Checkpoint: beacon-servicepoint CRUD + assignments API working
This commit is contained in:
commit
10200ad140
907 changed files with 63746 additions and 0 deletions
349
Application.cfm
Normal file
349
Application.cfm
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
<cfapplication name="payfrit_app_new"
|
||||
clientmanagement="Yes"
|
||||
sessionmanagement="Yes"
|
||||
setclientcookies="Yes"
|
||||
sessiontimeout="#CreateTimeSpan(0,0,30,0)#"
|
||||
clientstorage="cookie">
|
||||
|
||||
<CFSET application.datasource = "payfrit">
|
||||
<cfset application.businessMasterObj = new library.cfc.businessMaster(odbc = application.datasource) />
|
||||
<cfset application.twilioObj = new library.cfc.twilio() />
|
||||
|
||||
<cfset request.cgiPath = getPageContext().getRequest().getRequestURI() />
|
||||
|
||||
<!--- Lock persistent scopes to avoid conflicts --->
|
||||
<cflock scope="session" timeout="15" throwontimeout="yes" type="exclusive">
|
||||
<!--- Replacing cookie with session variable --->
|
||||
<cfparam name="session.UserID" default="0">
|
||||
<cfparam name="session.BusinessID" default="0">
|
||||
<!--- Duplicate the session variables in the request scope so you don't have to CFLOCK them every time you use them. --->
|
||||
<cfset request.UserID = Duplicate(session.UserID)>
|
||||
<cfset request.BusinessID = Duplicate(session.BusinessID)>
|
||||
</cflock>
|
||||
|
||||
<cfif request.UserID NEQ 0>
|
||||
|
||||
<cfquery name="check_user" datasource="#application.datasource#">
|
||||
SELECT UserFirstName, UserBalance, UserImageExtension
|
||||
FROM Users
|
||||
WHERE UserID = #request.UserID#
|
||||
</cfquery>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfif parameterexists(url.UUID)>
|
||||
<cfset form.UUID=url.UUID>
|
||||
</cfif>
|
||||
|
||||
<cfparam name="check_user.recordcount" default="0">
|
||||
<cfparam name="form.mode" default="start">
|
||||
<cfparam name="form.chip" default="0">
|
||||
<cfparam name="form.prevchip" default="0">
|
||||
<cfparam name="form.prevmode" default="0">
|
||||
<cfparam name="submitted" default="0">
|
||||
<cfparam name="form.UUID" default="">
|
||||
<!--- <cfset form.bizid = structKeyExists(url, "bizid") ? url.bizid : form.bizid>
|
||||
<cfset form.mode = structKeyExists(url, "mode") ? url.mode : form.mode> --->
|
||||
|
||||
<CFSET border_width = "0">
|
||||
|
||||
<cfif cgi.Server_Name EQ "127.0.0.1">
|
||||
<CFSET application.wwwrootprefix = "/biz.payfrit.com/">
|
||||
<CFSET application.rootprefix = "\">
|
||||
<CFSET application.httpprefix = "/">
|
||||
<CFSET application.httpsprefix = "/">
|
||||
<CFSET application.localprefix = "C:\Inetpub\wwwroot\biz.payfrit.com\">
|
||||
<CFSET application.archive_datasource = "payfrit_archive">
|
||||
<CFSET application.uploads_dir = "C:\lucee\tomcat\webapps\ROOT\biz.payfrit.com\uploads\">
|
||||
<CFSET application.captcha_public_key = "">
|
||||
<CFSET application.captcha_private_key = "">
|
||||
<CFSET application.image_display_prefix = "http://127.0.0.1:8888/biz.payfrit.com/uploads/">
|
||||
<cfsetting showDebugOutput="yes">
|
||||
<cfelse>
|
||||
<CFSET application.wwwrootprefix = "/">
|
||||
<CFSET application.rootprefix = "\">
|
||||
<CFSET application.httpprefix = "/">
|
||||
<CFSET application.httpsprefix = "https://">
|
||||
<CFSET application.localprefix = "C:\lucee\tomcat\webapps\ROOT\payfrit.com\user\">
|
||||
<CFSET application.archive_datasource = "payfrit_archive">
|
||||
<CFSET application.uploads_dir = "/var/www/biz.payfrit.com/uploads/">
|
||||
<CFSET application.captcha_public_key = "">
|
||||
<CFSET application.captcha_private_key = "">
|
||||
<CFSET application.image_display_prefix = "https://biz.payfrit.com/uploads/">
|
||||
<cfsetting showDebugOutput="no">
|
||||
</cfif>
|
||||
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
|
||||
<title>The Payfrit Admin App</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
|
||||
<script src= "https://code.jquery.com/jquery-1.12.4.min.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<!--- <script async src="https://www.googletagmanager.com/gtag/js?id=G-X33RKP7WNG"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-X33RKP7WNG');
|
||||
</script> --->
|
||||
|
||||
<cfinclude template="includes/track_visitors.cfm">
|
||||
|
||||
<body>
|
||||
|
||||
<cfoutput>
|
||||
|
||||
<div class="container">
|
||||
<!-- Fixed navbar -->
|
||||
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="#request.cgiPath#">The Payfrit Admin App</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="##navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-md-0">
|
||||
|
||||
<li class="nav-item">
|
||||
|
||||
<cfif request.BusinessID eq 0>
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformregister()
|
||||
{
|
||||
document.myformregister.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgiPath#" method="post" name="myformregister" id="myformregister" style="display:inline;">
|
||||
|
||||
<a class="nav-link" href="javascript: submitformregister()">Create Account</a>
|
||||
|
||||
<input type="hidden" name="mode" value="register">
|
||||
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformforgot()
|
||||
{
|
||||
document.myformforgot.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgiPath#" method="post" name="myformforgot" id="myformforgot" style="display:inline;">
|
||||
|
||||
<a class="nav-link" href="javascript: submitformforgot()">Reset Password</a>
|
||||
|
||||
<input type="hidden" name="mode" value="forgot">
|
||||
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
||||
<cfelseif request.BusinessID neq 0>
|
||||
|
||||
<li class="nav-item">
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformkitchen()
|
||||
{
|
||||
document.myformkitchen.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgiPath#" method="post" name="myformkitchen" id="myformkitchen" style="display:inline;">
|
||||
|
||||
<a class="nav-link" href="javascript: submitformkitchen()">Kitchen</a>
|
||||
|
||||
<input type="hidden" name="mode" value="kitchen">
|
||||
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformcat()
|
||||
{
|
||||
document.myformcat.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgiPath#" method="post" name="myformcat" id="myformcat" style="display:inline;">
|
||||
|
||||
<a class="nav-link" href="javascript: submitformcat()">Categories</a>
|
||||
|
||||
<input type="hidden" name="mode" value="categories">
|
||||
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformitems()
|
||||
{
|
||||
document.myformitems.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgiPath#" method="post" name="myformitems" id="myformitems" style="display:inline;">
|
||||
|
||||
<a class="nav-link" href="javascript: submitformitems()">Items</a>
|
||||
|
||||
<input type="hidden" name="mode" value="items">
|
||||
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformviewmenu()
|
||||
{
|
||||
document.myformviewmenu.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgiPath#" method="post" name="myformviewmenu" id="myformviewmenu" style="display:inline;">
|
||||
|
||||
<a class="nav-link" href="javascript: submitformviewmenu()">Edit Menu</a>
|
||||
|
||||
<input type="hidden" name="mode" value="viewmenu">
|
||||
<input type="hidden" name="submode" value="edit">
|
||||
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformreports()
|
||||
{
|
||||
document.myformreports.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgiPath#" method="post" name="myformreports" id="myformreports" style="display:inline;">
|
||||
|
||||
<a class="nav-link" href="javascript: submitformreports()">Reports</a>
|
||||
|
||||
<input type="hidden" name="mode" value="reports">
|
||||
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformaccount()
|
||||
{
|
||||
document.myformaccount.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgiPath#" method="post" name="myformaccount" id="myformaccount" style="display:inline;">
|
||||
|
||||
<a class="nav-link" href="javascript: submitformaccount()">Account</a>
|
||||
|
||||
<input type="hidden" name="mode" value="businesses">
|
||||
<input type="hidden" name="submode" value="edit">
|
||||
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformlogout()
|
||||
{
|
||||
document.myformlogout.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgiPath#" method="post" name="myformlogout" id="myformlogout" style="display:inline;">
|
||||
|
||||
<a class="nav-link" href="javascript: submitformlogout()">Logout</a>
|
||||
|
||||
<input type="hidden" name="mode" value="logout">
|
||||
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
||||
</cfif>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div><br><br><br></div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col sm-5 md-3">
|
||||
<<cfoutput>img src="#application.wwwrootprefix#images/payfrit-logo-light-100-100-max.jpg" width="100" height="100" border="0" alt=""></cfoutput>
|
||||
</div>
|
||||
<!--- <div class="col sm-2 md-6">
|
||||
|
||||
</div> --->
|
||||
<div class="col sm-5 md-3">
|
||||
|
||||
<cfif find("logout.cfm", request.cgiPath) EQ 0>
|
||||
|
||||
<cfif request.UserID NEQ 0>
|
||||
<cfif check_user.UserImageExtension gt ""><img src="#application.image_display_prefix#users/thumbs/#request.UserID#.#check_user.UserImageExtension#" border="0" alt=""><br></cfif>
|
||||
Hi, <cfif check_user.UserFirstName gt "">#check_user.UserFirstName#<br>#dollarformat(check_user.UserBalance)#<cfelse>Payfrit User</cfif><br>
|
||||
<cfelse>
|
||||
|
||||
<form action="#application.wwwrootprefix#index.cfm" method="post" name="login_form" id="login_form">
|
||||
|
||||
<label for="colFormLabelSm">username:</label><input class="form-control form-control-sm" type="Text" name="username" required="No" maxlength="100" placeholder="email or mobile number">
|
||||
<label for="colFormLabelSm">password:</label><input class="form-control form-control-sm" type="password" name="password" required="No" maxlength="20" placeholder="your password">
|
||||
<input type="submit" value="login" class="btn btn-success my-2">
|
||||
<input type="hidden" name="mode" value="login">
|
||||
<input type="hidden" name="submitted" value="1">
|
||||
|
||||
</form>
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</cfoutput>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
1
NoBark.apf
Normal file
1
NoBark.apf
Normal file
File diff suppressed because one or more lines are too long
1
Untitled1.cfm
Normal file
1
Untitled1.cfm
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
455
_process.cfm
Normal file
455
_process.cfm
Normal file
|
|
@ -0,0 +1,455 @@
|
|||
|
||||
<cftry>
|
||||
<!--- create a config that is not in svn --->
|
||||
<cfscript>
|
||||
cfg = { path = "cfpayment.api.gateway.stripe.stripe", TestSecretKey = "sk_test_LfbmDduJxTwbVZmvcByYmirw" };
|
||||
svc = createObject("component", "cfpayment.api.core").init(cfg);
|
||||
</cfscript>
|
||||
<cfcatch>
|
||||
<!--- if gwParams doesn't exist (or otherwise bombs), create a generic structure with blank values --->
|
||||
<cfset gwParams = StructNew() />
|
||||
<cfset gwParams.Path = "bogus.gateway" />
|
||||
<!--- these following params aren't needed for the bogus gateway, but should normally be filled in --->
|
||||
<cfset gwParams.MerchantAccount = "" />
|
||||
<cfset gwParams.userName = "" />
|
||||
<cfset gwParams.password = "" />
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<!--- create gw and get reference --->
|
||||
<cfset gw = svc.getGateway() />
|
||||
<cfset creditcard = svc.createCreditCard()>
|
||||
<cfset money = svc.createMoney()>
|
||||
<cfset errors=ArrayNew(1)>
|
||||
<!--- Initialize Form Variables --->
|
||||
<cfparam name="form.BillingFirstName" default="">
|
||||
<cfparam name="form.BillingLastName" default="">
|
||||
<cfparam name="form.BillingAddressOne" default="">
|
||||
<cfparam name="form.BillingCity" default="">
|
||||
<cfparam name="form.BillingState" default="">
|
||||
<cfparam name="form.BillingZip" default="">
|
||||
<cfparam name="form.BillingCountry" default="">
|
||||
<cfparam name="form.BillingPhoneNumber" default="">
|
||||
<cfparam name="form.BillingEmailAddress" default="">
|
||||
<cfparam name="form.orderID" default="1">
|
||||
|
||||
|
||||
<cfparam name="form.Amount" default="1">
|
||||
<cfparam name="form.CardNumber" default="">
|
||||
<cfparam name="form.CardType" default="">
|
||||
<cfparam name="form.ExpirationMonth" default="">
|
||||
<cfparam name="form.ExpirationYear" default="">
|
||||
<cfparam name="form.TransactionType" default="SALE">
|
||||
<cfparam name="form.cvv2" default="">
|
||||
<cftry>
|
||||
|
||||
|
||||
<cfif structKeyExists(form, "submitBtn")>
|
||||
<!--- PROCESS --->
|
||||
<cftry>
|
||||
<!--- populate credit card object with passed data --->
|
||||
<cfset ccObjList="Account,Month,Year,VerificationValue,FirstName,LastName,Address,PostalCode">
|
||||
<cfset formFieldList="CardNumber,ExpirationMonth,ExpirationYear,cvv2,BillingFirstName,BillingLastName,BillingAddressOne,BillingZip">
|
||||
<cfset numFields=ListLen(ccObjList)>
|
||||
<cfloop from="1" to="#numFields#" index="idx">
|
||||
<cfset currCCField=ListGetAt(ccObjList, idx)>
|
||||
<cfset currFormField=ListGetAt(formFieldList, idx)>
|
||||
<cfinvoke component="#creditcard#" method="set#currCCField#">
|
||||
<cfinvokeargument name="#currCCField#" value="#form[currFormField]#" />
|
||||
</cfinvoke>
|
||||
</cfloop>
|
||||
<!--- validate credit card --->
|
||||
<cfset errors=creditCard.validate()>
|
||||
<cfif not ArrayLen(errors)>
|
||||
<!--- gateway specific parameters --->
|
||||
<!--- for example, the skipjack gateway requires email, phonenumber and ordernumber; these are passed in the options struct --->
|
||||
<cfset options=StructNew()>
|
||||
<cfset options.address=StructNew()>
|
||||
<cfset options.email=form.BillingEmailAddress>
|
||||
<!--- send through generic address structure --->
|
||||
<cfset options.address.phone=form.BillingPhoneNumber>
|
||||
<cfset options.address.Address1=form.BillingAddressOne>
|
||||
<cfset options.address.City=form.BillingCity>
|
||||
<cfset options.address.State=form.BillingState>
|
||||
<cfset options.address.PostalCode=form.BillingZip>
|
||||
<cfset options.address.Country=form.BillingCountry>
|
||||
<cfset options.order_id=form.orderID>
|
||||
|
||||
<!--- setup the money object with the amount --->
|
||||
<cfset money.init( 100)><!--- in cents --->
|
||||
|
||||
<!--- send authorize command --->
|
||||
<!--- pass in the money object, the creditcard object, extra parameters required by the specific gateway --->
|
||||
<cfset authResponse=gw.purchase(money, creditCard)>
|
||||
|
||||
<!--- process response --->
|
||||
|
||||
<cfif authResponse.getSuccess()>
|
||||
<!---- TODO use stcResult to get the data post payment. ---->
|
||||
<cfset stcResult = {
|
||||
id = authResponse.getParsedResult().id,
|
||||
amount = round(authResponse.getParsedResult().amount)/100,
|
||||
message = authResponse.getParsedResult().outcome.seller_message,
|
||||
receipt_url = authResponse.getParsedResult().receipt_url,
|
||||
status = authResponse.getParsedResult().status
|
||||
}>
|
||||
|
||||
<cfoutput>The credit card payment was successfully processed. <br><br>
|
||||
Your receipt can be found <a href="#stcResult.receipt_url#" target="new">here.</a><br><br></cfoutput>
|
||||
|
||||
<!--- <cfdump var=#stcResult#>
|
||||
|
||||
TODO: you should now do something (record, redirect, etc.) --->
|
||||
|
||||
<!--- <cfdump var="#deserializeJSON(authResponse.getResult())#" label="getResult">
|
||||
<cfdump var="#authResponse.getParsedResult()#" label="getParsedResult">
|
||||
<cfif isdefined("arguments")><cfdump var="#arguments#" label="Arguments Scope"></cfif>
|
||||
<cfif isdefined("attributes")><cfdump var="#attributes#" label="Attributes Scope"></cfif>
|
||||
<cfif isdefined("CGI")><cfdump var="#CGI#" label="CGI Scope"></cfif>
|
||||
<cfif isdefined("Request")><cfdump var="#Request#" label="Request Scope"></cfif>
|
||||
<cfif isdefined("URL")><cfdump var="#URL#" label="URL Scope"></cfif>
|
||||
<cfif isdefined("Form")><cfdump var="#Form#" label="Form Scope"></cfif>
|
||||
<cfif isdefined("session")><cfdump var="#Session#" label="Session Scope"></cfif> --->
|
||||
|
||||
<!--- do the rest of the stuff --->
|
||||
|
||||
<cfset cart_total = 0>
|
||||
|
||||
<CFQUERY name="get_queued_food" datasource="#application.datasource#" dbtype="ODBC">
|
||||
SELECT A.CartID, A.AddedOn, A.Quantity, A.SpecialRemark, B.BusinessName, B.UserID, C.ItemName, A.Price, D.UserFirstName, D.LaerFirstName, D.Balance
|
||||
FROM dbo.Business_CartMaster A, dbo.BusinessMaster B, dbo.Business_ItemMaster C, Users D
|
||||
WHERE A.UserID = D.UserID
|
||||
AND
|
||||
A.ItemID = C.ItemID
|
||||
AND
|
||||
B.BusinessID = C.BusinessID
|
||||
AND
|
||||
C.BusinessID = #form.bizid#
|
||||
AND
|
||||
A.CartStatusID = 1
|
||||
AND
|
||||
A.UserID = #session.UserID#
|
||||
ORDER BY A.AddedOn DESC
|
||||
</CFQUERY>
|
||||
|
||||
<cfoutput query="get_queued_food">
|
||||
|
||||
<cfif len(get_queued_food.Price) EQ 0><cfset get_queued_food.Price=0></cfif>
|
||||
|
||||
<cfset cart_total = (cart_total + (get_queued_food.price*get_queued_food.quantity))>
|
||||
|
||||
<CFQUERY name="update_cart_items" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE dbo.Business_CartMaster
|
||||
SET CartStatusID=2
|
||||
WHERE CartID=#get_queued_food.CartID#
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="Insert_order" datasource="#application.datasource#" dbtype="ODBC">
|
||||
INSERT Into dbo.Business_OrderMaster (
|
||||
UserID,
|
||||
BusinessID,
|
||||
IsDelivery,
|
||||
TotalAmount,
|
||||
Remark,
|
||||
Address,
|
||||
DeliveryCharge,
|
||||
TaxChargeAmount,
|
||||
AddedOn
|
||||
)
|
||||
values (
|
||||
#session.UserID#,
|
||||
#form.bizid#,
|
||||
0,
|
||||
#cart_total#,
|
||||
'#form.SpecialRemark#',
|
||||
'',
|
||||
0,
|
||||
0,
|
||||
#CreateODBCDateTime(now())#
|
||||
);
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="get_last_inserted" datasource="#application.datasource#" dbtype="ODBC">
|
||||
SELECT TOP 1 O.OrderID, M.UserID as person_to_pay_for_orderID, U.Balance
|
||||
FROM dbo.Business_OrderMaster O, dbo.BusinessMaster M, Users U
|
||||
WHERE O.BusinessID = M.BusinessID
|
||||
AND
|
||||
M.UserID = U.UserID
|
||||
ORDER BY O.AddedOn DESC
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="link_order" datasource="#application.datasource#" dbtype="ODBC">
|
||||
INSERT INTO dbo.Business_OrderCartTransaction (
|
||||
OrderID,
|
||||
CartID
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#get_last_inserted.OrderID#,
|
||||
#get_queued_food.CartID#
|
||||
)
|
||||
</CFQUERY>
|
||||
|
||||
</cfoutput>
|
||||
|
||||
<cfif payment_mode eq "account">
|
||||
|
||||
<cfif cart_total < 10>
|
||||
<cfset admin_fees_calculated = cart_total * .022>
|
||||
<cfelse>
|
||||
<cfset admin_fees_calculated = cart_total * .005 +.215>
|
||||
</cfif>
|
||||
|
||||
<cfelseif payment_mode eq "mixed">
|
||||
|
||||
<cfif cart_total-get_queued_food.balance < 10>
|
||||
<cfset admin_fees_calculated = (cart_total-get_queued_food.balance) * .022>
|
||||
<cfelse>
|
||||
<cfset admin_fees_calculated = (cart_total-get_queued_food.balance) * .005 +.215>
|
||||
</cfif>
|
||||
|
||||
<cfelseif payment_mode eq "creditcard">
|
||||
|
||||
<cfset admin_fees_calculated = 0>
|
||||
|
||||
<cfelse>
|
||||
|
||||
problem! what is the payment_mode?<br><br>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfif payment_mode eq "account">
|
||||
|
||||
<CFQUERY name="insert_payment" datasource="#application.datasource#" dbtype="ODBC">
|
||||
INSERT INTO dbo.PaymentMaster (
|
||||
ReceiverID,
|
||||
PayUserID,
|
||||
BusinessID,
|
||||
Amount,
|
||||
AdminFees,
|
||||
PayUserRemark,
|
||||
SystemRemark,
|
||||
AddedOn,
|
||||
CartID,
|
||||
PaymentReceiptURL
|
||||
)
|
||||
VALUES (
|
||||
#get_last_inserted.person_to_pay_for_orderID#,
|
||||
#session.UserID#,
|
||||
#form.bizid#,
|
||||
#cart_total-admin_fees_calculated#,
|
||||
#admin_fees_calculated#,
|
||||
'',
|
||||
'from account balance',
|
||||
#createODBCDateTime(now())#,
|
||||
#get_queued_food.CartID#,
|
||||
'#stcResult.receipt_url#'
|
||||
)
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="delete_item_cost" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE Users
|
||||
SET balance = #check_user.balance-cart_total#
|
||||
WHERE UserID = #session.UserID#
|
||||
</CFQUERY>
|
||||
|
||||
<cfif cart_total < 10>
|
||||
<cfset admin_fees_calculated = cart_total * .022>
|
||||
<cfelse>
|
||||
<cfset admin_fees_calculated = cart_total * .005 +.215>
|
||||
</cfif>
|
||||
|
||||
<CFQUERY name="transfer_money_to_business_creators_UserID" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE Users
|
||||
SET balance = #get_last_inserted.balance+(cart_total-admin_fees_calculated)#
|
||||
WHERE UserID = #get_last_inserted.person_to_pay_for_orderID#
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="get_user_104_balance" datasource="#application.datasource#" dbtype="ODBC">
|
||||
SELECT balance
|
||||
FROM Users
|
||||
WHERE UserID = 104
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="transfer_fees_to_UserID_104" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE Users
|
||||
SET balance = #get_user_104_balance.balance+admin_fees_calculated#
|
||||
WHERE UserID = 104
|
||||
</CFQUERY>
|
||||
|
||||
<cfelseif payment_mode eq "mixed">
|
||||
|
||||
<cfset card_fee = (cart_total-get_queued_food.balance/.9725)*.0275+.30>
|
||||
|
||||
<CFQUERY name="insert_account_payment" datasource="#application.datasource#" dbtype="ODBC">
|
||||
INSERT INTO dbo.PaymentMaster (
|
||||
ReceiverID,
|
||||
PayUserID,
|
||||
BusinessID,
|
||||
Amount,
|
||||
AdminFees,
|
||||
PayUserRemark,
|
||||
SystemRemark,
|
||||
AddedOn,
|
||||
CartID
|
||||
)
|
||||
VALUES (
|
||||
#get_last_inserted.person_to_pay_for_orderID#,
|
||||
#session.UserID#,
|
||||
#form.bizid#,
|
||||
#get_queued_food.balance#,
|
||||
#admin_fees_calculated#,
|
||||
'',
|
||||
'mixed - from account balance #dollarformat(get_queued_food.balance)#',
|
||||
#createODBCDateTime(now())#,
|
||||
#get_queued_food.CartID#
|
||||
)
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="insert_cc_payment" datasource="#application.datasource#" dbtype="ODBC">
|
||||
INSERT INTO dbo.PaymentMaster (
|
||||
ReceiverID,
|
||||
PayUserID,
|
||||
BusinessID,
|
||||
Amount,
|
||||
AdminFees,
|
||||
PayUserRemark,
|
||||
SystemRemark,
|
||||
AddedOn,
|
||||
CartID
|
||||
)
|
||||
VALUES (
|
||||
#get_last_inserted.person_to_pay_for_orderID#,
|
||||
#session.UserID#,
|
||||
#form.bizid#,
|
||||
#cart_total-get_queued_food.balance#,
|
||||
0,
|
||||
'',
|
||||
'mixed - from credit card #dollarformat(amount)#',
|
||||
#createODBCDateTime(now())#,
|
||||
#get_queued_food.CartID#
|
||||
)
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="delete_item_cost" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE Users
|
||||
SET balance = 0
|
||||
WHERE UserID = #session.UserID#
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="transfer_money_to_business_creators_UserID" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE Users
|
||||
SET balance = #get_last_inserted.balance+(cart_total-admin_fees_calculated)#
|
||||
WHERE UserID = #get_last_inserted.person_to_pay_for_orderID#
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="get_user_104_balance" datasource="#application.datasource#" dbtype="ODBC">
|
||||
SELECT balance
|
||||
FROM Users
|
||||
WHERE UserID = 104
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="transfer_fees_to_UserID_104" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE Users
|
||||
SET balance = #get_user_104_balance.balance+admin_fees_calculated#
|
||||
WHERE UserID = 104
|
||||
</CFQUERY>
|
||||
|
||||
<cfelseif payment_mode eq "creditcard"> <!--- credit card --->
|
||||
|
||||
<CFQUERY name="insert_payment" datasource="#application.datasource#" dbtype="ODBC">
|
||||
INSERT INTO dbo.PaymentMaster (
|
||||
ReceiverID,
|
||||
PayUserID,
|
||||
BusinessID,
|
||||
Amount,
|
||||
AdminFees,
|
||||
PayUserRemark,
|
||||
SystemRemark,
|
||||
AddedOn,
|
||||
CartID
|
||||
)
|
||||
VALUES (
|
||||
#get_last_inserted.person_to_pay_for_orderID#,
|
||||
#session.UserID#,
|
||||
#form.bizid#,
|
||||
#cart_total-admin_fees_calculated#,
|
||||
#admin_fees_calculated#,
|
||||
'',
|
||||
'from credit card',
|
||||
#createODBCDateTime(now())#,
|
||||
#get_queued_food.CartID#
|
||||
)
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="transfer_money_to_business_creators_UserID" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE Users
|
||||
SET balance = #get_last_inserted.balance+(cart_total-admin_fees_calculated)#
|
||||
WHERE UserID = #get_last_inserted.person_to_pay_for_orderID#
|
||||
</CFQUERY>
|
||||
|
||||
<cfelse>
|
||||
|
||||
problem! what is the payment_mode?<br><br><cfabort>
|
||||
|
||||
</cfif>
|
||||
|
||||
<div align="center">Order Complete!<br><br><a href="index.cfm">Reload</a> for new balance<br><br>
|
||||
|
||||
<!--- end additional stuff --->
|
||||
|
||||
<cfoutput>
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformfunctionaddstuff()
|
||||
{
|
||||
document.myformcartadd.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgiPath#" method="post" name="myformcartadd" id="myformcartadd" style="display:inline;">
|
||||
|
||||
<a href="javascript: submitformfunctionaddstuff()">Add Stuff</a>
|
||||
|
||||
<input type="hidden" name="mode" value="start">
|
||||
|
||||
</form><br><br>
|
||||
|
||||
</cfoutput>
|
||||
|
||||
<!--- end do the rest of the stuff --->
|
||||
|
||||
<cfelse>
|
||||
<!--- add the gateway errors to any existing errors we are tracking (eg. creditcard object errors) --->
|
||||
<cfset ArrayAppend(errors, authResponse.getMessage())>
|
||||
</cfif>
|
||||
</cfif>
|
||||
<!--- if we get here, there were errors --->
|
||||
<!--- <cfdump var="#errors.getErrors()#"> --->
|
||||
<cfcatch type="cfpayment">
|
||||
|
||||
<!--- <cfdump var="#cfcatch#"><cfabort> --->
|
||||
<cfset ArrayAppend(errors, cfcatch.message)>
|
||||
</cfcatch>
|
||||
<cfcatch>
|
||||
|
||||
<!--- <cfdump var="#cfcatch#"><cfabort> --->
|
||||
<cfset ArrayAppend(errors, cfcatch.message)>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
</cfif>
|
||||
|
||||
<cfcatch>
|
||||
<cfoutput>Initialization Error - Credit Card Payment Form</cfoutput>
|
||||
<!--- TODO: this should be e-mailed or logged somewhere --->
|
||||
<cfdump var="#CFCatch#" label="CFCatch Scope">
|
||||
<cfif isdefined("arguments")><cfdump var="#arguments#" label="Arguments Scope"></cfif>
|
||||
<cfif isdefined("attributes")><cfdump var="#attributes#" label="Attributes Scope"></cfif>
|
||||
<cfif isdefined("CGI")><cfdump var="#CGI#" label="CGI Scope"></cfif>
|
||||
<cfif isdefined("Request")><cfdump var="#Request#" label="Request Scope"></cfif>
|
||||
<cfif isdefined("URL")><cfdump var="#URL#" label="URL Scope"></cfif>
|
||||
<cfif isdefined("Form")><cfdump var="#Form#" label="Form Scope"></cfif>
|
||||
<cfif isdefined("session")><cfdump var="#Session#" label="Session Scope"></cfif>
|
||||
<cfabort>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
1
aaa Payfrit app new.apf
Normal file
1
aaa Payfrit app new.apf
Normal file
File diff suppressed because one or more lines are too long
302
admin/beacon_servicepoint.cfm
Normal file
302
admin/beacon_servicepoint.cfm
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Payfrit Admin - Beacon ↔ ServicePoint</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
select, input, button { padding: 8px; margin: 6px 0; width: 520px; max-width: 100%; }
|
||||
button { width: auto; cursor: pointer; }
|
||||
.row { display: flex; gap: 24px; flex-wrap: wrap; }
|
||||
.card { border: 1px solid #ddd; padding: 14px; border-radius: 10px; flex: 1; min-width: 320px; }
|
||||
pre { background: #111; color: #0f0; padding: 10px; overflow: auto; border-radius: 8px; min-height: 160px; }
|
||||
table { border-collapse: collapse; width: 100%; margin-top: 12px; }
|
||||
th, td { border: 1px solid #ddd; padding: 8px; }
|
||||
th { background: #f5f5f5; text-align: left; }
|
||||
.ok { color: #060; font-weight: bold; }
|
||||
.warn { color: #b00; font-weight: bold; }
|
||||
.mini { font-size: 12px; color: #555; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Beacon ↔ ServicePoint Relationships</h2>
|
||||
<div class="ok" id="jsStatus">(JS not loaded yet)</div>
|
||||
<div class="warn" id="counts"></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="card">
|
||||
<h3>Create / Update Relationship</h3>
|
||||
<div>
|
||||
<label>Beacon</label><br>
|
||||
<select id="BeaconSelect"></select>
|
||||
</div>
|
||||
<div>
|
||||
<label>ServicePoint</label><br>
|
||||
<select id="ServicePointSelect"></select>
|
||||
</div>
|
||||
<div>
|
||||
<label>Notes</label><br>
|
||||
<input id="Notes" placeholder="Optional">
|
||||
</div>
|
||||
<button type="button" onclick="saveRel()">Link</button>
|
||||
<button type="button" onclick="refreshAll()">Refresh</button>
|
||||
|
||||
<h3>Last Action Response</h3>
|
||||
<div class="mini">This shows the raw response from save/delete so it can’t be overwritten by refreshAll.</div>
|
||||
<pre id="respAction"></pre>
|
||||
|
||||
<h3>Current Data Snapshot</h3>
|
||||
<div class="mini">This shows the latest Beacons/ServicePoints/Assignments bundle.</div>
|
||||
<pre id="respSnapshot"></pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Delete Relationship</h3>
|
||||
<div>
|
||||
<label>Relationship ID (lt_Beacon_Businesses_ServicePointID)</label><br>
|
||||
<input id="RelID" placeholder="Click a row below to fill this">
|
||||
</div>
|
||||
<button type="button" onclick="deleteRel()">Delete</button>
|
||||
<div style="margin-top:8px;" class="mini">
|
||||
Tip: Delete first to re-assign a Beacon (since assigned beacons are hidden from the dropdown).
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Existing Relationships (click row to copy ID)</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Beacon</th>
|
||||
<th>ServicePoint</th>
|
||||
<th>Notes</th>
|
||||
<th>CreatedAt</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="rows"></tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
(function boot(){
|
||||
document.getElementById("jsStatus").textContent = "JS loaded OK";
|
||||
})();
|
||||
|
||||
function showAction(o){ document.getElementById("respAction").textContent = JSON.stringify(o, null, 2); }
|
||||
function showSnapshot(o){ document.getElementById("respSnapshot").textContent = JSON.stringify(o, null, 2); }
|
||||
|
||||
const API_BASE = "/biz.payfrit.com/api";
|
||||
|
||||
// 1:1 MODE (for now)
|
||||
const HIDE_ASSIGNED_BEACONS = true;
|
||||
const HIDE_ASSIGNED_SERVICEPOINTS = true;
|
||||
|
||||
async function api(path, bodyObj) {
|
||||
const fullPath = API_BASE + path;
|
||||
try {
|
||||
const res = await fetch(fullPath, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(bodyObj || {})
|
||||
});
|
||||
const txt = await res.text();
|
||||
try {
|
||||
const parsed = JSON.parse(txt);
|
||||
parsed._httpStatus = res.status;
|
||||
parsed._path = fullPath;
|
||||
return parsed;
|
||||
} catch {
|
||||
return { OK:false, ERROR:"non_json", RAW:txt, _httpStatus: res.status, _path: fullPath };
|
||||
}
|
||||
} catch (e) {
|
||||
return { OK:false, ERROR:"network_error", MESSAGE:String(e), _path: fullPath };
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml(s){
|
||||
return (""+s)
|
||||
.replaceAll("&","&")
|
||||
.replaceAll("<","<")
|
||||
.replaceAll(">",">")
|
||||
.replaceAll('"',""")
|
||||
.replaceAll("'","'");
|
||||
}
|
||||
|
||||
function setSelectPlaceholder(sel, label){
|
||||
sel.innerHTML = "";
|
||||
const opt = document.createElement("option");
|
||||
opt.value = "";
|
||||
opt.textContent = label;
|
||||
sel.appendChild(opt);
|
||||
}
|
||||
|
||||
function buildAssignedSets(assignOut){
|
||||
const assignedBeaconIDs = new Set();
|
||||
const assignedServicePointIDs = new Set();
|
||||
|
||||
(assignOut.ASSIGNMENTS || []).forEach(a => {
|
||||
if (a && a.BeaconID != null) assignedBeaconIDs.add(String(a.BeaconID));
|
||||
if (a && a.ServicePointID != null) assignedServicePointIDs.add(String(a.ServicePointID));
|
||||
});
|
||||
|
||||
return { assignedBeaconIDs, assignedServicePointIDs };
|
||||
}
|
||||
|
||||
function getSelVal(id){
|
||||
const el = document.getElementById(id);
|
||||
return el ? String(el.value || "") : "";
|
||||
}
|
||||
|
||||
function setSelValIfExists(id, value){
|
||||
const el = document.getElementById(id);
|
||||
if (!el) return;
|
||||
|
||||
const opt = Array.from(el.options).find(o => String(o.value) === String(value));
|
||||
if (opt) el.value = String(value);
|
||||
}
|
||||
|
||||
async function refreshAssignments(){
|
||||
const out = await api("/assignments/list.cfm", {});
|
||||
const tbody = document.getElementById("rows");
|
||||
tbody.innerHTML = "";
|
||||
|
||||
(out.ASSIGNMENTS || []).forEach(a => {
|
||||
const tr = document.createElement("tr");
|
||||
tr.innerHTML = `
|
||||
<td>${a.lt_Beacon_Businesses_ServicePointID}</td>
|
||||
<td>${escapeHtml((a.BeaconName || "") + " (ID " + a.BeaconID + ")")}</td>
|
||||
<td>${escapeHtml((a.ServicePointName || "") + " (ID " + a.ServicePointID + ")")}</td>
|
||||
<td>${escapeHtml(a.lt_Beacon_Businesses_ServicePointNotes || "")}</td>
|
||||
<td>${escapeHtml(a.CreatedAt || "")}</td>
|
||||
`;
|
||||
tr.style.cursor = "pointer";
|
||||
tr.onclick = () => document.getElementById("RelID").value = a.lt_Beacon_Businesses_ServicePointID;
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
async function refreshBeacons(assignedBeaconIDs, keepSelectedBeaconID){
|
||||
const out = await api("/beacons/list.cfm", {});
|
||||
const sel = document.getElementById("BeaconSelect");
|
||||
setSelectPlaceholder(sel, "-- Select Beacon --");
|
||||
|
||||
(out.BEACONS || []).forEach(b => {
|
||||
const isAssigned = assignedBeaconIDs.has(String(b.BeaconID));
|
||||
if (HIDE_ASSIGNED_BEACONS && isAssigned) return;
|
||||
|
||||
const opt = document.createElement("option");
|
||||
opt.value = b.BeaconID;
|
||||
opt.textContent = String(b.BeaconID) + " - " + (b.BeaconName || "");
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
|
||||
if (keepSelectedBeaconID) setSelValIfExists("BeaconSelect", keepSelectedBeaconID);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
async function refreshServicePoints(assignedServicePointIDs, keepSelectedServicePointID){
|
||||
const out = await api("/servicepoints/list.cfm", {});
|
||||
const sel = document.getElementById("ServicePointSelect");
|
||||
setSelectPlaceholder(sel, "-- Select ServicePoint --");
|
||||
|
||||
(out.SERVICEPOINTS || []).forEach(sp => {
|
||||
const isAssigned = assignedServicePointIDs.has(String(sp.ServicePointID));
|
||||
if (HIDE_ASSIGNED_SERVICEPOINTS && isAssigned) return;
|
||||
|
||||
const opt = document.createElement("option");
|
||||
opt.value = sp.ServicePointID;
|
||||
opt.textContent = String(sp.ServicePointID) + " - " + (sp.ServicePointName || "");
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
|
||||
if (keepSelectedServicePointID) setSelValIfExists("ServicePointSelect", keepSelectedServicePointID);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
async function refreshAll(){
|
||||
// preserve selection during refresh
|
||||
const keepBeacon = getSelVal("BeaconSelect");
|
||||
const keepSP = getSelVal("ServicePointSelect");
|
||||
|
||||
// assignments first (for filtering)
|
||||
const assignOut = await refreshAssignments();
|
||||
const sets = buildAssignedSets(assignOut);
|
||||
|
||||
const beaconOut = await refreshBeacons(sets.assignedBeaconIDs, keepBeacon);
|
||||
const spOut = await refreshServicePoints(sets.assignedServicePointIDs, keepSP);
|
||||
|
||||
const beaconCount = (beaconOut.BEACONS || []).length;
|
||||
const spCount = (spOut.SERVICEPOINTS || []).length;
|
||||
const assignCount = (assignOut.ASSIGNMENTS || []).length;
|
||||
|
||||
document.getElementById("counts").textContent =
|
||||
"Beacons: " + beaconCount + " | ServicePoints: " + spCount + " | Assignments: " + assignCount;
|
||||
|
||||
showSnapshot({
|
||||
AssignedBeaconIDs: Array.from(sets.assignedBeaconIDs),
|
||||
AssignedServicePointIDs: Array.from(sets.assignedServicePointIDs),
|
||||
BeaconsResponse: beaconOut,
|
||||
ServicePointsResponse: spOut,
|
||||
AssignmentsResponse: assignOut
|
||||
});
|
||||
}
|
||||
|
||||
async function saveRel(){
|
||||
const rawBeacon = getSelVal("BeaconSelect");
|
||||
const rawSP = getSelVal("ServicePointSelect");
|
||||
|
||||
if (!rawBeacon || !rawSP){
|
||||
showAction({
|
||||
OK:false,
|
||||
ERROR: (!rawBeacon ? "missing_BeaconID" : "missing_ServicePointID"),
|
||||
BeaconSelectValue: rawBeacon,
|
||||
ServicePointSelectValue: rawSP
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const BeaconID = parseInt(rawBeacon, 10);
|
||||
const ServicePointID = parseInt(rawSP, 10);
|
||||
const Notes = (document.getElementById("Notes").value || "").trim();
|
||||
|
||||
if (!BeaconID){
|
||||
showAction({ OK:false, ERROR:"missing_BeaconID", BeaconSelectValue: rawBeacon });
|
||||
return;
|
||||
}
|
||||
if (!ServicePointID){
|
||||
showAction({ OK:false, ERROR:"missing_ServicePointID", ServicePointSelectValue: rawSP });
|
||||
return;
|
||||
}
|
||||
|
||||
// IMPORTANT: show the save response and DO NOT overwrite it with refresh output
|
||||
const out = await api("/assignments/save.cfm", { BeaconID, ServicePointID, Notes });
|
||||
showAction(out);
|
||||
|
||||
// refresh snapshot + table silently (snapshot still updates, but action box stays)
|
||||
await refreshAll();
|
||||
}
|
||||
|
||||
async function deleteRel(){
|
||||
const idStr = (document.getElementById("RelID").value || "").trim();
|
||||
const id = parseInt(idStr, 10);
|
||||
if (!id){
|
||||
showAction({OK:false,ERROR:"missing_lt_Beacon_Businesses_ServicePointID"});
|
||||
return;
|
||||
}
|
||||
|
||||
const out = await api("/assignments/delete.cfm", { lt_Beacon_Businesses_ServicePointID: id });
|
||||
showAction(out);
|
||||
await refreshAll();
|
||||
}
|
||||
|
||||
// initial load
|
||||
showAction({ OK:true, MESSAGE:"Ready. Select Beacon + ServicePoint then click Link." });
|
||||
refreshAll();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<a href="/pads.payfrit.com" target="_blank">pads.payfrit.com</a> | <a href="/payfr.it" target="_blank">payfr.it</a> | <a href="/work.payfrit.com" target="_blank">work.payfr.it</a> | <a href="https://help.payfrit.com" target="_blank">support ticket</a><br>Copyright 2025 <a href="mailto:admin@payfrit.com">Payfrit</a>
|
||||
233
admin/beacons.cfm
Normal file
233
admin/beacons.cfm
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="text/html; charset=utf-8" reset="true">
|
||||
|
||||
<cfoutput>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Payfrit Admin - Beacons</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
input, button, select { padding: 8px; margin: 6px 0; width: 420px; max-width: 100%; }
|
||||
button { width: auto; cursor: pointer; }
|
||||
table { border-collapse: collapse; width: 100%; margin-top: 12px; }
|
||||
th, td { border: 1px solid ##ddd; padding: 8px; }
|
||||
th { background: ##f5f5f5; text-align: left; }
|
||||
.row { display: flex; gap: 24px; flex-wrap: wrap; }
|
||||
.card { border: 1px solid ##ddd; padding: 14px; border-radius: 10px; flex: 1; min-width: 320px; }
|
||||
pre { background: ##111; color: ##0f0; padding: 10px; overflow: auto; border-radius: 8px; min-height: 140px; }
|
||||
.warn { color: ##b00; font-weight: bold; }
|
||||
.ok { color: ##060; font-weight: bold; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Beacons</h2>
|
||||
<div class="warn">Required: BeaconName</div>
|
||||
<div class="ok" id="jsStatus">(JS not loaded yet)</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="card">
|
||||
<h3>Create / Update</h3>
|
||||
|
||||
<div>
|
||||
<label>BeaconID (blank = create)</label><br>
|
||||
<input id="BeaconID" placeholder="e.g. 123">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>BeaconName (required)</label><br>
|
||||
<input id="BeaconName" placeholder="Front Door" required>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>UUID (iBeacon-style)</label><br>
|
||||
<input id="UUID" placeholder="E2C56DB5-DFFB-48D2-B060-D0F5A71096E0">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>NamespaceId (Eddystone-UID first 20 hex chars)</label><br>
|
||||
<input id="NamespaceId" placeholder="0A1B2C3D4E5F60718293">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>InstanceId (Eddystone-UID last 12 hex chars)</label><br>
|
||||
<input id="InstanceId" placeholder="A1B2C3D4E5F6">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>IsActive</label><br>
|
||||
<select id="IsActive">
|
||||
<option value="1" selected>1 (Active)</option>
|
||||
<option value="0">0 (Inactive)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="button" onclick="saveBeacon()">Save</button>
|
||||
<button type="button" onclick="refresh()">Refresh List</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Delete (soft)</h3>
|
||||
<div>
|
||||
<label>BeaconID</label><br>
|
||||
<input id="DelBeaconID" placeholder="e.g. 123">
|
||||
</div>
|
||||
<button type="button" onclick="deleteBeacon()">Delete</button>
|
||||
|
||||
<h3>Response</h3>
|
||||
<pre id="resp"></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Beacon List (click row to load)</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>BeaconID</th>
|
||||
<th>Name</th>
|
||||
<th>UUID</th>
|
||||
<th>NamespaceId</th>
|
||||
<th>InstanceId</th>
|
||||
<th>IsActive</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="rows"></tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
(function boot(){
|
||||
document.getElementById("jsStatus").textContent = "JS loaded OK";
|
||||
})();
|
||||
|
||||
function show(o){
|
||||
document.getElementById("resp").textContent = JSON.stringify(o, null, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
IMPORTANT:
|
||||
Your Lucee error shows /api/... is resolving to C:\lucee\tomcat\webapps\ROOT\api\...
|
||||
So we must call the API under the biz.payfrit.com context explicitly.
|
||||
*/
|
||||
const API_BASE = "/biz.payfrit.com/api";
|
||||
|
||||
async function api(path, bodyObj) {
|
||||
const fullPath = API_BASE + path;
|
||||
show({ INFO:"API CALL", PATH: fullPath, BODY: bodyObj || {} });
|
||||
|
||||
try {
|
||||
const res = await fetch(fullPath, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(bodyObj || {})
|
||||
});
|
||||
|
||||
const txt = await res.text();
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(txt);
|
||||
parsed._httpStatus = res.status;
|
||||
parsed._path = fullPath;
|
||||
return parsed;
|
||||
} catch (e) {
|
||||
return {
|
||||
OK:false,
|
||||
ERROR:"non_json",
|
||||
_httpStatus: res.status,
|
||||
_path: fullPath,
|
||||
RAW: txt
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
return { OK:false, ERROR:"network_error", MESSAGE:String(e), _path: fullPath };
|
||||
}
|
||||
}
|
||||
|
||||
function valIntOrNull(id){
|
||||
const v = (document.getElementById(id).value||"").trim();
|
||||
if (!v) return null;
|
||||
const n = parseInt(v, 10);
|
||||
return isNaN(n) ? null : n;
|
||||
}
|
||||
|
||||
function escapeHtml(s){
|
||||
return (""+s)
|
||||
.replaceAll("&","&")
|
||||
.replaceAll("<","<")
|
||||
.replaceAll(">",">")
|
||||
.replaceAll('"',""")
|
||||
.replaceAll("'","&##039;");
|
||||
}
|
||||
|
||||
function loadIntoForm(b){
|
||||
document.getElementById("BeaconID").value = b.BeaconID || "";
|
||||
document.getElementById("BeaconName").value = b.BeaconName || "";
|
||||
document.getElementById("UUID").value = b.UUID || "";
|
||||
document.getElementById("NamespaceId").value = b.NamespaceId || "";
|
||||
document.getElementById("InstanceId").value = b.InstanceId || "";
|
||||
document.getElementById("IsActive").value = ("" + (b.IsActive ?? 1));
|
||||
document.getElementById("DelBeaconID").value = b.BeaconID || "";
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
const out = await api("/beacons/list.cfm", {});
|
||||
show(out);
|
||||
|
||||
const tbody = document.getElementById("rows");
|
||||
tbody.innerHTML = "";
|
||||
|
||||
const items = out.BEACONS || [];
|
||||
for (const b of items) {
|
||||
const tr = document.createElement("tr");
|
||||
tr.innerHTML = `
|
||||
<td>${b.BeaconID}</td>
|
||||
<td>${escapeHtml(b.BeaconName||"")}</td>
|
||||
<td>${escapeHtml(b.UUID||"")}</td>
|
||||
<td>${escapeHtml(b.NamespaceId||"")}</td>
|
||||
<td>${escapeHtml(b.InstanceId||"")}</td>
|
||||
<td>${b.IsActive}</td>
|
||||
`;
|
||||
tr.style.cursor = "pointer";
|
||||
tr.onclick = () => loadIntoForm(b);
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
}
|
||||
|
||||
async function saveBeacon() {
|
||||
const name = (document.getElementById("BeaconName").value || "").trim();
|
||||
if (!name) {
|
||||
show({ OK:false, ERROR:"missing_beacon_name", MESSAGE:"BeaconName is required" });
|
||||
return;
|
||||
}
|
||||
|
||||
const body = {
|
||||
BeaconID: valIntOrNull("BeaconID"),
|
||||
BeaconName: name,
|
||||
UUID: (document.getElementById("UUID").value || "").trim(),
|
||||
NamespaceId: (document.getElementById("NamespaceId").value || "").trim(),
|
||||
InstanceId: (document.getElementById("InstanceId").value || "").trim(),
|
||||
IsActive: parseInt(document.getElementById("IsActive").value, 10)
|
||||
};
|
||||
if (!body.BeaconID) delete body.BeaconID;
|
||||
|
||||
const out = await api("/beacons/save.cfm", body);
|
||||
show(out);
|
||||
await refresh();
|
||||
}
|
||||
|
||||
async function deleteBeacon() {
|
||||
const id = valIntOrNull("DelBeaconID");
|
||||
if (!id) { show({OK:false,ERROR:"missing_beacon_id"}); return; }
|
||||
|
||||
const out = await api("/beacons/delete.cfm", { BeaconID: id });
|
||||
show(out);
|
||||
await refresh();
|
||||
}
|
||||
|
||||
refresh();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</cfoutput>
|
||||
138
admin/email_users.cfm
Normal file
138
admin/email_users.cfm
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
<cfif session.UserID NEQ 0>
|
||||
|
||||
<cfif form.mode eq "start">
|
||||
|
||||
<h3>Send an email!</h3>
|
||||
|
||||
<cfparam name="users_to_email" default="">
|
||||
|
||||
<cfquery name="select_users_to_email" datasource="#application.datasource#">
|
||||
SELECT U.UserEmailAddress
|
||||
FROM Users U
|
||||
WHERE UserID in (0,1,2)
|
||||
</cfquery>
|
||||
|
||||
<cfoutput query="select_users_to_email">
|
||||
|
||||
#UserEmailAddress#,
|
||||
|
||||
<cfset users_to_email=listappend(users_to_email, #UserEmailAddress#)>
|
||||
|
||||
</cfoutput><br><br>
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitforminputemail()
|
||||
{
|
||||
document.myforminputemail.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<cfoutput><form action="#request.cgipath#" method="post" name="myforminputemail" id="myforminputemail" style="display:inline;">
|
||||
|
||||
Email subject:<br><input type="text" name="email_subject" size="30" maxlength="50"><br><br>
|
||||
|
||||
Email Body:<br>
|
||||
|
||||
<textarea name="email_body" rows="4" cols="30" placeholder="type email body here"></textarea><br><br>
|
||||
|
||||
<a href="javascript: submitforminputemail()">Submit</a><br>
|
||||
|
||||
<input type="hidden" name="mode" value="confirm_email_contents">
|
||||
<input type="hidden" name="users_to_email" value="#users_to_email#">
|
||||
|
||||
</form></cfoutput>
|
||||
|
||||
<cfelseif form.mode eq "confirm_email_contents">
|
||||
|
||||
does this look correct?<br><br>
|
||||
|
||||
Subject:<br><cfoutput>#form.email_subject#</cfoutput><br><br>
|
||||
|
||||
Body:<br><cfoutput>#HTMLCodeFormat(form.email_body)#</cfoutput>
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformsendtest()
|
||||
{
|
||||
document.myformsendtest.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<cfoutput><form action="#request.cgipath#" method="post" name="myformsendtest" id="myformsendtest" style="display:inline;">
|
||||
|
||||
<a href="javascript: submitformsendtest()">Yes, send the test email!</a><br>
|
||||
|
||||
<input type="hidden" name="mode" value="send_test_email">
|
||||
<input type="hidden" name="email_subject" value="#form.email_subject#">
|
||||
<input type="hidden" name="email_body" value="#form.email_body#">
|
||||
<input type="hidden" name="users_to_email" value="#users_to_email#">
|
||||
|
||||
</form></cfoutput>
|
||||
|
||||
<cfelseif form.mode eq "send_test_email">
|
||||
|
||||
<cfmail to="admin@payfrit.com" from="admin@payfrit.com" subject="#form.email_subject#" type="HTML">#HTMLCodeFormat(form.email_body)#</cfmail>
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformsendtest()
|
||||
{
|
||||
document.myformsendtest.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<cfoutput><form action="#request.cgipath#" method="post" name="myformsendtest" id="myformsendtest" style="display:inline;">
|
||||
|
||||
<a href="javascript: submitformsendtest()">Looks good, send the real email!</a><br>
|
||||
|
||||
<input type="hidden" name="mode" value="send_email">
|
||||
<input type="hidden" name="email_subject" value="#form.email_subject#">
|
||||
<input type="hidden" name="email_body" value="#form.email_body#">
|
||||
<input type="hidden" name="users_to_email" value="#users_to_email#">
|
||||
|
||||
</form></cfoutput>
|
||||
|
||||
<cfelseif form.mode eq "send_email">
|
||||
|
||||
<cfloop index="the_email_address" list="#users_to_email#">
|
||||
|
||||
<cfquery name="get_user_email" datasource="#application.datasource#">
|
||||
SELECT UserUUID
|
||||
FROM Users
|
||||
WHERE UserEmailAddress = '#the_email_address#'
|
||||
AND
|
||||
UserIsEmailverified = 1
|
||||
AND
|
||||
UserIsContactVerified > 0
|
||||
</cfquery>
|
||||
|
||||
<cfset form.this_email_body = form.email_body & "
|
||||
|
||||
instant unsubscribe link: https://www.payfrit.com/remove_me.cfm?UserUUID="&#get_user_email.UserUUID#>
|
||||
|
||||
<cfmail to="#the_email_address#" from="admin@payfrit.com" subject="#form.email_subject#" type="HTML">
|
||||
#HTMLCodeFormat(form.this_email_body)#</cfmail>
|
||||
|
||||
</cfloop>
|
||||
|
||||
<cfquery name="insert_email" datasource="#application.datasource#">
|
||||
INSERT INTO MarketingEmails
|
||||
(
|
||||
MarketingEmailSubject,
|
||||
MarketingEmailBody,
|
||||
MarketingEmailUsersEmailed
|
||||
)
|
||||
VALUES (
|
||||
'#form.email_subject#',
|
||||
'#form.email_body#',
|
||||
'#users_to_email#'
|
||||
)
|
||||
</cfquery>
|
||||
|
||||
Email sent!<br>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfelse>
|
||||
|
||||
Please Login!
|
||||
|
||||
</cfif>
|
||||
112
admin/god_mode.cfm
Normal file
112
admin/god_mode.cfm
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
<cfparam name="form.mode" default="start">
|
||||
|
||||
<cfif session.UserID NEQ 0>
|
||||
|
||||
<cfif form.mode eq "start">
|
||||
|
||||
<CFQUERY name="get_verified_users" datasource="#application.datasource#">
|
||||
SELECT U.UserID, U.UserEmailAddress, U.UserContactNumber,U.UserAddedOn
|
||||
FROM Users U
|
||||
WHERE U.UserIsEmailVerified = 1
|
||||
AND
|
||||
U.UserIsCOntactVerified > 0
|
||||
AND
|
||||
U.UserID > 435
|
||||
ORDER BY U.UserID DESC
|
||||
</cfquery>
|
||||
|
||||
|
||||
|
||||
<table border="0" cellspacing="5" cellpadding="5">
|
||||
<tr>
|
||||
<th>UserID</th>
|
||||
<th>Email</th>
|
||||
<th>Mobile</th>
|
||||
<th>Added On</th>
|
||||
<th>Order(s)</th>
|
||||
</tr>
|
||||
|
||||
<cfoutput query="get_verified_users">
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<script language="JavaScript">
|
||||
function submitformUserTraffic#UserID#()
|
||||
{
|
||||
document.myformUserTraffic#UserID#.submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="#request.cgipath#" method="post" name="myformUserTraffic#UserID#" id="myformUserTraffic#UserID#" style="display:inline;">
|
||||
|
||||
<a href="javascript: submitformUserTraffic#UserID#()">#UserID#</a>
|
||||
|
||||
<input type="hidden" name="mode" value="user_traffic">
|
||||
<input type="hidden" name="chip" value="#UserID#">
|
||||
|
||||
</form>
|
||||
|
||||
</td>
|
||||
<td>#UserEmailAddress#</td>
|
||||
<td>#UserContactNumber#</td>
|
||||
<td>#dateformat(UserAddedOn, "mmmm dd, YYYY")# at #timeformat(UserAddedOn, "hh:nn tt")#</td>
|
||||
<td>
|
||||
|
||||
<CFQUERY name="get_orders" datasource="#application.datasource#">
|
||||
SELECT O.OrderUUID
|
||||
FROM Orders O
|
||||
WHERE O.OrderUserID = #get_verified_users.UserID#
|
||||
ORDER BY O.OrderID DESC
|
||||
</cfquery>
|
||||
|
||||
<cfparam name="looper" default="">
|
||||
|
||||
<cfset looper=0>
|
||||
|
||||
<cfloop query="get_orders">
|
||||
<cfset looper=incrementvalue(looper)>
|
||||
<a href="https://payfr.it/show_order.cfm?OrderUUID=#get_orders.OrderUUID#&is_admin_view=1" target="_blank">#looper#</a>,
|
||||
</cfloop>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</cfoutput>
|
||||
|
||||
</table>
|
||||
|
||||
<cfelseif form.mode eq "user_traffic">
|
||||
|
||||
<CFQUERY name="get_user_traffic" datasource="#application.datasource#">
|
||||
SELECT V.VisitorTrackingPageMode, V.VisitorTrackingAddedOn
|
||||
FROM VisitorTracking V
|
||||
WHERE V.VisitorTrackingUserID = #form.chip#
|
||||
ORDER BY V.VisitorTrackingAddedOn DESC
|
||||
</cfquery>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>mode</td>
|
||||
<td>date/time</td>
|
||||
</tr>
|
||||
<cfoutput query="get_user_traffic">
|
||||
<tr>
|
||||
<td>#VisitorTrackingPageMode#</td>
|
||||
<td>#VisitorTrackingAddedOn#</td>
|
||||
</tr>
|
||||
</cfoutput>
|
||||
</table>
|
||||
|
||||
|
||||
<cfelse>
|
||||
|
||||
no mode provided!<br>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfelse>
|
||||
|
||||
please login!<br>
|
||||
|
||||
</cfif>
|
||||
228
admin/servicepoints.cfm
Normal file
228
admin/servicepoints.cfm
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="text/html; charset=utf-8" reset="true">
|
||||
|
||||
<cfoutput>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Payfrit Admin - ServicePoints</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
input, button, select { padding: 8px; margin: 6px 0; width: 520px; max-width: 100%; }
|
||||
button { width: auto; cursor: pointer; }
|
||||
table { border-collapse: collapse; width: 100%; margin-top: 12px; }
|
||||
th, td { border: 1px solid ##ddd; padding: 8px; }
|
||||
th { background: ##f5f5f5; text-align: left; }
|
||||
.row { display: flex; gap: 24px; flex-wrap: wrap; }
|
||||
.card { border: 1px solid ##ddd; padding: 14px; border-radius: 10px; flex: 1; min-width: 320px; }
|
||||
pre { background: ##111; color: ##0f0; padding: 10px; overflow: auto; border-radius: 8px; min-height: 140px; }
|
||||
.warn { color: ##b00; font-weight: bold; }
|
||||
.ok { color: ##060; font-weight: bold; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>ServicePoints</h2>
|
||||
<div class="warn">Required: ServicePointName</div>
|
||||
<div class="ok" id="jsStatus">(JS not loaded yet)</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="card">
|
||||
<h3>Create / Update</h3>
|
||||
|
||||
<div>
|
||||
<label>ServicePointID (blank = create)</label><br>
|
||||
<input id="ServicePointID" placeholder="e.g. 12">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>ServicePointName (required)</label><br>
|
||||
<input id="ServicePointName" placeholder="Front Counter" required>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>ServicePointTypeID</label><br>
|
||||
<input id="ServicePointTypeID" placeholder="0">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>ServicePointCode</label><br>
|
||||
<input id="ServicePointCode" placeholder="COUNTER">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>Description</label><br>
|
||||
<input id="Description" placeholder="">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>SortOrder</label><br>
|
||||
<input id="SortOrder" placeholder="0">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>IsActive</label><br>
|
||||
<select id="IsActive">
|
||||
<option value="1" selected>1 (Active)</option>
|
||||
<option value="0">0 (Inactive)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="button" onclick="saveSP()">Save</button>
|
||||
<button type="button" onclick="refresh()">Refresh List</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Delete (soft)</h3>
|
||||
<div>
|
||||
<label>ServicePointID</label><br>
|
||||
<input id="DelServicePointID" placeholder="e.g. 12">
|
||||
</div>
|
||||
<button type="button" onclick="deleteSP()">Delete</button>
|
||||
|
||||
<h3>Response</h3>
|
||||
<pre id="resp"></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>ServicePoint List (click row to load)</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ServicePointID</th>
|
||||
<th>Name</th>
|
||||
<th>TypeID</th>
|
||||
<th>Code</th>
|
||||
<th>SortOrder</th>
|
||||
<th>IsActive</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="rows"></tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
(function boot(){
|
||||
document.getElementById("jsStatus").textContent = "JS loaded OK";
|
||||
})();
|
||||
|
||||
function show(o){
|
||||
document.getElementById("resp").textContent = JSON.stringify(o, null, 2);
|
||||
}
|
||||
|
||||
const API_BASE = "/biz.payfrit.com/api";
|
||||
|
||||
async function api(path, bodyObj) {
|
||||
const fullPath = API_BASE + path;
|
||||
try {
|
||||
const res = await fetch(fullPath, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(bodyObj || {})
|
||||
});
|
||||
const txt = await res.text();
|
||||
try {
|
||||
const parsed = JSON.parse(txt);
|
||||
parsed._httpStatus = res.status;
|
||||
parsed._path = fullPath;
|
||||
return parsed;
|
||||
} catch {
|
||||
return { OK:false, ERROR:"non_json", RAW:txt, _httpStatus: res.status, _path: fullPath };
|
||||
}
|
||||
} catch (e) {
|
||||
return { OK:false, ERROR:"network_error", MESSAGE:String(e), _path: fullPath };
|
||||
}
|
||||
}
|
||||
|
||||
function valIntOrNull(id){
|
||||
const v = (document.getElementById(id).value||"").trim();
|
||||
if (!v) return null;
|
||||
const n = parseInt(v, 10);
|
||||
return isNaN(n) ? null : n;
|
||||
}
|
||||
function valIntOrZero(id){
|
||||
const n = valIntOrNull(id);
|
||||
return n ? n : 0;
|
||||
}
|
||||
function escapeHtml(s){
|
||||
return (""+s)
|
||||
.replaceAll("&","&")
|
||||
.replaceAll("<","<")
|
||||
.replaceAll(">",">")
|
||||
.replaceAll('"',""")
|
||||
.replaceAll("'","&##039;");
|
||||
}
|
||||
|
||||
function loadIntoForm(sp){
|
||||
document.getElementById("ServicePointID").value = sp.ServicePointID || "";
|
||||
document.getElementById("ServicePointName").value = sp.ServicePointName || "";
|
||||
document.getElementById("ServicePointTypeID").value = (sp.ServicePointTypeID ?? 0);
|
||||
document.getElementById("ServicePointCode").value = sp.ServicePointCode || "";
|
||||
document.getElementById("Description").value = sp.Description || "";
|
||||
document.getElementById("SortOrder").value = (sp.SortOrder ?? 0);
|
||||
document.getElementById("IsActive").value = ("" + (sp.IsActive ?? 1));
|
||||
document.getElementById("DelServicePointID").value = sp.ServicePointID || "";
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
const out = await api("/servicepoints/list.cfm", {});
|
||||
show(out);
|
||||
|
||||
const tbody = document.getElementById("rows");
|
||||
tbody.innerHTML = "";
|
||||
|
||||
const items = out.SERVICEPOINTS || [];
|
||||
for (const sp of items) {
|
||||
const tr = document.createElement("tr");
|
||||
tr.innerHTML = `
|
||||
<td>${sp.ServicePointID}</td>
|
||||
<td>${escapeHtml(sp.ServicePointName||"")}</td>
|
||||
<td>${sp.ServicePointTypeID}</td>
|
||||
<td>${escapeHtml(sp.ServicePointCode||"")}</td>
|
||||
<td>${sp.SortOrder}</td>
|
||||
<td>${sp.IsActive}</td>
|
||||
`;
|
||||
tr.style.cursor = "pointer";
|
||||
tr.onclick = () => loadIntoForm(sp);
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
}
|
||||
|
||||
async function saveSP() {
|
||||
const name = (document.getElementById("ServicePointName").value || "").trim();
|
||||
if (!name) {
|
||||
show({ OK:false, ERROR:"missing_servicepoint_name", MESSAGE:"ServicePointName is required" });
|
||||
return;
|
||||
}
|
||||
|
||||
const body = {
|
||||
ServicePointID: valIntOrNull("ServicePointID"),
|
||||
ServicePointName: name,
|
||||
ServicePointTypeID: valIntOrZero("ServicePointTypeID"),
|
||||
ServicePointCode: (document.getElementById("ServicePointCode").value || "").trim(),
|
||||
Description: (document.getElementById("Description").value || "").trim(),
|
||||
SortOrder: valIntOrZero("SortOrder"),
|
||||
IsActive: parseInt(document.getElementById("IsActive").value, 10)
|
||||
};
|
||||
if (!body.ServicePointID) delete body.ServicePointID;
|
||||
|
||||
const out = await api("/servicepoints/save.cfm", body);
|
||||
show(out);
|
||||
await refresh();
|
||||
}
|
||||
|
||||
async function deleteSP() {
|
||||
const id = valIntOrNull("DelServicePointID");
|
||||
if (!id) { show({OK:false,ERROR:"missing_servicepoint_id"}); return; }
|
||||
|
||||
const out = await api("/servicepoints/delete.cfm", { ServicePointID: id });
|
||||
show(out);
|
||||
await refresh();
|
||||
}
|
||||
|
||||
refresh();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</cfoutput>
|
||||
BIN
android-chrome-192x192.png
Normal file
BIN
android-chrome-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
BIN
android-chrome-512x512.png
Normal file
BIN
android-chrome-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
51
api/Application.cfm
Normal file
51
api/Application.cfm
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<!---
|
||||
FILE: C:\lucee\tomcat\webapps\ROOT\biz.payfrit.com\api\Application.cfm
|
||||
|
||||
GOAL:
|
||||
- Ensure /api/* requests run under the SAME CF application/session as biz.payfrit.com
|
||||
by including the parent Application.cfm (because CF uses the nearest Application.cfm).
|
||||
- Force JSON responses for API requests (never HTML).
|
||||
- Gate access based on existing biz login + business "Become" selection:
|
||||
session.UserID / request.UserID
|
||||
session.BusinessID / request.BusinessID
|
||||
--->
|
||||
|
||||
<!--- Mark API context BEFORE including parent, in case parent logic checks it --->
|
||||
<cfset request.IsApiRequest = true>
|
||||
|
||||
<!---
|
||||
CRITICAL:
|
||||
Without this include, /api/* becomes a different app/session and won't see logged-in state.
|
||||
--->
|
||||
<cfinclude template="../Application.cfm">
|
||||
|
||||
<!--- Force JSON for everything under /api --->
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj) {
|
||||
writeOutput(serializeJSON(obj));
|
||||
abort;
|
||||
}
|
||||
|
||||
// Some apps store auth in session and copy to request in page code.
|
||||
// Make /api resilient by copying from session if needed.
|
||||
if (!structKeyExists(request, "UserID") && structKeyExists(session, "UserID")) {
|
||||
request.UserID = Duplicate(session.UserID);
|
||||
}
|
||||
if (!structKeyExists(request, "BusinessID") && structKeyExists(session, "BusinessID")) {
|
||||
request.BusinessID = Duplicate(session.BusinessID);
|
||||
}
|
||||
|
||||
// Enforce auth for all /api endpoints
|
||||
if (!structKeyExists(request, "UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="not_logged_in" });
|
||||
}
|
||||
if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="no_business_selected" });
|
||||
}
|
||||
</cfscript>
|
||||
50
api/New folder/delete.cfm
Normal file
50
api/New folder/delete.cfm
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj){ writeOutput(serializeJSON(obj)); abort; }
|
||||
|
||||
function readJsonBody(){
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0) return {};
|
||||
try { parsed = deserializeJSON(raw); }
|
||||
catch(any e){ apiAbort({ OK=false, ERROR="bad_json", MESSAGE="Invalid JSON body" }); }
|
||||
if (!isStruct(parsed)) return {};
|
||||
return parsed;
|
||||
}
|
||||
|
||||
data = readJsonBody();
|
||||
|
||||
if (!structKeyExists(request,"UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) apiAbort({OK=false,ERROR="not_logged_in"});
|
||||
if (!structKeyExists(request,"BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) apiAbort({OK=false,ERROR="no_business_selected"});
|
||||
|
||||
if (!structKeyExists(data,"ServicePointID") || !isNumeric(data.ServicePointID) || int(data.ServicePointID) LTE 0) {
|
||||
apiAbort({OK=false,ERROR="missing_servicepoint_id"});
|
||||
}
|
||||
spid = int(data.ServicePointID);
|
||||
</cfscript>
|
||||
|
||||
<cfquery datasource="#application.datasource#">
|
||||
UPDATE ServicePoints
|
||||
SET IsActive = 0
|
||||
WHERE ServicePointID = <cfqueryparam cfsqltype="cf_sql_integer" value="#spid#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="qCheck" datasource="#application.datasource#">
|
||||
SELECT ServicePointID
|
||||
FROM ServicePoints
|
||||
WHERE ServicePointID = <cfqueryparam cfsqltype="cf_sql_integer" value="#spid#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
|
||||
<cfif qCheck.recordCount EQ 0>
|
||||
<cfoutput>#serializeJSON({ OK=false, ERROR="not_found" })#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<cfoutput>#serializeJSON({ OK=true, ERROR="", ServicePointID=spid })#</cfoutput>
|
||||
67
api/New folder/get.cfm
Normal file
67
api/New folder/get.cfm
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj){ writeOutput(serializeJSON(obj)); abort; }
|
||||
|
||||
function readJsonBody(){
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0) return {};
|
||||
try { parsed = deserializeJSON(raw); }
|
||||
catch(any e){ apiAbort({ OK=false, ERROR="bad_json", MESSAGE="Invalid JSON body" }); }
|
||||
if (!isStruct(parsed)) return {};
|
||||
return parsed;
|
||||
}
|
||||
|
||||
data = readJsonBody();
|
||||
|
||||
if (!structKeyExists(request,"UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) apiAbort({OK=false,ERROR="not_logged_in"});
|
||||
if (!structKeyExists(request,"BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) apiAbort({OK=false,ERROR="no_business_selected"});
|
||||
|
||||
if (!structKeyExists(data,"ServicePointID") || !isNumeric(data.ServicePointID) || int(data.ServicePointID) LTE 0) {
|
||||
apiAbort({OK=false,ERROR="missing_servicepoint_id"});
|
||||
}
|
||||
|
||||
spid = int(data.ServicePointID);
|
||||
</cfscript>
|
||||
|
||||
<cfquery name="q" datasource="#application.datasource#">
|
||||
SELECT
|
||||
ServicePointID,
|
||||
BusinessID,
|
||||
ServicePointName,
|
||||
ServicePointTypeID,
|
||||
ServicePointCode,
|
||||
Description,
|
||||
SortOrder,
|
||||
IsActive,
|
||||
CreatedAt,
|
||||
UpdatedAt
|
||||
FROM ServicePoints
|
||||
WHERE ServicePointID = <cfqueryparam cfsqltype="cf_sql_integer" value="#spid#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
|
||||
<cfif q.recordCount EQ 0>
|
||||
<cfoutput>#serializeJSON({ OK=false, ERROR="not_found" })#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<cfset sp = {
|
||||
"ServicePointID"=q.ServicePointID,
|
||||
"BusinessID"=q.BusinessID,
|
||||
"ServicePointName"=q.ServicePointName,
|
||||
"ServicePointTypeID"=q.ServicePointTypeID,
|
||||
"ServicePointCode"=q.ServicePointCode,
|
||||
"Description"=q.Description,
|
||||
"SortOrder"=q.SortOrder,
|
||||
"IsActive"=q.IsActive,
|
||||
"CreatedAt"=(q.CreatedAt & ""),
|
||||
"UpdatedAt"=(q.UpdatedAt & "")
|
||||
}>
|
||||
|
||||
<cfoutput>#serializeJSON({ OK=true, ERROR="", SERVICEPOINT=sp })#</cfoutput>
|
||||
82
api/New folder/list.cfm
Normal file
82
api/New folder/list.cfm
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj) {
|
||||
writeOutput(serializeJSON(obj));
|
||||
abort;
|
||||
}
|
||||
|
||||
function readJsonBody() {
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0) return {};
|
||||
try {
|
||||
parsed = deserializeJSON(raw);
|
||||
} catch(any e) {
|
||||
apiAbort({ OK=false, ERROR="bad_json", MESSAGE="Invalid JSON body" });
|
||||
}
|
||||
if (!isStruct(parsed)) return {};
|
||||
return parsed;
|
||||
}
|
||||
|
||||
data = readJsonBody();
|
||||
|
||||
if (!structKeyExists(request, "UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="not_logged_in" });
|
||||
}
|
||||
if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="no_business_selected" });
|
||||
}
|
||||
|
||||
onlyActive = true;
|
||||
if (structKeyExists(data, "onlyActive")) {
|
||||
if (isBoolean(data.onlyActive)) {
|
||||
onlyActive = data.onlyActive;
|
||||
} else if (isNumeric(data.onlyActive)) {
|
||||
onlyActive = (int(data.onlyActive) EQ 1);
|
||||
} else if (isSimpleValue(data.onlyActive)) {
|
||||
onlyActive = (lcase(trim(toString(data.onlyActive))) EQ "true");
|
||||
}
|
||||
}
|
||||
</cfscript>
|
||||
|
||||
<cfquery name="q" datasource="#application.datasource#">
|
||||
SELECT
|
||||
ServicePointID,
|
||||
BusinessID,
|
||||
ServicePointName,
|
||||
ServicePointTypeID,
|
||||
ServicePointCode,
|
||||
Description,
|
||||
SortOrder,
|
||||
IsActive,
|
||||
CreatedAt,
|
||||
UpdatedAt
|
||||
FROM ServicePoints
|
||||
WHERE BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
<cfif onlyActive>
|
||||
AND IsActive = 1
|
||||
</cfif>
|
||||
ORDER BY SortOrder, ServicePointName, ServicePointID
|
||||
</cfquery>
|
||||
|
||||
<cfset sps = []>
|
||||
<cfloop query="q">
|
||||
<cfset arrayAppend(sps, {
|
||||
"ServicePointID"=q.ServicePointID,
|
||||
"BusinessID"=q.BusinessID,
|
||||
"ServicePointName"=q.ServicePointName,
|
||||
"ServicePointTypeID"=q.ServicePointTypeID,
|
||||
"ServicePointCode"=q.ServicePointCode,
|
||||
"Description"=q.Description,
|
||||
"SortOrder"=q.SortOrder,
|
||||
"IsActive"=q.IsActive,
|
||||
"CreatedAt"=(q.CreatedAt & ""),
|
||||
"UpdatedAt"=(q.UpdatedAt & "")
|
||||
})>
|
||||
</cfloop>
|
||||
|
||||
<cfoutput>#serializeJSON({ OK=true, ERROR="", BUSINESSID=(request.BusinessID & ""), COUNT=arrayLen(sps), SERVICEPOINTS=sps })#</cfoutput>
|
||||
136
api/New folder/save.cfm
Normal file
136
api/New folder/save.cfm
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj){ writeOutput(serializeJSON(obj)); abort; }
|
||||
|
||||
function readJsonBody(){
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0) return {};
|
||||
try { parsed = deserializeJSON(raw); }
|
||||
catch(any e){ apiAbort({ OK=false, ERROR="bad_json", MESSAGE="Invalid JSON body" }); }
|
||||
if (!isStruct(parsed)) return {};
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function normStr(v){
|
||||
if (isNull(v)) return "";
|
||||
return trim(toString(v));
|
||||
}
|
||||
|
||||
data = readJsonBody();
|
||||
|
||||
if (!structKeyExists(request,"UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) apiAbort({OK=false,ERROR="not_logged_in"});
|
||||
if (!structKeyExists(request,"BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) apiAbort({OK=false,ERROR="no_business_selected"});
|
||||
|
||||
if (!structKeyExists(data,"ServicePointName") || len(normStr(data.ServicePointName)) EQ 0) {
|
||||
apiAbort({OK=false,ERROR="missing_servicepoint_name",MESSAGE="ServicePointName is required"});
|
||||
}
|
||||
|
||||
spid = 0;
|
||||
if (structKeyExists(data,"ServicePointID") && isNumeric(data.ServicePointID) && int(data.ServicePointID) GT 0) {
|
||||
spid = int(data.ServicePointID);
|
||||
}
|
||||
|
||||
spName = normStr(data.ServicePointName);
|
||||
spTypeID = (structKeyExists(data,"ServicePointTypeID") && isNumeric(data.ServicePointTypeID)) ? int(data.ServicePointTypeID) : 0;
|
||||
spCode = structKeyExists(data,"ServicePointCode") ? normStr(data.ServicePointCode) : "";
|
||||
descr = structKeyExists(data,"Description") ? normStr(data.Description) : "";
|
||||
sortOrd = (structKeyExists(data,"SortOrder") && isNumeric(data.SortOrder)) ? int(data.SortOrder) : 0;
|
||||
|
||||
isActive = 1;
|
||||
if (structKeyExists(data,"IsActive")) {
|
||||
if (isBoolean(data.IsActive)) isActive = (data.IsActive ? 1 : 0);
|
||||
else if (isNumeric(data.IsActive)) isActive = int(data.IsActive);
|
||||
else if (isSimpleValue(data.IsActive)) isActive = (lcase(trim(toString(data.IsActive))) EQ "true" ? 1 : 0);
|
||||
}
|
||||
</cfscript>
|
||||
|
||||
<cfif spid GT 0>
|
||||
<cfquery datasource="#application.datasource#">
|
||||
UPDATE ServicePoints
|
||||
SET
|
||||
ServicePointName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#spName#">,
|
||||
ServicePointTypeID = <cfqueryparam cfsqltype="cf_sql_integer" value="#spTypeID#">,
|
||||
ServicePointCode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#spCode#" null="#(len(spCode) EQ 0)#">,
|
||||
Description = <cfqueryparam cfsqltype="cf_sql_varchar" value="#descr#" null="#(len(descr) EQ 0)#">,
|
||||
SortOrder = <cfqueryparam cfsqltype="cf_sql_integer" value="#sortOrd#">,
|
||||
IsActive = <cfqueryparam cfsqltype="cf_sql_tinyint" value="#isActive#">
|
||||
WHERE ServicePointID = <cfqueryparam cfsqltype="cf_sql_integer" value="#spid#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="qCheck" datasource="#application.datasource#">
|
||||
SELECT ServicePointID
|
||||
FROM ServicePoints
|
||||
WHERE ServicePointID = <cfqueryparam cfsqltype="cf_sql_integer" value="#spid#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
|
||||
<cfif qCheck.recordCount EQ 0>
|
||||
<cfoutput>#serializeJSON({ OK=false, ERROR="not_found" })#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
<cfelse>
|
||||
<cfquery datasource="#application.datasource#">
|
||||
INSERT INTO ServicePoints (
|
||||
BusinessID,
|
||||
ServicePointName,
|
||||
ServicePointTypeID,
|
||||
ServicePointCode,
|
||||
Description,
|
||||
SortOrder,
|
||||
IsActive
|
||||
) VALUES (
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_varchar" value="#spName#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#spTypeID#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_varchar" value="#spCode#" null="#(len(spCode) EQ 0)#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_varchar" value="#descr#" null="#(len(descr) EQ 0)#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#sortOrd#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_tinyint" value="#isActive#">
|
||||
)
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="qId" datasource="#application.datasource#">
|
||||
SELECT LAST_INSERT_ID() AS ServicePointID
|
||||
</cfquery>
|
||||
<cfset spid = qId.ServicePointID>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="qOut" datasource="#application.datasource#">
|
||||
SELECT
|
||||
ServicePointID,
|
||||
BusinessID,
|
||||
ServicePointName,
|
||||
ServicePointTypeID,
|
||||
ServicePointCode,
|
||||
Description,
|
||||
SortOrder,
|
||||
IsActive,
|
||||
CreatedAt,
|
||||
UpdatedAt
|
||||
FROM ServicePoints
|
||||
WHERE ServicePointID = <cfqueryparam cfsqltype="cf_sql_integer" value="#spid#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
|
||||
<cfset sp = {
|
||||
"ServicePointID"=qOut.ServicePointID,
|
||||
"BusinessID"=qOut.BusinessID,
|
||||
"ServicePointName"=qOut.ServicePointName,
|
||||
"ServicePointTypeID"=qOut.ServicePointTypeID,
|
||||
"ServicePointCode"=qOut.ServicePointCode,
|
||||
"Description"=qOut.Description,
|
||||
"SortOrder"=qOut.SortOrder,
|
||||
"IsActive"=qOut.IsActive,
|
||||
"CreatedAt"=(qOut.CreatedAt & ""),
|
||||
"UpdatedAt"=(qOut.UpdatedAt & "")
|
||||
}>
|
||||
|
||||
<cfoutput>#serializeJSON({ OK=true, ERROR="", SERVICEPOINT=sp })#</cfoutput>
|
||||
93
api/assignments/delete.cfm
Normal file
93
api/assignments/delete.cfm
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj){
|
||||
writeOutput(serializeJSON(obj));
|
||||
abort;
|
||||
}
|
||||
|
||||
function readJsonBody(){
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0){
|
||||
apiAbort({OK=false,ERROR="missing_body"});
|
||||
}
|
||||
try {
|
||||
parsed = deserializeJSON(raw);
|
||||
} catch(any e){
|
||||
apiAbort({OK=false,ERROR="bad_json",MESSAGE="Invalid JSON body"});
|
||||
}
|
||||
if (!isStruct(parsed)){
|
||||
apiAbort({OK=false,ERROR="bad_json",MESSAGE="JSON must be an object"});
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/* ---------- AUTH CONTEXT ---------- */
|
||||
if (!structKeyExists(request,"UserID") || !isNumeric(request.UserID) || request.UserID LTE 0){
|
||||
apiAbort({OK=false,ERROR="not_logged_in"});
|
||||
}
|
||||
if (!structKeyExists(request,"BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0){
|
||||
apiAbort({OK=false,ERROR="no_business_selected"});
|
||||
}
|
||||
|
||||
/* ---------- INPUT ---------- */
|
||||
data = readJsonBody();
|
||||
|
||||
if (
|
||||
!structKeyExists(data,"lt_Beacon_Businesses_ServicePointID")
|
||||
|| !isNumeric(data.lt_Beacon_Businesses_ServicePointID)
|
||||
|| int(data.lt_Beacon_Businesses_ServicePointID) LTE 0
|
||||
){
|
||||
apiAbort({OK=false,ERROR="missing_lt_Beacon_Businesses_ServicePointID"});
|
||||
}
|
||||
|
||||
RelID = int(data.lt_Beacon_Businesses_ServicePointID);
|
||||
</cfscript>
|
||||
|
||||
<!--- Confirm the row exists for this BusinessID (and capture what it was) --->
|
||||
<cfquery name="qFind" datasource="#application.datasource#">
|
||||
SELECT
|
||||
lt_Beacon_Businesses_ServicePointID,
|
||||
BeaconID,
|
||||
ServicePointID
|
||||
FROM lt_Beacon_Businesses_ServicePoints
|
||||
WHERE lt_Beacon_Businesses_ServicePointID =
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#RelID#">
|
||||
AND BusinessID =
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
|
||||
<cfif qFind.recordCount EQ 0>
|
||||
<cfoutput>#serializeJSON({
|
||||
"OK"=false,
|
||||
"ERROR"="not_found",
|
||||
"lt_Beacon_Businesses_ServicePointID"=RelID,
|
||||
"BusinessID"=(request.BusinessID & "")
|
||||
})#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<!--- Delete it --->
|
||||
<cfquery datasource="#application.datasource#">
|
||||
DELETE FROM lt_Beacon_Businesses_ServicePoints
|
||||
WHERE lt_Beacon_Businesses_ServicePointID =
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#RelID#">
|
||||
AND BusinessID =
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
|
||||
<cfoutput>#serializeJSON({
|
||||
"OK"=true,
|
||||
"ERROR"="",
|
||||
"ACTION"="deleted",
|
||||
"lt_Beacon_Businesses_ServicePointID"=RelID,
|
||||
"BeaconID"=qFind.BeaconID,
|
||||
"ServicePointID"=qFind.ServicePointID,
|
||||
"BusinessID"=(request.BusinessID & "")
|
||||
})#</cfoutput>
|
||||
68
api/assignments/list.cfm
Normal file
68
api/assignments/list.cfm
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj){
|
||||
writeOutput(serializeJSON(obj));
|
||||
abort;
|
||||
}
|
||||
|
||||
if (!structKeyExists(request,"UserID") || !isNumeric(request.UserID) || request.UserID LTE 0){
|
||||
apiAbort({OK=false,ERROR="not_logged_in"});
|
||||
}
|
||||
if (!structKeyExists(request,"BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0){
|
||||
apiAbort({OK=false,ERROR="no_business_selected"});
|
||||
}
|
||||
</cfscript>
|
||||
|
||||
<cfquery name="q" datasource="#application.datasource#">
|
||||
SELECT
|
||||
lt.lt_Beacon_Businesses_ServicePointID AS lt_Beacon_Businesses_ServicePointID,
|
||||
lt.BeaconID AS BeaconID,
|
||||
b.BeaconName AS BeaconName,
|
||||
lt.ServicePointID AS ServicePointID,
|
||||
sp.ServicePointName AS ServicePointName,
|
||||
lt.lt_Beacon_Businesses_ServicePointNotes AS lt_Beacon_Businesses_ServicePointNotes,
|
||||
lt.CreatedAt AS CreatedAt
|
||||
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||
INNER JOIN Beacons b
|
||||
ON b.BeaconID = lt.BeaconID
|
||||
AND b.BusinessID = lt.BusinessID
|
||||
INNER JOIN ServicePoints sp
|
||||
ON sp.ServicePointID = lt.ServicePointID
|
||||
AND sp.BusinessID = lt.BusinessID
|
||||
WHERE lt.BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
ORDER BY lt.lt_Beacon_Businesses_ServicePointID DESC
|
||||
</cfquery>
|
||||
|
||||
<cfscript>
|
||||
assignments = [];
|
||||
i = 1;
|
||||
|
||||
for (i = 1; i <= q.recordCount; i = i + 1){
|
||||
// Build keys EXACTLY as the admin UI expects (case-sensitive in JS)
|
||||
row = {
|
||||
"lt_Beacon_Businesses_ServicePointID": q["lt_Beacon_Businesses_ServicePointID"][i],
|
||||
"BeaconID": q["BeaconID"][i],
|
||||
"BeaconName": q["BeaconName"][i],
|
||||
"ServicePointID": q["ServicePointID"][i],
|
||||
"ServicePointName": q["ServicePointName"][i],
|
||||
"lt_Beacon_Businesses_ServicePointNotes": q["lt_Beacon_Businesses_ServicePointNotes"][i],
|
||||
"CreatedAt": q["CreatedAt"][i]
|
||||
};
|
||||
arrayAppend(assignments, row);
|
||||
}
|
||||
|
||||
out = {
|
||||
"OK": true,
|
||||
"ERROR": "",
|
||||
"BUSINESSID": (request.BusinessID & ""),
|
||||
"COUNT": arrayLen(assignments),
|
||||
"ASSIGNMENTS": assignments
|
||||
};
|
||||
</cfscript>
|
||||
|
||||
<cfoutput>#serializeJSON(out)#</cfoutput>
|
||||
138
api/assignments/save.cfm
Normal file
138
api/assignments/save.cfm
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj){
|
||||
writeOutput(serializeJSON(obj));
|
||||
abort;
|
||||
}
|
||||
|
||||
function readJsonBody(){
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0){
|
||||
apiAbort({OK=false,ERROR="missing_body"});
|
||||
}
|
||||
try {
|
||||
parsed = deserializeJSON(raw);
|
||||
} catch(any e){
|
||||
apiAbort({OK=false,ERROR="bad_json",MESSAGE="Invalid JSON body"});
|
||||
}
|
||||
if (!isStruct(parsed)){
|
||||
apiAbort({OK=false,ERROR="bad_json",MESSAGE="JSON must be an object"});
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function normStr(v){
|
||||
if (isNull(v)) return "";
|
||||
return trim(toString(v));
|
||||
}
|
||||
|
||||
/* ---------- AUTH CONTEXT ---------- */
|
||||
if (!structKeyExists(request,"UserID") || !isNumeric(request.UserID) || request.UserID LTE 0){
|
||||
apiAbort({OK=false,ERROR="not_logged_in"});
|
||||
}
|
||||
if (!structKeyExists(request,"BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0){
|
||||
apiAbort({OK=false,ERROR="no_business_selected"});
|
||||
}
|
||||
|
||||
/* ---------- INPUT ---------- */
|
||||
data = readJsonBody();
|
||||
|
||||
if (!structKeyExists(data,"BeaconID") || !isNumeric(data.BeaconID) || int(data.BeaconID) LTE 0){
|
||||
apiAbort({OK=false,ERROR="missing_BeaconID"});
|
||||
}
|
||||
if (!structKeyExists(data,"ServicePointID") || !isNumeric(data.ServicePointID) || int(data.ServicePointID) LTE 0){
|
||||
apiAbort({OK=false,ERROR="missing_ServicePointID"});
|
||||
}
|
||||
|
||||
BeaconID = int(data.BeaconID);
|
||||
ServicePointID = int(data.ServicePointID);
|
||||
Notes = "";
|
||||
if (structKeyExists(data,"Notes")){
|
||||
Notes = left(normStr(data.Notes), 255);
|
||||
}
|
||||
</cfscript>
|
||||
|
||||
<!--- Validate Beacon belongs to Business --->
|
||||
<cfquery name="qB" datasource="#application.datasource#">
|
||||
SELECT BeaconID
|
||||
FROM Beacons
|
||||
WHERE BeaconID = <cfqueryparam cfsqltype="cf_sql_integer" value="#BeaconID#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
<cfif qB.recordCount EQ 0>
|
||||
<cfoutput>#serializeJSON({OK=false,ERROR="beacon_not_found_for_business"})#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<!--- Validate ServicePoint belongs to Business --->
|
||||
<cfquery name="qS" datasource="#application.datasource#">
|
||||
SELECT ServicePointID
|
||||
FROM ServicePoints
|
||||
WHERE ServicePointID = <cfqueryparam cfsqltype="cf_sql_integer" value="#ServicePointID#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
<cfif qS.recordCount EQ 0>
|
||||
<cfoutput>#serializeJSON({OK=false,ERROR="servicepoint_not_found_for_business"})#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<!--- Enforce 1:1 uniqueness --->
|
||||
<cfquery name="qBeaconTaken" datasource="#application.datasource#">
|
||||
SELECT lt_Beacon_Businesses_ServicePointID
|
||||
FROM lt_Beacon_Businesses_ServicePoints
|
||||
WHERE BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
AND BeaconID = <cfqueryparam cfsqltype="cf_sql_integer" value="#BeaconID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
<cfif qBeaconTaken.recordCount GT 0>
|
||||
<cfoutput>#serializeJSON({OK=false,ERROR="beacon_already_assigned"})#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="qServicePointTaken" datasource="#application.datasource#">
|
||||
SELECT lt_Beacon_Businesses_ServicePointID
|
||||
FROM lt_Beacon_Businesses_ServicePoints
|
||||
WHERE BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
AND ServicePointID = <cfqueryparam cfsqltype="cf_sql_integer" value="#ServicePointID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
<cfif qServicePointTaken.recordCount GT 0>
|
||||
<cfoutput>#serializeJSON({OK=false,ERROR="servicepoint_already_assigned"})#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<!--- INSERT --->
|
||||
<cfquery datasource="#application.datasource#">
|
||||
INSERT INTO lt_Beacon_Businesses_ServicePoints
|
||||
(BusinessID, BeaconID, ServicePointID,
|
||||
lt_Beacon_Businesses_ServicePointAssignedByUserID,
|
||||
lt_Beacon_Businesses_ServicePointNotes)
|
||||
VALUES
|
||||
(
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#BeaconID#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#ServicePointID#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#request.UserID#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_varchar" value="#Notes#" null="#(len(Notes) EQ 0)#">
|
||||
)
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="qID" datasource="#application.datasource#">
|
||||
SELECT LAST_INSERT_ID() AS NewID
|
||||
</cfquery>
|
||||
|
||||
<cfoutput>#serializeJSON({
|
||||
"OK"=true,
|
||||
"ACTION"="inserted",
|
||||
"lt_Beacon_Businesses_ServicePointID"=qID.NewID,
|
||||
"BeaconID"=BeaconID,
|
||||
"ServicePointID"=ServicePointID,
|
||||
"BusinessID"=(request.BusinessID & "")
|
||||
})#</cfoutput>
|
||||
62
api/beacons/delete.cfm
Normal file
62
api/beacons/delete.cfm
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj) {
|
||||
writeOutput(serializeJSON(obj));
|
||||
abort;
|
||||
}
|
||||
|
||||
function readJsonBody() {
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0) return {};
|
||||
try {
|
||||
parsed = deserializeJSON(raw);
|
||||
} catch(any e) {
|
||||
apiAbort({ OK=false, ERROR="bad_json", MESSAGE="Invalid JSON body" });
|
||||
}
|
||||
if (!isStruct(parsed)) return {};
|
||||
return parsed;
|
||||
}
|
||||
|
||||
data = readJsonBody();
|
||||
|
||||
if (!structKeyExists(request, "UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="not_logged_in" });
|
||||
}
|
||||
if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="no_business_selected" });
|
||||
}
|
||||
|
||||
if (!structKeyExists(data, "BeaconID") || !isNumeric(data.BeaconID) || int(data.BeaconID) LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="missing_beacon_id", MESSAGE="BeaconID is required" });
|
||||
}
|
||||
|
||||
beaconId = int(data.BeaconID);
|
||||
</cfscript>
|
||||
|
||||
<cfquery datasource="#application.datasource#">
|
||||
UPDATE Beacons
|
||||
SET IsActive = 0
|
||||
WHERE BeaconID = <cfqueryparam cfsqltype="cf_sql_integer" value="#beaconId#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
</cfquery>
|
||||
|
||||
<!--- confirm --->
|
||||
<cfquery name="qCheck" datasource="#application.datasource#">
|
||||
SELECT BeaconID, IsActive
|
||||
FROM Beacons
|
||||
WHERE BeaconID = <cfqueryparam cfsqltype="cf_sql_integer" value="#beaconId#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
|
||||
<cfif qCheck.recordCount EQ 0>
|
||||
<cfoutput>#serializeJSON({ OK=false, ERROR="not_found" })#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<cfoutput>#serializeJSON({ OK=true, ERROR="", BeaconID=beaconId })#</cfoutput>
|
||||
75
api/beacons/get.cfm
Normal file
75
api/beacons/get.cfm
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj) {
|
||||
writeOutput(serializeJSON(obj));
|
||||
abort;
|
||||
}
|
||||
|
||||
function readJsonBody() {
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0) return {};
|
||||
try {
|
||||
parsed = deserializeJSON(raw);
|
||||
} catch(any e) {
|
||||
apiAbort({ OK=false, ERROR="bad_json", MESSAGE="Invalid JSON body" });
|
||||
}
|
||||
if (!isStruct(parsed)) return {};
|
||||
return parsed;
|
||||
}
|
||||
|
||||
data = readJsonBody();
|
||||
|
||||
if (!structKeyExists(request, "UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="not_logged_in" });
|
||||
}
|
||||
if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="no_business_selected" });
|
||||
}
|
||||
|
||||
if (!structKeyExists(data, "BeaconID") || !isNumeric(data.BeaconID) || int(data.BeaconID) LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="missing_beacon_id", MESSAGE="BeaconID is required" });
|
||||
}
|
||||
|
||||
beaconId = int(data.BeaconID);
|
||||
</cfscript>
|
||||
|
||||
<cfquery name="q" datasource="#application.datasource#">
|
||||
SELECT
|
||||
BeaconID,
|
||||
BusinessID,
|
||||
BeaconName,
|
||||
UUID,
|
||||
NamespaceId,
|
||||
InstanceId,
|
||||
IsActive,
|
||||
CreatedAt,
|
||||
UpdatedAt
|
||||
FROM Beacons
|
||||
WHERE BeaconID = <cfqueryparam cfsqltype="cf_sql_integer" value="#beaconId#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
|
||||
<cfif q.recordCount EQ 0>
|
||||
<cfoutput>#serializeJSON({ OK=false, ERROR="not_found" })#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<cfset beacon = {
|
||||
"BeaconID" = q.BeaconID,
|
||||
"BusinessID" = q.BusinessID,
|
||||
"BeaconName" = q.BeaconName,
|
||||
"UUID" = q.UUID,
|
||||
"NamespaceId" = q.NamespaceId,
|
||||
"InstanceId" = q.InstanceId,
|
||||
"IsActive" = q.IsActive,
|
||||
"CreatedAt" = q.CreatedAt,
|
||||
"UpdatedAt" = q.UpdatedAt
|
||||
}>
|
||||
|
||||
<cfoutput>#serializeJSON({ OK=true, ERROR="", BEACON=beacon })#</cfoutput>
|
||||
84
api/beacons/list.cfm
Normal file
84
api/beacons/list.cfm
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj) {
|
||||
writeOutput(serializeJSON(obj));
|
||||
abort;
|
||||
}
|
||||
|
||||
function readJsonBody() {
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0) return {};
|
||||
try {
|
||||
parsed = deserializeJSON(raw);
|
||||
} catch(any e) {
|
||||
apiAbort({ OK=false, ERROR="bad_json", MESSAGE="Invalid JSON body" });
|
||||
}
|
||||
// We only accept object bodies
|
||||
if (!isStruct(parsed)) return {};
|
||||
return parsed;
|
||||
}
|
||||
|
||||
data = readJsonBody();
|
||||
|
||||
// Auth/business gating should already happen in /api/Application.cfm,
|
||||
// but keep this defensive so the file is safe standalone.
|
||||
if (!structKeyExists(request, "UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="not_logged_in" });
|
||||
}
|
||||
if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="no_business_selected" });
|
||||
}
|
||||
|
||||
// Default behavior: only active beacons unless onlyActive is explicitly false/0
|
||||
onlyActive = true;
|
||||
if (structKeyExists(data, "onlyActive")) {
|
||||
if (isBoolean(data.onlyActive)) {
|
||||
onlyActive = data.onlyActive;
|
||||
} else if (isNumeric(data.onlyActive)) {
|
||||
onlyActive = (int(data.onlyActive) EQ 1);
|
||||
} else if (isSimpleValue(data.onlyActive)) {
|
||||
onlyActive = (lcase(trim(toString(data.onlyActive))) EQ "true");
|
||||
}
|
||||
}
|
||||
</cfscript>
|
||||
|
||||
<cfquery name="q" datasource="#application.datasource#">
|
||||
SELECT
|
||||
BeaconID,
|
||||
BusinessID,
|
||||
BeaconName,
|
||||
UUID,
|
||||
NamespaceId,
|
||||
InstanceId,
|
||||
IsActive,
|
||||
CreatedAt,
|
||||
UpdatedAt
|
||||
FROM Beacons
|
||||
WHERE BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
<cfif onlyActive>
|
||||
AND IsActive = 1
|
||||
</cfif>
|
||||
ORDER BY BeaconName, BeaconID
|
||||
</cfquery>
|
||||
|
||||
<cfset beacons = []>
|
||||
<cfloop query="q">
|
||||
<cfset arrayAppend(beacons, {
|
||||
"BeaconID" = q.BeaconID,
|
||||
"BusinessID" = q.BusinessID,
|
||||
"BeaconName" = q.BeaconName,
|
||||
"UUID" = q.UUID,
|
||||
"NamespaceId" = q.NamespaceId,
|
||||
"InstanceId" = q.InstanceId,
|
||||
"IsActive" = q.IsActive,
|
||||
"CreatedAt" = q.CreatedAt,
|
||||
"UpdatedAt" = q.UpdatedAt
|
||||
})>
|
||||
</cfloop>
|
||||
|
||||
<cfoutput>#serializeJSON({ OK=true, ERROR="", BusinessID=request.BusinessID, COUNT=arrayLen(beacons), BEACONS=beacons })#</cfoutput>
|
||||
145
api/beacons/save.cfm
Normal file
145
api/beacons/save.cfm
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj) {
|
||||
writeOutput(serializeJSON(obj));
|
||||
abort;
|
||||
}
|
||||
|
||||
function readJsonBody() {
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0) return {};
|
||||
try {
|
||||
parsed = deserializeJSON(raw);
|
||||
} catch(any e) {
|
||||
apiAbort({ OK=false, ERROR="bad_json", MESSAGE="Invalid JSON body" });
|
||||
}
|
||||
if (!isStruct(parsed)) return {};
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function normStr(v) {
|
||||
if (isNull(v)) return "";
|
||||
return trim(toString(v));
|
||||
}
|
||||
|
||||
data = readJsonBody();
|
||||
|
||||
if (!structKeyExists(request, "UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="not_logged_in" });
|
||||
}
|
||||
if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="no_business_selected" });
|
||||
}
|
||||
|
||||
if (!structKeyExists(data, "BeaconName") || len(normStr(data.BeaconName)) EQ 0) {
|
||||
apiAbort({ OK=false, ERROR="missing_beacon_name", MESSAGE="BeaconName is required" });
|
||||
}
|
||||
|
||||
beaconId = 0;
|
||||
if (structKeyExists(data, "BeaconID") && isNumeric(data.BeaconID) && int(data.BeaconID) GT 0) {
|
||||
beaconId = int(data.BeaconID);
|
||||
}
|
||||
|
||||
beaconName = normStr(data.BeaconName);
|
||||
uuid = structKeyExists(data, "UUID") ? normStr(data.UUID) : "";
|
||||
namespaceId = structKeyExists(data, "NamespaceId") ? normStr(data.NamespaceId) : "";
|
||||
instanceId = structKeyExists(data, "InstanceId") ? normStr(data.InstanceId) : "";
|
||||
|
||||
isActive = 1;
|
||||
if (structKeyExists(data, "IsActive")) {
|
||||
if (isBoolean(data.IsActive)) isActive = (data.IsActive ? 1 : 0);
|
||||
else if (isNumeric(data.IsActive)) isActive = int(data.IsActive);
|
||||
else if (isSimpleValue(data.IsActive)) isActive = (lcase(trim(toString(data.IsActive))) EQ "true" ? 1 : 0);
|
||||
}
|
||||
</cfscript>
|
||||
|
||||
<cfif beaconId GT 0>
|
||||
<!--- Update, scoped to this business --->
|
||||
<cfquery datasource="#application.datasource#">
|
||||
UPDATE Beacons
|
||||
SET
|
||||
BeaconName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#beaconName#">,
|
||||
UUID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#uuid#" null="#(len(uuid) EQ 0)#">,
|
||||
NamespaceId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#namespaceId#" null="#(len(namespaceId) EQ 0)#">,
|
||||
InstanceId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#instanceId#" null="#(len(instanceId) EQ 0)#">,
|
||||
IsActive = <cfqueryparam cfsqltype="cf_sql_tinyint" value="#isActive#">
|
||||
WHERE BeaconID = <cfqueryparam cfsqltype="cf_sql_integer" value="#beaconId#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
</cfquery>
|
||||
|
||||
<!--- confirm it exists/belongs to business --->
|
||||
<cfquery name="qCheck" datasource="#application.datasource#">
|
||||
SELECT BeaconID
|
||||
FROM Beacons
|
||||
WHERE BeaconID = <cfqueryparam cfsqltype="cf_sql_integer" value="#beaconId#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
|
||||
<cfif qCheck.recordCount EQ 0>
|
||||
<cfoutput>#serializeJSON({ OK=false, ERROR="not_found" })#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<cfelse>
|
||||
<!--- Insert --->
|
||||
<cfquery datasource="#application.datasource#">
|
||||
INSERT INTO Beacons (
|
||||
BusinessID,
|
||||
BeaconName,
|
||||
UUID,
|
||||
NamespaceId,
|
||||
InstanceId,
|
||||
IsActive
|
||||
) VALUES (
|
||||
<cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_varchar" value="#beaconName#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_varchar" value="#uuid#" null="#(len(uuid) EQ 0)#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_varchar" value="#namespaceId#" null="#(len(namespaceId) EQ 0)#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_varchar" value="#instanceId#" null="#(len(instanceId) EQ 0)#">,
|
||||
<cfqueryparam cfsqltype="cf_sql_tinyint" value="#isActive#">
|
||||
)
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="qId" datasource="#application.datasource#">
|
||||
SELECT LAST_INSERT_ID() AS BeaconID
|
||||
</cfquery>
|
||||
<cfset beaconId = qId.BeaconID>
|
||||
</cfif>
|
||||
|
||||
<!--- Return saved row --->
|
||||
<cfquery name="qOut" datasource="#application.datasource#">
|
||||
SELECT
|
||||
BeaconID,
|
||||
BusinessID,
|
||||
BeaconName,
|
||||
UUID,
|
||||
NamespaceId,
|
||||
InstanceId,
|
||||
IsActive,
|
||||
CreatedAt,
|
||||
UpdatedAt
|
||||
FROM Beacons
|
||||
WHERE BeaconID = <cfqueryparam cfsqltype="cf_sql_integer" value="#beaconId#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
LIMIT 1
|
||||
</cfquery>
|
||||
|
||||
<cfset beacon = {
|
||||
"BeaconID" = qOut.BeaconID,
|
||||
"BusinessID" = qOut.BusinessID,
|
||||
"BeaconName" = qOut.BeaconName,
|
||||
"UUID" = qOut.UUID,
|
||||
"NamespaceId" = qOut.NamespaceId,
|
||||
"InstanceId" = qOut.InstanceId,
|
||||
"IsActive" = qOut.IsActive,
|
||||
"CreatedAt" = qOut.CreatedAt,
|
||||
"UpdatedAt" = qOut.UpdatedAt
|
||||
}>
|
||||
|
||||
<cfoutput>#serializeJSON({ OK=true, ERROR="", BEACON=beacon })#</cfoutput>
|
||||
82
api/servicepoints/list.cfm
Normal file
82
api/servicepoints/list.cfm
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<cfsetting showdebugoutput="false">
|
||||
<cfsetting enablecfoutputonly="true">
|
||||
|
||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfheader name="Cache-Control" value="no-store">
|
||||
|
||||
<cfscript>
|
||||
function apiAbort(obj) {
|
||||
writeOutput(serializeJSON(obj));
|
||||
abort;
|
||||
}
|
||||
|
||||
function readJsonBody() {
|
||||
raw = toString(getHttpRequestData().content);
|
||||
if (isNull(raw) || len(trim(raw)) EQ 0) return {};
|
||||
try {
|
||||
parsed = deserializeJSON(raw);
|
||||
} catch(any e) {
|
||||
apiAbort({ OK=false, ERROR="bad_json", MESSAGE="Invalid JSON body" });
|
||||
}
|
||||
if (!isStruct(parsed)) return {};
|
||||
return parsed;
|
||||
}
|
||||
|
||||
data = readJsonBody();
|
||||
|
||||
if (!structKeyExists(request, "UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="not_logged_in" });
|
||||
}
|
||||
if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) {
|
||||
apiAbort({ OK=false, ERROR="no_business_selected" });
|
||||
}
|
||||
|
||||
onlyActive = true;
|
||||
if (structKeyExists(data, "onlyActive")) {
|
||||
if (isBoolean(data.onlyActive)) {
|
||||
onlyActive = data.onlyActive;
|
||||
} else if (isNumeric(data.onlyActive)) {
|
||||
onlyActive = (int(data.onlyActive) EQ 1);
|
||||
} else if (isSimpleValue(data.onlyActive)) {
|
||||
onlyActive = (lcase(trim(toString(data.onlyActive))) EQ "true");
|
||||
}
|
||||
}
|
||||
</cfscript>
|
||||
|
||||
<cfquery name="q" datasource="#application.datasource#">
|
||||
SELECT
|
||||
ServicePointID,
|
||||
BusinessID,
|
||||
ServicePointName,
|
||||
ServicePointTypeID,
|
||||
ServicePointCode,
|
||||
Description,
|
||||
SortOrder,
|
||||
IsActive,
|
||||
CreatedAt,
|
||||
UpdatedAt
|
||||
FROM ServicePoints
|
||||
WHERE BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
<cfif onlyActive>
|
||||
AND IsActive = 1
|
||||
</cfif>
|
||||
ORDER BY SortOrder, ServicePointName, ServicePointID
|
||||
</cfquery>
|
||||
|
||||
<cfset sps = []>
|
||||
<cfloop query="q">
|
||||
<cfset arrayAppend(sps, {
|
||||
"ServicePointID"=q.ServicePointID,
|
||||
"BusinessID"=q.BusinessID,
|
||||
"ServicePointName"=q.ServicePointName,
|
||||
"ServicePointTypeID"=q.ServicePointTypeID,
|
||||
"ServicePointCode"=q.ServicePointCode,
|
||||
"Description"=q.Description,
|
||||
"SortOrder"=q.SortOrder,
|
||||
"IsActive"=q.IsActive,
|
||||
"CreatedAt"=(q.CreatedAt & ""),
|
||||
"UpdatedAt"=(q.UpdatedAt & "")
|
||||
})>
|
||||
</cfloop>
|
||||
|
||||
<cfoutput>#serializeJSON({ OK=true, ERROR="", BUSINESSID=(request.BusinessID & ""), COUNT=arrayLen(sps), SERVICEPOINTS=sps })#</cfoutput>
|
||||
BIN
apple-touch-icon.png
Normal file
BIN
apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
262
cfpayment/_process.cfm
Normal file
262
cfpayment/_process.cfm
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
|
||||
<cftry>
|
||||
<!--- create a config that is not in svn --->
|
||||
<cfscript>
|
||||
cfg = { path = "cfpayment.api.gateway.stripe.stripe", TestSecretKey = "sk_test_LfbmDduJxTwbVZmvcByYmirw" };
|
||||
svc = createObject("component", "cfpayment.api.core").init(cfg);
|
||||
</cfscript>
|
||||
<cfcatch>
|
||||
<!--- if gwParams doesn't exist (or otherwise bombs), create a generic structure with blank values --->
|
||||
<cfset gwParams = StructNew() />
|
||||
<cfset gwParams.Path = "bogus.gateway" />
|
||||
<!--- these following params aren't needed for the bogus gateway, but should normally be filled in --->
|
||||
<cfset gwParams.MerchantAccount = "" />
|
||||
<cfset gwParams.userName = "" />
|
||||
<cfset gwParams.password = "" />
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<!--- create gw and get reference --->
|
||||
<cfset gw = svc.getGateway() />
|
||||
<cfset creditcard = svc.createCreditCard()>
|
||||
<cfset money = svc.createMoney()>
|
||||
<cfset errors=ArrayNew(1)>
|
||||
<cftry>
|
||||
<!--- Initialize Form Variables --->
|
||||
<cfparam name="form.BillingFirstName" default="">
|
||||
<cfparam name="form.BillingLastName" default="">
|
||||
<cfparam name="form.BillingAddressOne" default="">
|
||||
<cfparam name="form.BillingCity" default="">
|
||||
<cfparam name="form.BillingState" default="">
|
||||
<cfparam name="form.BillingZip" default="">
|
||||
<cfparam name="form.BillingCountry" default="">
|
||||
<cfparam name="form.BillingPhoneNumber" default="">
|
||||
<cfparam name="form.BillingEmailAddress" default="">
|
||||
|
||||
<cfparam name="form.Amount" default="">
|
||||
<cfparam name="form.CardNumber" default="">
|
||||
<cfparam name="form.CardType" default="">
|
||||
<cfparam name="form.ExpirationMonth" default="">
|
||||
<cfparam name="form.ExpirationYear" default="">
|
||||
<cfparam name="form.TransactionType" default="SALE">
|
||||
<cfparam name="form.cvv2" default="">
|
||||
|
||||
<cfif structKeyExists(form, "submitBtn")>
|
||||
<!--- PROCESS --->
|
||||
<cftry>
|
||||
<!--- populate credit card object with passed data --->
|
||||
<cfset ccObjList="Account,Month,Year,VerificationValue,FirstName,LastName,Address,PostalCode">
|
||||
<cfset formFieldList="CardNumber,ExpirationMonth,ExpirationYear,cvv2,BillingFirstName,BillingLastName,BillingAddressOne,BillingZip">
|
||||
<cfset numFields=ListLen(ccObjList)>
|
||||
<cfloop from="1" to="#numFields#" index="idx">
|
||||
<cfset currCCField=ListGetAt(ccObjList, idx)>
|
||||
<cfset currFormField=ListGetAt(formFieldList, idx)>
|
||||
<cfinvoke component="#creditcard#" method="set#currCCField#">
|
||||
<cfinvokeargument name="#currCCField#" value="#form[currFormField]#" />
|
||||
</cfinvoke>
|
||||
</cfloop>
|
||||
<!--- validate credit card --->
|
||||
<cfset errors=creditCard.validate()>
|
||||
<cfif not ArrayLen(errors)>
|
||||
|
||||
<!--- gateway specific parameters --->
|
||||
<!--- for example, the skipjack gateway requires email, phonenumber and ordernumber; these are passed in the options struct --->
|
||||
<cfset options=StructNew()>
|
||||
<cfset options.address=StructNew()>
|
||||
<cfset options.email=form.BillingEmailAddress>
|
||||
<!--- send through generic address structure --->
|
||||
<cfset options.address.phone=form.BillingPhoneNumber>
|
||||
<cfset options.address.Address1=form.BillingAddressOne>
|
||||
<cfset options.address.City=form.BillingCity>
|
||||
<cfset options.address.State=form.BillingState>
|
||||
<cfset options.address.PostalCode=form.BillingZip>
|
||||
<cfset options.address.Country=form.BillingCountry>
|
||||
<cfset options.order_id="1234ORDER">
|
||||
|
||||
<!--- setup the money object with the amount --->
|
||||
<cfset money.init(form.amount * 100)><!--- in cents --->
|
||||
|
||||
<!--- send authorize command --->
|
||||
<!--- pass in the money object, the creditcard object, extra parameters required by the specific gateway --->
|
||||
<cfset authResponse=gw.purchase(money, creditCard)>
|
||||
|
||||
<!--- process response --->
|
||||
|
||||
<cfif authResponse.getSuccess()>
|
||||
<cfoutput>The credit card payment was successfully processed. </cfoutput>
|
||||
<!--- TODO: you should now do something (record, redirect, etc.) --->
|
||||
|
||||
<!--- <cfdump var="#deserializeJSON(authResponse.getResult())#" label="getResult">
|
||||
<cfdump var="#authResponse.getParsedResult()#" label="getParsedResult">
|
||||
<cfif isdefined("arguments")><cfdump var="#arguments#" label="Arguments Scope"></cfif>
|
||||
<cfif isdefined("attributes")><cfdump var="#attributes#" label="Attributes Scope"></cfif>
|
||||
<cfif isdefined("CGI")><cfdump var="#CGI#" label="CGI Scope"></cfif>
|
||||
<cfif isdefined("Request")><cfdump var="#Request#" label="Request Scope"></cfif>
|
||||
<cfif isdefined("URL")><cfdump var="#URL#" label="URL Scope"></cfif>
|
||||
<cfif isdefined("Form")><cfdump var="#Form#" label="Form Scope"></cfif>
|
||||
<cfif isdefined("session")><cfdump var="#Session#" label="Session Scope"></cfif> --->
|
||||
|
||||
<!--- do the rest of the stuff --->
|
||||
|
||||
<cfset cart_total = 0>
|
||||
|
||||
<CFQUERY name="get_queued_food" datasource="#application.datasource#" dbtype="ODBC">
|
||||
SELECT A.CartID, A.AddedOn, A.Quantity, A.SpecialRemark, B.BusinessName, B.UserID, C.ItemName, A.Price, D.UserFirstName, D.LaerFirstName, D.Balance
|
||||
FROM dbo.Business_CartMaster A, dbo.BusinessMaster B, dbo.Business_ItemMaster C, Users D
|
||||
WHERE A.UserID = D.UserID
|
||||
AND
|
||||
A.ItemID = C.ItemID
|
||||
AND
|
||||
B.BusinessID = C.BusinessID
|
||||
AND
|
||||
C.BusinessID = #form.bizid#
|
||||
AND
|
||||
A.CartStatusID = 1
|
||||
AND
|
||||
A.UserID = #session.UserID#
|
||||
ORDER BY A.AddedOn DESC
|
||||
</CFQUERY>
|
||||
|
||||
<cfoutput query="get_queued_food">
|
||||
|
||||
<cfif len(get_queued_food.Price) EQ 0><cfset get_queued_food.Price=0></cfif>
|
||||
|
||||
<cfset cart_total = (cart_total + (get_queued_food.price*get_queued_food.quantity))>
|
||||
|
||||
<CFQUERY name="update_cart_items" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE dbo.Business_CartMaster
|
||||
SET CartStatusID=2
|
||||
WHERE CartID=#get_queued_food.CartID#
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="Insert_order" datasource="#application.datasource#" dbtype="ODBC">
|
||||
INSERT Into dbo.Business_OrderMaster (
|
||||
UserID,
|
||||
BusinessID,
|
||||
IsDelivery,
|
||||
TotalAmount,
|
||||
Address,
|
||||
DeliveryCharge,
|
||||
TaxChargeAmount,
|
||||
AddedOn
|
||||
)
|
||||
values (
|
||||
#session.UserID#,
|
||||
#form.bizid#,
|
||||
0,
|
||||
#cart_total#,
|
||||
'',
|
||||
0,
|
||||
0,
|
||||
#CreateODBCDateTime(now())#
|
||||
);
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="get_last_inserted" datasource="#application.datasource#" dbtype="ODBC">
|
||||
SELECT TOP 1 O.OrderID, M.UserID as person_to_pay_for_orderID
|
||||
FROM dbo.Business_OrderMaster O, dbo.BusinessMaster M
|
||||
WHERE O.BusinessID = M.BusinessID
|
||||
ORDER BY O.AddedOn DESC
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="link_order" datasource="#application.datasource#" dbtype="ODBC">
|
||||
INSERT INTO dbo.Business_OrderCartTransaction (
|
||||
OrderID,
|
||||
CartID
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#get_last_inserted.OrderID#,
|
||||
#get_queued_food.CartID#
|
||||
)
|
||||
</CFQUERY>
|
||||
|
||||
</cfoutput>
|
||||
|
||||
<cfif cart_total < 10>
|
||||
<cfset admin_fees_calculated = cart_total * .022>
|
||||
<cfelse>
|
||||
<cfset admin_fees_calculated = cart_total * .005 +.22>
|
||||
</cfif>
|
||||
|
||||
<CFQUERY name="insert_payment" datasource="#application.datasource#" dbtype="ODBC">
|
||||
INSERT INTO dbo.PaymentMaster (
|
||||
ReceiverID,
|
||||
PayUserID,
|
||||
BusinessID,
|
||||
Amount,
|
||||
AdminFees,
|
||||
PayUserRemark,
|
||||
SystemRemark,
|
||||
AddedOn,
|
||||
CartID
|
||||
)
|
||||
VALUES (
|
||||
#get_last_inserted.person_to_pay_for_orderID#,
|
||||
#session.UserID#,
|
||||
#form.bizid#,
|
||||
#cart_total-admin_fees_calculated#,
|
||||
#admin_fees_calculated#,
|
||||
'',
|
||||
'',
|
||||
#createODBCDateTime(now())#,
|
||||
#get_queued_food.CartID#
|
||||
)
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="delete_item_cost" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE Users
|
||||
SET balance = #check_user.balance-cart_total#
|
||||
WHERE UserID = #session.UserID#
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="transfer_money_to_business_creators_UserID" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE Users
|
||||
SET balance = #check_user.balance+(cart_total-admin_fees_calculated)#
|
||||
WHERE UserID = #get_last_inserted.person_to_pay_for_orderID#
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="transfer_fees_to_UserID_104" datasource="#application.datasource#" dbtype="ODBC">
|
||||
UPDATE Users
|
||||
SET balance = #check_user.balance+admin_fees_calculated#
|
||||
WHERE UserID = 104
|
||||
</CFQUERY>
|
||||
|
||||
<div align="center">Order Complete!<br><br><a href="index.cfm">Reload</a> for new balance<br><br>
|
||||
|
||||
<!--- end do the rest of the stuff --->
|
||||
|
||||
<cfelse>
|
||||
<!--- add the gateway errors to any existing errors we are tracking (eg. creditcard object errors) --->
|
||||
<cfset ArrayAppend(errors, authResponse.getMessage())>
|
||||
</cfif>
|
||||
</cfif>
|
||||
<!--- if we get here, there were errors --->
|
||||
<!--- <cfdump var="#errors.getErrors()#"> --->
|
||||
<cfcatch type="cfpayment">
|
||||
|
||||
<!--- <cfdump var="#cfcatch#"><cfabort> --->
|
||||
<cfset ArrayAppend(errors, cfcatch.message)>
|
||||
</cfcatch>
|
||||
<cfcatch>
|
||||
|
||||
<!--- <cfdump var="#cfcatch#"><cfabort> --->
|
||||
<cfset ArrayAppend(errors, cfcatch.message)>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
</cfif>
|
||||
|
||||
<cfcatch>
|
||||
<cfoutput>Initialization Error - Credit Card Payment Form</cfoutput>
|
||||
<!--- TODO: this should be e-mailed or logged somewhere --->
|
||||
<cfdump var="#CFCatch#" label="CFCatch Scope">
|
||||
<cfif isdefined("arguments")><cfdump var="#arguments#" label="Arguments Scope"></cfif>
|
||||
<cfif isdefined("attributes")><cfdump var="#attributes#" label="Attributes Scope"></cfif>
|
||||
<cfif isdefined("CGI")><cfdump var="#CGI#" label="CGI Scope"></cfif>
|
||||
<cfif isdefined("Request")><cfdump var="#Request#" label="Request Scope"></cfif>
|
||||
<cfif isdefined("URL")><cfdump var="#URL#" label="URL Scope"></cfif>
|
||||
<cfif isdefined("Form")><cfdump var="#Form#" label="Form Scope"></cfif>
|
||||
<cfif isdefined("session")><cfdump var="#Session#" label="Session Scope"></cfif>
|
||||
<cfabort>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
135
cfpayment/api/core.cfc
Normal file
135
cfpayment/api/core.cfc
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2007 Brian Ghidinelli (http://www.ghidinelli.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 name="core" output="false" displayname="CFPAYMENT Core" hint="The core API for CFPAYMENT">
|
||||
|
||||
<!---
|
||||
NOTES:
|
||||
* This is the main object that will be invoked
|
||||
* Create the object and init() it with a configuration object
|
||||
|
||||
USAGE:
|
||||
requires a configuration object that looks like:
|
||||
|
||||
.path (REQUIRED, to gateway cfc, could be "itransact.itransact_cc" or "bogus.gateway")
|
||||
.id (a unique id you give your gateways. If only ever have one, use 1)
|
||||
.mid (merchant account number)
|
||||
.username
|
||||
.password
|
||||
...
|
||||
(these are arbitrary keys passed to the gateway on init so if not using l/p, pass here)
|
||||
|
||||
--->
|
||||
|
||||
<!--- pseudo-constructor --->
|
||||
<cfset variables.instance = structNew() />
|
||||
<cfset variables.instance.VERSION = "@VERSION@" />
|
||||
|
||||
|
||||
<cffunction name="init" output="false" access="public" returntype="any" hint="Initialize the core API and return a reference to it">
|
||||
<cfargument name="config" type="struct" required="true" />
|
||||
|
||||
<cfset variables.instance.config = arguments.config />
|
||||
|
||||
<!--- the core service expects a structure of configuration information to be passed to it
|
||||
telling it what gateway to use and so forth --->
|
||||
<cftry>
|
||||
<!--- instantiate gateway and initialize it with the passed configuration --->
|
||||
<cfset variables.instance.gateway = createObject("component", variables.instance.config.path).init(config = variables.instance.config, service = this) />
|
||||
|
||||
<cfcatch type="template">
|
||||
<!--- these are errors in the gateway itself, need to bubble them up for debugging --->
|
||||
<cfrethrow />
|
||||
</cfcatch>
|
||||
<cfcatch type="application">
|
||||
<cfthrow message="Invalid Gateway Specified: #variables.instance.config.path#" type="cfpayment.InvalidGateway" />
|
||||
</cfcatch>
|
||||
<cfcatch type="any">
|
||||
<cfrethrow />
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- PUBLIC METHODS --->
|
||||
|
||||
<cffunction name="getGateway" access="public" output="false" returntype="any" hint="return the gateway or throw an error">
|
||||
<cfreturn variables.instance.gateway />
|
||||
</cffunction>
|
||||
|
||||
<!--- getters and setters --->
|
||||
<cffunction name="getVersion" access="public" output="false" returntype="string">
|
||||
<cfif isNumeric(variables.instance.version)>
|
||||
<cfreturn variables.instance.version />
|
||||
<cfelse>
|
||||
<cfreturn "SVN" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createCreditCard" output="false" access="public" returntype="any" hint="return a credit card object for population">
|
||||
<cfreturn createObject("component", "model.creditcard").init(argumentCollection = arguments) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createEFT" output="false" access="public" returntype="any" hint="create an electronic funds transfer (EFT) object for population">
|
||||
<cfreturn createObject("component", "model.eft").init(argumentCollection = arguments) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createOAuth" output="false" access="public" returntype="any" hint="create a representation for OAuth credentials to perform actions on behalf of someone">
|
||||
<cfreturn createObject("component", "model.oauth").init(argumentCollection = arguments) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createToken" output="false" access="public" returntype="any" hint="create a remote storage token for population">
|
||||
<cfreturn createObject("component", "model.token").init(argumentCollection = arguments) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createMoney" output="false" access="public" returntype="any" hint="Create a money component for amount and currency conversion and formatting">
|
||||
<cfreturn createObject("component", "model.money").init(argumentCollection = arguments) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getAccountType" output="false" access="public" returntype="any">
|
||||
<cfargument name="Account" type="any" required="true" />
|
||||
<cfreturn lcase(listLast(getMetaData(arguments.account).fullname, ".")) />
|
||||
</cffunction>
|
||||
|
||||
<!--- statuses to determine success and failure --->
|
||||
<cffunction name="getStatusUnprocessed" output="false" access="public" returntype="any" hint="This status is used to denote the transaction wasn't performed">
|
||||
<cfreturn -1 />
|
||||
</cffunction>
|
||||
<cffunction name="getStatusSuccessful" output="false" access="public" returntype="any" hint="This status indicates success">
|
||||
<cfreturn 0 />
|
||||
</cffunction>
|
||||
<cffunction name="getStatusPending" output="false" access="public" returntype="any" hint="This status indicates when we have sent a request to the gateway and are awaiting response (Transaction API or delayed settlement like ACH)">
|
||||
<cfreturn 1 />
|
||||
</cffunction>
|
||||
<cffunction name="getStatusDeclined" output="false" access="public" returntype="any" hint="This status indicates a declined transaction">
|
||||
<cfreturn 2 />
|
||||
</cffunction>
|
||||
<cffunction name="getStatusFailure" output="false" access="public" returntype="any" hint="This status indicates something went wrong like the gateway threw an error but we believe the transaction was not processed">
|
||||
<cfreturn 3 />
|
||||
</cffunction>
|
||||
<cffunction name="getStatusTimeout" output="false" access="public" returntype="any" hint="This status indicates the remote server doesn't answer meaning we don't know if transaction was processed">
|
||||
<cfreturn 4 />
|
||||
</cffunction>
|
||||
<cffunction name="getStatusUnknown" output="false" access="public" returntype="any" hint="This status indicates an exception we don't know how to handle (yet)">
|
||||
<cfreturn 99 />
|
||||
</cffunction>
|
||||
<cffunction name="getStatusErrors" output="false" access="public" returntype="any" hint="This defines which statuses are errors">
|
||||
<cfreturn "3,4,99" />
|
||||
</cffunction>
|
||||
</cfcomponent>
|
||||
535
cfpayment/api/encryption/asymmetric/asymmetric.cfc
Normal file
535
cfpayment/api/encryption/asymmetric/asymmetric.cfc
Normal file
|
|
@ -0,0 +1,535 @@
|
|||
<!-----------------------------------------------------------------------------
|
||||
|
||||
Component Name: Cryptography.
|
||||
Description: This component handles all the functionalities
|
||||
related to cryptography.
|
||||
|
||||
Author: Mindfire Solutions (contracted by Brian Ghidinelli)
|
||||
Create Date: 25th June 2007
|
||||
Copyright: Copyright (c) 2007 Brian Ghidinelli (http://www.ghidinelli.com)
|
||||
|
||||
------------------------------------------------------------------------------>
|
||||
<cfcomponent name="cryptoService"
|
||||
displayname="Cryptography Component"
|
||||
hint="I contain all functionalities related to cryptography">
|
||||
|
||||
<!---------------------------------------------------------------------------
|
||||
|
||||
Name: init
|
||||
|
||||
Arguments:
|
||||
1. keyStoreFile [ Type:String Required:Yes ]
|
||||
- The keystore filename with physical path which is to be initialized
|
||||
|
||||
Returns:
|
||||
Nothing.
|
||||
|
||||
Description:
|
||||
Initializes a specified keystore file. Creates a new one, if specified
|
||||
keystore file is not present and initializes to the new keystore.
|
||||
|
||||
---------------------------------------------------------------------------->
|
||||
<cffunction name="init"
|
||||
access="public"
|
||||
displayname="Init Key Store"
|
||||
returntype="void"
|
||||
output="false">
|
||||
<cfargument name="keyStoreFile"
|
||||
displayname="Key Store File "
|
||||
type="string"
|
||||
required="yes">
|
||||
<cfargument name="passPhrase"
|
||||
displayname="Pass Phrase "
|
||||
type="string"
|
||||
required="no">
|
||||
|
||||
|
||||
<!--- Initialization of local variables. --->
|
||||
<cfset var objCrypto = 0>
|
||||
|
||||
<!--- Create the java object and initialize by calling its constructor. --->
|
||||
<cfset objCrypto = CreateObject("java", "java.Cryptography")>
|
||||
<cfset objCrypto.Init()>
|
||||
|
||||
<cftry>
|
||||
|
||||
<cfif not FileExists(keyStoreFile) and Len(passPhrase) eq 0>
|
||||
|
||||
<cfset displayError("Invalid Arguments","Password is not provided and KeyStore doesn't exist")>
|
||||
|
||||
<cfelseif not FileExists(keyStoreFile) and Len(passPhrase) gt 0>
|
||||
|
||||
<cfset objCrypto.keyStoreGenerator(keyStoreFile,passPhrase )>
|
||||
<cfset objCrypto.Init(keyStoreFile)>
|
||||
|
||||
<cfelse>
|
||||
|
||||
<cfset objCrypto.Init(keyStoreFile)>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfset displayError(cfcatch.Type,cfcatch.Message)>
|
||||
</cfcatch>
|
||||
|
||||
</cftry>
|
||||
|
||||
<cfset variables.objCrypto = objCrypto>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<!---------------------------------------------------------------------------
|
||||
|
||||
Name: encryptData
|
||||
|
||||
Arguments:
|
||||
1. data [ Type:String Required:Yes ]
|
||||
- Data to be encrypted.
|
||||
|
||||
2. publicKey [ Type:Struct Required:Yes ]
|
||||
- Structure containing public key data to be used for encryption.
|
||||
|
||||
|
||||
Returns:
|
||||
The encrypted Data.
|
||||
[ Type:String ]
|
||||
|
||||
Description:
|
||||
Encrypts the specified data using the specified public key.
|
||||
|
||||
---------------------------------------------------------------------------->
|
||||
<cffunction name="encryptData"
|
||||
access="public"
|
||||
displayname="Encrypt Data"
|
||||
returntype="string"
|
||||
output="false">
|
||||
<cfargument name="data"
|
||||
displayname="Data"
|
||||
type="string"
|
||||
required="yes">
|
||||
<cfargument name="publicKey"
|
||||
displayname="Public Key"
|
||||
type="struct"
|
||||
required="yes">
|
||||
|
||||
|
||||
<!--- Initialization of local variables. --->
|
||||
<cfset var encString = "">
|
||||
|
||||
<cftry>
|
||||
|
||||
<cfset encString = variables.objCrypto.encryption(data, publicKey.modulus, publicKey.exponent)>
|
||||
<cfcatch type="any" >
|
||||
<cfset displayError(cfcatch.Type,cfcatch.Message)>
|
||||
</cfcatch>
|
||||
|
||||
</cftry>
|
||||
|
||||
<cfreturn encString>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<!---------------------------------------------------------------------------
|
||||
|
||||
Name: decryptData
|
||||
|
||||
Arguments:
|
||||
1. data [ Type:String Required:Yes ]
|
||||
- Data to be decrypted.
|
||||
|
||||
2. privateKey [ Type:Struct Required:Yes ]
|
||||
- Structure containing private key data to be used for decryption.
|
||||
|
||||
Returns:
|
||||
The decrypted Data.
|
||||
[ Type:String ]
|
||||
|
||||
Description:
|
||||
Decrypts the specified data using the specified private key.
|
||||
|
||||
---------------------------------------------------------------------------->
|
||||
<cffunction name="decryptData"
|
||||
access="public"
|
||||
displayname="Decrypt Data"
|
||||
returntype="String"
|
||||
output="false">
|
||||
<cfargument name="data"
|
||||
displayname="Data"
|
||||
type="string"
|
||||
required="yes">
|
||||
<cfargument name="privateKey"
|
||||
displayname="Private Key"
|
||||
type="struct"
|
||||
required="yes">
|
||||
|
||||
|
||||
<!--- Initialization of local variables. --->
|
||||
<cfset var decString = "">
|
||||
|
||||
<cftry>
|
||||
|
||||
<cfset decString = variables.objCrypto.decryption(data, privateKey.modulus,
|
||||
privateKey.privExponent, privateKey.pubExponent, privateKey.primeP,
|
||||
privateKey.primeQ, privateKey.primeexponentP,
|
||||
privateKey.primeExponentQ, privateKey.crtCoefficient)>
|
||||
|
||||
<cfcatch type="any" >
|
||||
<cfset displayError(cfcatch.Type,cfcatch.Message)>
|
||||
</cfcatch>
|
||||
|
||||
</cftry>
|
||||
|
||||
<cfreturn decString>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<!---------------------------------------------------------------------------
|
||||
|
||||
Name: importKey
|
||||
|
||||
Arguments:
|
||||
1. key [ Type:Structure Required:Yes ]
|
||||
- key which will be added in the KeyStore.It can be Public Key or Private Key .
|
||||
|
||||
2. passPhrase [ Type:String Required:Yes ]
|
||||
- Password of the keystore where key is to be imported.
|
||||
|
||||
3. alias [ Type:String Required:Yes ]
|
||||
- Alias name for the key to be imported.
|
||||
|
||||
Returns:
|
||||
Noting
|
||||
[ Type:Void ]
|
||||
|
||||
Description:
|
||||
Add a key from specified keyfile to the keystore with the specified
|
||||
alias and password.
|
||||
|
||||
---------------------------------------------------------------------------->
|
||||
<cffunction name="importKey"
|
||||
access="public"
|
||||
displayname="Import Key"
|
||||
returntype="Void"
|
||||
output="false">
|
||||
<cfargument name="key"
|
||||
displayname="Key"
|
||||
type="struct"
|
||||
required="yes">
|
||||
<cfargument name="alias"
|
||||
displayname="Alias"
|
||||
type="string"
|
||||
required="yes">
|
||||
<cfargument name="passPhrase"
|
||||
displayname="Pass Phrase"
|
||||
type="string"
|
||||
required="yes">
|
||||
|
||||
|
||||
<cftry>
|
||||
|
||||
<cfif StructCount(key) GT 2>
|
||||
<cfset variables.objCrypto.importKey(alias, passPhrase, key.modulus,
|
||||
key.privExponent, key.pubExponent, key.primeP, key.primeQ,
|
||||
key.primeExponentP, key.primeExponentQ, key.crtCoefficient)>
|
||||
|
||||
<cfelse>
|
||||
|
||||
<cfset variables.objCrypto.importKey
|
||||
(alias, passPhrase, key.modulus, key.exponent)>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfcatch type="any" >
|
||||
<cfset displayError(cfcatch.Type,cfcatch.Message)>
|
||||
</cfcatch>
|
||||
|
||||
</cftry>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<!---------------------------------------------------------------------------
|
||||
|
||||
Name: deleteKey
|
||||
|
||||
Arguments:
|
||||
1. alias [ Type:String Required:Yes ]
|
||||
- Alias name of the key to be deleted.
|
||||
|
||||
2. passPhrase [ Type:String Required:Yes ]
|
||||
- Password of the keystore from which key is to be deleted.
|
||||
|
||||
Returns:
|
||||
Noting
|
||||
[ Type:Void ]
|
||||
|
||||
Description:
|
||||
Deletes a key with the specified alias name.
|
||||
|
||||
---------------------------------------------------------------------------->
|
||||
<cffunction name="deleteKey"
|
||||
access="public"
|
||||
displayname="Delete Key"
|
||||
returntype="Void"
|
||||
output="false">
|
||||
<cfargument name="alias"
|
||||
displayname="Alias"
|
||||
type="string"
|
||||
required="yes">
|
||||
<cfargument name="passPhrase"
|
||||
displayname="Pass Phrase"
|
||||
type="string"
|
||||
required="yes">
|
||||
|
||||
<cftry>
|
||||
|
||||
<cfset variables.objCrypto.deleteKey(alias,passPhrase)>
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfset displayError(cfcatch.Type,cfcatch.Message)>
|
||||
</cfcatch>
|
||||
|
||||
</cftry>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<!---------------------------------------------------------------------------
|
||||
|
||||
Name: listKeys
|
||||
|
||||
Arguments:
|
||||
1. passPhrase [ Type:String Required:Yes ]
|
||||
- Password of the keystore from which key aliases are to be listed.
|
||||
|
||||
Returns:
|
||||
A an array containing a list of key aliases.
|
||||
[ Type:Array ]
|
||||
|
||||
Description:
|
||||
Lists all key aliases from the keystore.
|
||||
|
||||
---------------------------------------------------------------------------->
|
||||
<cffunction name="listKeys"
|
||||
access="public"
|
||||
displayname="Init Key Store"
|
||||
returntype="array"
|
||||
output="false">
|
||||
|
||||
<cfargument name="passPhrase"
|
||||
displayname="Pass Phrase"
|
||||
type="string"
|
||||
required="yes">
|
||||
|
||||
|
||||
<!--- Initialization of local variables. --->
|
||||
<cfset var keyArray = ArrayNew(1)>
|
||||
|
||||
<cftry>
|
||||
|
||||
<cfset keyArray = variables.objCrypto.listKeys(passPhrase)>
|
||||
<cfcatch>
|
||||
<cfset displayError(cfcatch.Type,cfcatch.Message)>
|
||||
</cfcatch>
|
||||
|
||||
</cftry>
|
||||
|
||||
<cfreturn keyArray>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<!---------------------------------------------------------------------------
|
||||
|
||||
Name: getKey
|
||||
|
||||
Arguments:
|
||||
1. alias [ Type:String Required:Yes ]
|
||||
- Alias name of the key to be retrieved.
|
||||
|
||||
2. passPhrase [ Type:String Required:Yes ]
|
||||
- Password of the keystore from which key will be retrieved.
|
||||
|
||||
Returns:
|
||||
The key related to the specified alias name.
|
||||
[ Type:Structure ]
|
||||
|
||||
Description:
|
||||
Gets the key of the specified alias name.
|
||||
|
||||
---------------------------------------------------------------------------->
|
||||
<cffunction name="getKey"
|
||||
access="public"
|
||||
displayname="Get Key"
|
||||
returntype="struct"
|
||||
output="false">
|
||||
<cfargument name="alias"
|
||||
displayname="Alias"
|
||||
type="string"
|
||||
required="yes">
|
||||
<cfargument name="passPhrase"
|
||||
displayname="Pass Phrase"
|
||||
type="string"
|
||||
required="yes">
|
||||
|
||||
|
||||
<!--- Initialization of local variables. --->
|
||||
<cfset var retKey = "" />
|
||||
<cfset var isPublicKey = 0 />
|
||||
<cfset var Key = StructNew() />
|
||||
|
||||
<cftry>
|
||||
|
||||
<cfset retKey = variables.objCrypto.retrieveKey(alias,passPhrase)>
|
||||
<cfset isPublicKey = Find("RSAPublicKey",retKey.getClass().toString())>
|
||||
|
||||
<cfif isPublicKey EQ "0">
|
||||
<!--- Create a Private Key Structure --->
|
||||
<cfset Key.modulus = retKey.getModulus().toString()>
|
||||
<cfset Key.privExponent = retKey.getPrivateExponent().toString()>
|
||||
<cfset Key.pubExponent = retKey.getPublicExponent().toString()>
|
||||
<cfset Key.primeP = retKey.getPrimeP().toString()>
|
||||
<cfset Key.primeQ = retKey.getPrimeQ().toString()>
|
||||
<cfset Key.primeExponentP = retKey.getPrimeExponentP().toString()>
|
||||
<cfset Key.primeExponentQ = retKey.getPrimeExponentQ().toString()>
|
||||
<cfset Key.crtCoefficient = retKey.getCrtCoefficient().toString()>
|
||||
|
||||
<cfelse>
|
||||
<!--- Create a Public Key Structure --->
|
||||
<cfset Key = StructNew()>
|
||||
<cfset Key.modulus = retKey.getModulus().toString()>
|
||||
<cfset Key.exponent = retKey.getPublicExponent().toString()>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfcatch type="any" >
|
||||
<cfset displayError(cfcatch.Type,cfcatch.Message)>
|
||||
</cfcatch>
|
||||
|
||||
</cftry>
|
||||
|
||||
<cfreturn Key>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<!---------------------------------------------------------------------------
|
||||
|
||||
Name: generateKeyPair
|
||||
|
||||
Arguments:
|
||||
1. keySize [ Type:Integer Required:Yes ]
|
||||
- Size of the keyPair to be generated.
|
||||
|
||||
Returns:
|
||||
A structure containing a key pair of private key and public key.
|
||||
[ Type:Struct ]
|
||||
|
||||
Description:
|
||||
Generate a keypair having public key and private key.
|
||||
|
||||
---------------------------------------------------------------------------->
|
||||
<cffunction name="generateKeyPair"
|
||||
access="public"
|
||||
displayname="Generate Key Pair"
|
||||
returntype="struct"
|
||||
output="false">
|
||||
<cfargument name="keySize"
|
||||
displayname="Key Size"
|
||||
type="numeric"
|
||||
required="yes">
|
||||
|
||||
|
||||
<!--- Initialization of local variables. --->
|
||||
<cfset var keyPair = StructNew()>
|
||||
<cfset var key = 0>
|
||||
|
||||
<cfif arguments.keySize gt 2048>
|
||||
<cfset displayError("KeySize Exception","KeySize exceeded than 2048 bits")>
|
||||
<cfelseif arguments.keySize lt 0>
|
||||
<cfset displayError("KeySize Exception","KeySize cannot be negative.")>
|
||||
<cfelse>
|
||||
|
||||
<cftry>
|
||||
|
||||
<cfset key = variables.objCrypto.keyPairGeneration(arguments.keySize)>
|
||||
<cfset keyPair.publicKey = StructNew()>
|
||||
<cfset keyPair.publicKey.modulus = key.getPublic().getModulus().toString()>
|
||||
<cfset keyPair.publicKey.exponent = key.getPublic().getExponent().toString()>
|
||||
|
||||
<cfset keyPair.privateKey = StructNew()>
|
||||
<cfset keyPair.privateKey.modulus = key.getPrivate().getModulus().toString()>
|
||||
<cfset keyPair.privateKey.privExponent = key.getPrivate().getExponent().toString()>
|
||||
<cfset keyPair.privateKey.pubExponent = key.getPrivate().getPublicExponent().toString()>
|
||||
<cfset keyPair.privateKey.primeExponentP = key.getPrivate().getDP().toString()>
|
||||
<cfset keyPair.privateKey.primeExponentQ = key.getPrivate().getDQ().toString()>
|
||||
<cfset keyPair.privateKey.primeP = key.getPrivate().getP().toString()>
|
||||
<cfset keyPair.privateKey.primeQ = key.getPrivate().getQ().toString()>
|
||||
<cfset keyPair.privateKey.crtCoefficient = key.getPrivate().getQInv().toString()>
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfset displayError(cfcatch.Type,cfcatch.Message)>
|
||||
</cfcatch>
|
||||
|
||||
</cftry>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn keyPair>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<!---------------------------------------------------------------------------
|
||||
|
||||
Name: displayError
|
||||
|
||||
Arguments:
|
||||
1. errorType [ Type:String Required:Yes ]
|
||||
- Type of exception to be generated.
|
||||
2. errorMessage [Type:String Required:Yes]
|
||||
- Message for the exception
|
||||
|
||||
Returns:
|
||||
A string containing a type of exception and details about the exception.
|
||||
[ Type:String ]
|
||||
|
||||
Description:
|
||||
Display exception of particular type and corresponding message.
|
||||
|
||||
---------------------------------------------------------------------------->
|
||||
<cffunction name="displayError"
|
||||
access="public"
|
||||
displayname="Display Error"
|
||||
returntype="struct"
|
||||
output="true">
|
||||
<cfargument name="errorType"
|
||||
displayname="Error Type"
|
||||
type="string"
|
||||
required="yes">
|
||||
<cfargument name="errorMessage"
|
||||
displayname="Error Message"
|
||||
type="string"
|
||||
required="yes">
|
||||
|
||||
<cfoutput>
|
||||
|
||||
<table cellpadding="2" style="font-family:Verdana;width:80%;color:##666666;
|
||||
border-top:##CCCCCC solid 1px;
|
||||
border-bottom:##999999 solid 1px;
|
||||
border-right:##CCCCCC solid 1px;
|
||||
border-left:##999999 solid 1px;">
|
||||
<tr style="background-color:##cccccc;font-size:16px;">
|
||||
<td colspan="2"><b>Error</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-size:14px;">Type:</td>
|
||||
<td style="font-size:12px;">#errorType#</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-size:14px;">Message:</td>
|
||||
<td style="font-size:12px;">#errorMessage#</td>
|
||||
</tr>
|
||||
</table>
|
||||
</cfoutput>
|
||||
<cfabort>
|
||||
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
38
cfpayment/api/encryption/asymmetric/build.xml
Normal file
38
cfpayment/api/encryption/asymmetric/build.xml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0"?>
|
||||
<project name="Crptography" default="archive">
|
||||
<description>
|
||||
Compiles and create jar files for Cryptography application
|
||||
</description>
|
||||
|
||||
<property name="src" location="java/"/>
|
||||
<property name="dist" location="dist/"/>
|
||||
<property name="classes" location="build/"/>
|
||||
<property name="bcjar" location="lib/"/>
|
||||
|
||||
|
||||
<target name="init" description="Initializes the project by deleting and creating temporary directories" >
|
||||
<delete dir="${dist}"/>
|
||||
<delete dir="${classes}"/>
|
||||
|
||||
<mkdir dir="${dist}" />
|
||||
<mkdir dir="${classes}" />
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="init" description="Compile the Cryptography files">
|
||||
<javac srcdir="${src}" destdir="${classes}">
|
||||
|
||||
<classpath>
|
||||
<fileset dir="${bcjar}">
|
||||
<include name="*.jar"/>
|
||||
</fileset>
|
||||
</classpath>
|
||||
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="archive" depends="compile" description="create jar files of the compiled classes" >
|
||||
<jar destfile="${dist}/Cryptography.jar" basedir="${classes}" />
|
||||
</target>
|
||||
</project>
|
||||
|
||||
|
||||
52
cfpayment/api/encryption/asymmetric/install.txt
Normal file
52
cfpayment/api/encryption/asymmetric/install.txt
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
ANT Build Tool
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
1.In order to use ANT Tool you have to install Apache ANT Tool in your system.
|
||||
|
||||
2.Download ANT Tool from "http://www.devlib.org/apache/ant/binaries/apache-ant-1.7.0-bin.zip".
|
||||
|
||||
3.Unzip the file and paste it any where you want (For example C:\Ant ).
|
||||
|
||||
4. Set the ANT_HOME and JAVA_HOME environment variables and add them to your PATH.
|
||||
|
||||
|
||||
|
||||
Bouncy Castle Crypto APIs
|
||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
1. Download "bcprov-jdk14-136.jar" "from http://ftp.cica.es/mirrors/maven2/bouncycastle/bcprov-jdk14/136/"
|
||||
|
||||
2. Put the jar file "bcprov-jdk14-136.jar" in "<coldfusion intalled directory>\runtime\jre\lib\ext" directory.
|
||||
|
||||
[ Note: If the jar file is put to any other directory, the Java and JVM Class path needs to be set in the Coldfusion Administrator. The path
|
||||
needs to be the full physical path containing the jar file name. ]
|
||||
|
||||
|
||||
|
||||
Project Setup.
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
1. Put the java file to any desired directory of your project folder. [For example "<project root>\java"].
|
||||
|
||||
2. Put the component cfc file to any desired directory of your project folder. [For example "<project root>\cfc"].
|
||||
|
||||
3. Put the "build.xml" file to any desired path.
|
||||
|
||||
4. Next you need to edit the "build.xml" file with few paths.
|
||||
There are mainly 4 properties whose path needs to be set.
|
||||
|
||||
<property name="src" location="path to source java file"/>
|
||||
<property name="dist" location="destination path for jar file"/>
|
||||
<property name="classes" location="destination path for class file"/>
|
||||
<property name="bcjar" location="path for the bcprov-jdk14-136.jar file"/>
|
||||
|
||||
The location attribute of property "src" needs to be path where the java file is kept. For example "<project root>\java".
|
||||
The location attribute of property "dist" needs to be the destination path where the jar file will be extracted. For example "<project root>\build\jar".
|
||||
The location attribute of property "classes" needs to be the destination path where the class file will be extracted. For example "<project root>\build\classes".
|
||||
The location attribute of property "bcjar" needs to be path where the bcprov-jdk14-136.jar file is kept. For example "<project root>\bouncycastlejar".
|
||||
|
||||
5.Now, in order to run the "build.xml" file go to the directory where "build.xml" file is present using command line and then type "ant" in the command line .
|
||||
And pressing enter would create the required jar and class files in the specified directories.
|
||||
|
||||
6. Set the Java and JVM Class path for the generated jar file in Coldfusion Administrator.
|
||||
|
||||
7. Restart Coldfusion Administrator.
|
||||
|
||||
8. Now the cfc methods can be used.
|
||||
BIN
cfpayment/api/encryption/asymmetric/java/Cryptography.class
Normal file
BIN
cfpayment/api/encryption/asymmetric/java/Cryptography.class
Normal file
Binary file not shown.
BIN
cfpayment/api/encryption/asymmetric/java/Cryptography.jar
Normal file
BIN
cfpayment/api/encryption/asymmetric/java/Cryptography.jar
Normal file
Binary file not shown.
546
cfpayment/api/encryption/asymmetric/java/Cryptography.java
Normal file
546
cfpayment/api/encryption/asymmetric/java/Cryptography.java
Normal file
|
|
@ -0,0 +1,546 @@
|
|||
/***************************************************************************************************
|
||||
|
||||
File Name: Cryptography.java.
|
||||
Author: Mindfire Solutions.
|
||||
Create Date: 25th June 2007.
|
||||
CopyRight: Copyright (c) 2007 Mindfire Solutions, Inc.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java .util.Enumeration;
|
||||
import java.util.Date;
|
||||
import java.security.*;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.Key;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.RSAPrivateCrtKeySpec;
|
||||
import java.security.interfaces.RSAPrivateCrtKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.Certificate;
|
||||
import org.bouncycastle.x509.X509V1CertificateGenerator;
|
||||
import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
|
||||
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
|
||||
import org.bouncycastle.crypto.params.RSAKeyParameters;
|
||||
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
|
||||
import org.bouncycastle.crypto.AsymmetricBlockCipher;
|
||||
import org.bouncycastle.crypto.engines.RSAEngine;
|
||||
import org.bouncycastle.crypto.encodings.PKCS1Encoding;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
|
||||
Class Name:Cryptography
|
||||
|
||||
Description:
|
||||
This class use constructor to initialze KeyStoreName.It handles methods to create a new
|
||||
KeyStore and add or delete Key into KeyStore.It handles methods for generating
|
||||
AsymmetricCipherKeyPair(Public Key and Private Key) using RSA algorithm and use those keys
|
||||
for encrypting given data and deccrypting encrypted data.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
public class Cryptography
|
||||
{
|
||||
private AsymmetricBlockCipher cipher = null;
|
||||
private String keyStoreFileName = null;
|
||||
|
||||
public Cryptography()
|
||||
{
|
||||
/*Empty*/
|
||||
}
|
||||
|
||||
public Cryptography(String keyStoreName)throws Exception
|
||||
{
|
||||
keyStoreFileName = keyStoreName;
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
|
||||
Method Name:keyPairGeneration
|
||||
|
||||
Arguments:
|
||||
1. strength [Type: Integer]
|
||||
- The size, in bits, of the keys we want to produce.
|
||||
|
||||
Return:
|
||||
A KeyPair containing PublicKey and Private Key.
|
||||
[Type: AsymmetricCipherKeyPair Object]
|
||||
|
||||
Description:
|
||||
Gernerate KeyPair of specified size.
|
||||
|
||||
*******************************************************************************************/
|
||||
|
||||
public AsymmetricCipherKeyPair keyPairGeneration(int strength)throws Exception
|
||||
{
|
||||
SecureRandom securerandom = new SecureRandom();
|
||||
BigInteger pubExp = new BigInteger("10001", 16);
|
||||
|
||||
RSAKeyGenerationParameters RSAKeyGenParams = new RSAKeyGenerationParameters
|
||||
(pubExp,securerandom, strength, 80);
|
||||
RSAKeyPairGenerator rsakeygen = new RSAKeyPairGenerator();
|
||||
rsakeygen.init(RSAKeyGenParams);
|
||||
AsymmetricCipherKeyPair keypair = rsakeygen.generateKeyPair();
|
||||
|
||||
return keypair;
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
|
||||
Method Name:encryption
|
||||
|
||||
Arguments:
|
||||
1. input [Type: String]
|
||||
- String to be encrypted.
|
||||
2. modulus [Type: String]
|
||||
- Used to generate RSA Public Key.
|
||||
3. exponent [Type: String]
|
||||
- Used to generate RSA Public Key.
|
||||
|
||||
Return:
|
||||
Encrypted String.
|
||||
[Type: String]
|
||||
|
||||
Description:
|
||||
This method is used to encrypt bytes from a given string and convert the bytes into
|
||||
string.This method uses AsymmetricBlockCipher to perform the encryption.
|
||||
|
||||
*******************************************************************************************/
|
||||
public String encryption(String input, String modulus, String exponent)throws Exception
|
||||
{
|
||||
String encString = null;
|
||||
|
||||
BigInteger intModulus = new BigInteger(modulus);
|
||||
BigInteger intExponent = new BigInteger(exponent);
|
||||
RSAKeyParameters RSApubKey = new RSAKeyParameters(false, intModulus, intExponent);
|
||||
byte[] toEncrypt = input.getBytes();
|
||||
cipher = new PKCS1Encoding(new RSAEngine());
|
||||
cipher.init(true, RSApubKey);
|
||||
byte[] encByte = cipher.processBlock(toEncrypt, 0, toEncrypt.length);
|
||||
byte[] encValue = Hex.encode(encByte);
|
||||
encString = new String(encValue);
|
||||
|
||||
return encString;
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
|
||||
Method Name:decryption
|
||||
|
||||
Arguments:
|
||||
1. input [Type: String]
|
||||
-String to be decrypted.
|
||||
2. modulus [Type: String]
|
||||
- Used to generate RSA Private Key.
|
||||
3. privExponent [Type: String]
|
||||
- Used to generate RSA Private Key.
|
||||
4. pubExponent [Type: String]
|
||||
- Used to generate RSA Private Key.
|
||||
5. primeP [Type: String]
|
||||
- Used to generate RSA Private Key.
|
||||
6. primeQ [Type: String]
|
||||
- Used to generate RSA Private Key.
|
||||
7. primeExponentP [Type: String]
|
||||
- Used to generate RSA Private Key.
|
||||
8. primeExponentQ [Type: String]
|
||||
- Used to generate RSA Private Key.
|
||||
9. crtCoefficient [Type: String]
|
||||
- Used to generate RSA Private Key.
|
||||
|
||||
Return:
|
||||
A Plain Text.
|
||||
[Type: String]
|
||||
|
||||
Description:
|
||||
Method For Decrypting Encrypted String.
|
||||
|
||||
*******************************************************************************************/
|
||||
|
||||
public String decryption(String input,String modulus,String privExponent,String pubExponent,
|
||||
String primeP,String primeQ,String primeExponentP,String primeExponentQ,
|
||||
String crtCoefficient)throws Exception
|
||||
{
|
||||
BigInteger intModulus = new BigInteger(modulus);
|
||||
BigInteger intPrivExponent = new BigInteger(privExponent);
|
||||
BigInteger intPubExponent = new BigInteger(pubExponent);
|
||||
BigInteger intPrimeP = new BigInteger(primeP);
|
||||
BigInteger intPrimeQ = new BigInteger(primeQ);
|
||||
BigInteger intPrimeExponentP = new BigInteger(primeExponentP);
|
||||
BigInteger intPrimeExponentQ = new BigInteger(primeExponentQ);
|
||||
BigInteger intCrtCoefficient = new BigInteger(crtCoefficient);
|
||||
|
||||
RSAPrivateCrtKeyParameters RSAprivKey = new RSAPrivateCrtKeyParameters
|
||||
(intModulus, intPubExponent, intPrivExponent, intPrimeP,
|
||||
intPrimeQ, intPrimeExponentP, intPrimeExponentQ, intCrtCoefficient);
|
||||
byte[] toDecrypt = Hex.decode(input);
|
||||
cipher = new PKCS1Encoding(new RSAEngine());
|
||||
cipher.init(false, RSAprivKey);
|
||||
byte[] decByte = cipher.processBlock(toDecrypt, 0, toDecrypt.length);
|
||||
String decString = new String(decByte);
|
||||
return decString;
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
|
||||
Method Name:keyStoreGenerator
|
||||
|
||||
Arguments :
|
||||
1. keyStorePassword [Type: String]
|
||||
- Password to generate the keystore integrity check.
|
||||
|
||||
Return:
|
||||
Nothing.
|
||||
[Type: Void]
|
||||
|
||||
Description:
|
||||
This method generates an empty KeyStore with specified password using JCEKS.
|
||||
|
||||
*******************************************************************************************/
|
||||
public void keyStoreGenerator(String keyStoreName, String keyStorePassword)throws Exception
|
||||
{
|
||||
FileOutputStream stream = null;
|
||||
|
||||
try
|
||||
{
|
||||
stream= new FileOutputStream(keyStoreName);
|
||||
KeyStore keystore = KeyStore.getInstance( "JCEKS", "SunJCE" );
|
||||
|
||||
//Create empty KeyStore
|
||||
keystore.load(null,null);
|
||||
|
||||
//Save KeyStore
|
||||
keystore.store(stream, keyStorePassword.toCharArray());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.close();
|
||||
} catch (Exception e){}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
|
||||
Method Name:importKey
|
||||
|
||||
Arguments:
|
||||
1. keyAlias [Type: String]
|
||||
- Alias for adding key in the KeyStore.
|
||||
2. keyStorePassword [type: String]
|
||||
- Password of the KeyStore to which key is to be imported.
|
||||
3. modulus [Type: String]
|
||||
- Used to generate a RSAPublicKeySpec.
|
||||
4. publicExponent [Type: String]
|
||||
- Used to generate a RSAPublicKeySpec.
|
||||
|
||||
Return:
|
||||
Nothing.
|
||||
[Type: Void]
|
||||
|
||||
Description :
|
||||
Add a new Public key in the Keystore with spcified key alias.Can not add key if the
|
||||
specified key alias already present in the KeyStore.
|
||||
|
||||
*******************************************************************************************/
|
||||
|
||||
public void importKey(String keyAlias, String keyStorePassword,
|
||||
String modulus, String publicExponent)throws Exception
|
||||
{
|
||||
|
||||
// read keystore file
|
||||
FileInputStream keyStoreFile = new FileInputStream(keyStoreFileName);
|
||||
KeyStore keyStore = KeyStore.getInstance( "JCEKS", "SunJCE" );
|
||||
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
|
||||
|
||||
//check whether specified alias present or not
|
||||
if(keyStore.isKeyEntry(keyAlias))
|
||||
{
|
||||
throw new KeyStoreException("Alias already exist in KeyStore.");
|
||||
}
|
||||
else
|
||||
{
|
||||
BigInteger RSAmod = new BigInteger(modulus);
|
||||
BigInteger RSApubExp = new BigInteger(publicExponent);
|
||||
|
||||
// create RSAPublicKeySpec key spec
|
||||
RSAPublicKeySpec RSAPubSpec =
|
||||
new RSAPublicKeySpec(RSAmod, RSApubExp);
|
||||
|
||||
KeyFactory keyfactory = KeyFactory.getInstance("RSA");
|
||||
RSAPublicKey publicKey = (RSAPublicKey)keyfactory.generatePublic(RSAPubSpec);
|
||||
|
||||
// add the key to the keystore
|
||||
keyStore.setKeyEntry(keyAlias, publicKey, keyStorePassword.toCharArray(), null);
|
||||
|
||||
//save keystore
|
||||
FileOutputStream keyStoreName = new FileOutputStream(keyStoreFileName);
|
||||
keyStore.store(keyStoreName, keyStorePassword.toCharArray());
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
|
||||
Method Name:importKey
|
||||
|
||||
Arguments:
|
||||
1. keyAlias [Type: String]
|
||||
- Alias for adding key in the KeyStore.
|
||||
2. keyStorePassword [type: String]
|
||||
- Password of the KeyStore to which key is to be imported.
|
||||
3. modulus [Type: String]
|
||||
- Used to generate new RSAPrivateCrtKeySpec.
|
||||
4. privExponent [Type: String]
|
||||
- Used to generate new RSAPrivateCrtKeySpec.
|
||||
5. pubExponent [Type: String]
|
||||
- Used to generate RSA Private Key.
|
||||
6. primeP [Type: String]
|
||||
- Used to generate new RSAPrivateCrtKeySpec.
|
||||
7. primeQ [Type: String]
|
||||
- Used to generate new RSAPrivateCrtKeySpec.
|
||||
8. primeExponentP [Type: String]
|
||||
- Used to generate new RSAPrivateCrtKeySpec.
|
||||
9. primeExponentQ [Type: String]
|
||||
- Used to generate new RSAPrivateCrtKeySpec.
|
||||
10. crtCoefficient [Type: String]
|
||||
- Used to generate new RSAPrivateCrtKeySpec.
|
||||
|
||||
Return:
|
||||
Nothing.
|
||||
[Type: Void]
|
||||
|
||||
Description :
|
||||
Add a new Private key in the Keystore with spcified key alias.Can not add key if the
|
||||
specified key alias already present in the KeyStore.
|
||||
|
||||
*******************************************************************************************/
|
||||
public void importKey(String keyAlias, String keyStorePassword, String modulus,
|
||||
String privExponent, String pubExponent,String primeP,
|
||||
String primeQ, String primeExponentP,String primeExponentQ,
|
||||
String crtCoefficient)throws Exception
|
||||
{
|
||||
|
||||
// read keystore file
|
||||
FileInputStream keyStoreFile = new FileInputStream(keyStoreFileName);
|
||||
KeyStore keyStore = KeyStore.getInstance( "JCEKS", "SunJCE" );
|
||||
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
|
||||
|
||||
//check whether specified alias present or not
|
||||
if(keyStore.isKeyEntry(keyAlias))
|
||||
{
|
||||
throw new KeyStoreException("Alias already exist in KeyStore.");
|
||||
}
|
||||
else
|
||||
{
|
||||
BigInteger RSAmod = new BigInteger(modulus);
|
||||
BigInteger RSApubExp = new BigInteger(pubExponent);
|
||||
BigInteger RSAPrivExp = new BigInteger(privExponent);
|
||||
BigInteger RSAp = new BigInteger(primeP);
|
||||
BigInteger RSAq = new BigInteger(primeQ);
|
||||
BigInteger RSADp = new BigInteger(primeExponentP);
|
||||
BigInteger RSADq = new BigInteger(primeExponentQ);
|
||||
BigInteger RSAqInv = new BigInteger(crtCoefficient);
|
||||
|
||||
// create RSAPublicKeySpec key spec using key file
|
||||
RSAPrivateCrtKeySpec RSAPrivSpec =
|
||||
new RSAPrivateCrtKeySpec(RSAmod, RSApubExp,RSAPrivExp,RSAp,RSAq,RSADp,RSADq,RSAqInv);
|
||||
|
||||
KeyFactory keyfactory = KeyFactory.getInstance("RSA");
|
||||
RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey)keyfactory.generatePrivate(RSAPrivSpec);
|
||||
|
||||
Provider newProvider = (java.security.Provider)Class.forName
|
||||
("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance();
|
||||
Security.addProvider(newProvider);
|
||||
|
||||
BigInteger intmod = new BigInteger(modulus);
|
||||
BigInteger intpubExp = new BigInteger(pubExponent);
|
||||
|
||||
// create RSAPublicKeySpec key spec using key file
|
||||
RSAPublicKeySpec RSAPubSpec =
|
||||
new RSAPublicKeySpec(intmod, intpubExp);
|
||||
|
||||
keyfactory = KeyFactory.getInstance("RSA");
|
||||
RSAPublicKey publicKey = (RSAPublicKey)keyfactory.generatePublic(RSAPubSpec);
|
||||
|
||||
// generate the certificate
|
||||
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
|
||||
|
||||
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
|
||||
certGen.setIssuerDN(new X500Principal("CN=Certificate"));
|
||||
certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000));
|
||||
certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000));
|
||||
certGen.setSubjectDN(new X500Principal("CN=Certificate"));
|
||||
certGen.setPublicKey(publicKey);
|
||||
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
|
||||
|
||||
Certificate[] chain = new Certificate[1];
|
||||
chain[0] = certGen.generate(privateKey,"BC");
|
||||
|
||||
|
||||
// add the key to the keystore
|
||||
keyStore.setKeyEntry(keyAlias, privateKey, keyStorePassword.toCharArray(), chain);
|
||||
|
||||
//save keystore
|
||||
FileOutputStream keyStoreName = new FileOutputStream(keyStoreFileName);
|
||||
keyStore.store(keyStoreName, keyStorePassword.toCharArray());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
|
||||
Method Name:retrieveKey
|
||||
|
||||
Arguments:
|
||||
1. keyAlias [Type: String]
|
||||
- Alias for retrieving key from the KeyStore.
|
||||
2. keyStorePassword [Type: String]
|
||||
- Password of the KeyStore from which key is to be retrieved.
|
||||
|
||||
Return:
|
||||
The key related to the specified alias name.
|
||||
[Type: Key]
|
||||
|
||||
Description:
|
||||
This method is used to retrieve Key from KeyStore using alias for that key.
|
||||
|
||||
*******************************************************************************************/
|
||||
public Key retrieveKey(String keyAlias,String keyStorePassword)throws Exception
|
||||
{
|
||||
String retKeyVal = null;
|
||||
Key key = null;
|
||||
|
||||
// read keystore file
|
||||
KeyStore keyStore = KeyStore.getInstance( "JCEKS", "SunJCE" );
|
||||
FileInputStream keyStoreFile = new FileInputStream(keyStoreFileName);
|
||||
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
|
||||
|
||||
|
||||
//check whether specified alias present or not
|
||||
if(keyStore.isKeyEntry(keyAlias))
|
||||
{
|
||||
//get key from keystore
|
||||
key = keyStore.getKey(keyAlias, keyStorePassword.toCharArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new KeyStoreException ("Alias doesn't exist in KeyStore for retrieval.");
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
|
||||
Method Name:deleteKey
|
||||
|
||||
Arguments:
|
||||
1. keyAlias [Type: String]
|
||||
- Alias for deleting key from the KeyStore.
|
||||
2. keyStorePassword [Type: String]
|
||||
- Password of the KeyStore from which key is to be deleted.
|
||||
|
||||
Return:
|
||||
Nothing.
|
||||
[Type: Void]
|
||||
|
||||
Description:
|
||||
Delete a specified key from KeyStore.
|
||||
|
||||
*******************************************************************************************/
|
||||
public void deleteKey(String keyAlias,String keyStorePassword) throws Exception
|
||||
{
|
||||
|
||||
// read KeyStore file
|
||||
KeyStore keyStore = KeyStore.getInstance( "JCEKS", "SunJCE" );
|
||||
FileInputStream keyStoreFile = new FileInputStream(keyStoreFileName);
|
||||
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
|
||||
|
||||
//check whether specified alias present or not
|
||||
if(keyStore.isKeyEntry(keyAlias))
|
||||
{
|
||||
//Delete key from KeyStore
|
||||
keyStore.deleteEntry(keyAlias);
|
||||
|
||||
//save KeyStore
|
||||
FileOutputStream keyStoreName = new FileOutputStream(keyStoreFileName);
|
||||
keyStore.store(keyStoreName, keyStorePassword.toCharArray());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new KeyStoreException("Alias doesn't exist in KeyStore for deletion.");
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
|
||||
Method Name:listKeys
|
||||
|
||||
Argument:
|
||||
1. keyStorePassword [Type: String]
|
||||
- Password of the KeyStore from which all the aliases will be retrieve.
|
||||
|
||||
Return:
|
||||
An array containing all the keyaliases of the KeyStore.
|
||||
[Type: Array]
|
||||
|
||||
Description:
|
||||
Generate an array containg all the alias.
|
||||
|
||||
*******************************************************************************************/
|
||||
public String[] listKeys(String keyStorePassword)throws Exception
|
||||
{
|
||||
String[] aliasArray = null;
|
||||
|
||||
// read KeyStore file
|
||||
KeyStore keyStore = KeyStore.getInstance( "JCEKS", "SunJCE" );
|
||||
FileInputStream keyStoreFile = new FileInputStream(keyStoreFileName);
|
||||
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
|
||||
|
||||
//Get total no. of alias in a KeyStore
|
||||
int totalAlias = keyStore.size();
|
||||
|
||||
if(totalAlias > 0)
|
||||
{
|
||||
|
||||
aliasArray = new String[totalAlias];
|
||||
|
||||
Enumeration enum = keyStore.aliases();
|
||||
while(enum.hasMoreElements())
|
||||
{
|
||||
String alias = enum.nextElement().toString();
|
||||
aliasArray[totalAlias -1] = alias;
|
||||
totalAlias = totalAlias -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new KeyStoreException ("KeyStore is empty. No Alias present.");
|
||||
}
|
||||
|
||||
return aliasArray;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************************
|
||||
|
||||
End of File.
|
||||
|
||||
***************************************************************************************************/
|
||||
BIN
cfpayment/api/encryption/asymmetric/lib/bcprov-jdk14-136.jar
Normal file
BIN
cfpayment/api/encryption/asymmetric/lib/bcprov-jdk14-136.jar
Normal file
Binary file not shown.
24
cfpayment/api/encryption/symmetric.cfc
Normal file
24
cfpayment/api/encryption/symmetric.cfc
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<cfcomponent displayname="Symmetric Encryption Provider" output="false" hint="Provides encryption and decryption services for CFPAYMENT transactions">
|
||||
|
||||
<cffunction name="init" access="public" output="false" returntype="any">
|
||||
<cfargument name="key" type="string" required="true" />
|
||||
|
||||
<cfset variables.instance = structNew() />
|
||||
<cfset variables.instance.key = arguments.key />
|
||||
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="encryptData" access="public" output="false" returntype="any">
|
||||
<cfargument name="data" type="any" required="true" />
|
||||
|
||||
<cfreturn encrypt(arguments.data, variables.instance.key, "AES") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="decryptData" access="public" output="false" returntype="any">
|
||||
<cfargument name="data" type="any" required="true" />
|
||||
|
||||
<cfreturn decrypt(arguments.data, variables.instance.key, "AES") />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
450
cfpayment/api/gateway/authorizenet/AuthorizenetXMLRequest.cfc
Normal file
450
cfpayment/api/gateway/authorizenet/AuthorizenetXMLRequest.cfc
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
<!---
|
||||
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
Helper class to genrate all the XML that is required to send to the of the authorize.net API.
|
||||
|
||||
http://developer.authorize.net/api/reference/index.html
|
||||
|
||||
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>
|
||||
<cfset variables.validTransactions = "authCaptureTransaction,authOnlyTransaction,priorAuthCaptureTransaction,refundTransaction,voidTransaction">
|
||||
|
||||
<cfset variables.validCustomerRequestTypes = "createCustomerProfileRequest,getCustomerProfileRequest,getCustomerProfileIdsRequest,updateCustomerProfileRequest,deleteCustomerProfileRequest,createCustomerPaymentProfileRequest,getCustomerPaymentProfileRequest,getCustomerPaymentProfileListRequest,validateCustomerPaymentProfileRequest,updateCustomerPaymentProfileRequest,deleteCustomerPaymentProfileRequest">
|
||||
|
||||
|
||||
<cfset variables.testmode = true>
|
||||
|
||||
<cffunction name="init">
|
||||
<cfargument name="testMode" required="true" type="boolean">
|
||||
<cfset variables.testmode = arguments.testmode>
|
||||
<cfreturn this>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createTransactionRequest" returntype="xml" hint="Main entry point for generating all the xml">
|
||||
<cfargument name="transactionType">
|
||||
<cfargument name="merchantAuthentication" hint="The merchant ids">
|
||||
<cfargument name="money" hint="The amount to that we want to debit">
|
||||
<cfargument name="account" hint="The account (i.e. card)">
|
||||
<cfargument name="customer" hint="A stored customer">
|
||||
<cfargument name="paymentProfile" hint="The customer's payment profile">
|
||||
<cfargument name="options" hint="other details about the transaction such as refId">
|
||||
|
||||
|
||||
<cfif !isValidTransactionType(transactionType)>
|
||||
<cfthrow type="cfpayment.UnknownTransactionType" message="transactionType, #transactionType# is not known">
|
||||
</cfif>
|
||||
|
||||
<cfif transactionType EQ "priorAuthCaptureTransaction" && NOT structKeyExists(options, "refTransId")>
|
||||
<cfthrow type="cfpayment.RequiredOptionMissing" message="transactionType, #transactionType# requires a refTransId in the options">
|
||||
</cfif>
|
||||
|
||||
|
||||
|
||||
<cfxml variable="local.xml">
|
||||
<cfoutput>
|
||||
|
||||
<createTransactionRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
|
||||
<merchantAuthentication>
|
||||
<name>#merchantAuthentication.name#</name>
|
||||
<transactionKey>#merchantAuthentication.transactionKey#</transactionKey>
|
||||
</merchantAuthentication>
|
||||
<cfif structKeyExists(options, "refId")>
|
||||
<refId>#options.refId#</refId>
|
||||
</cfif>
|
||||
|
||||
<transactionRequest>
|
||||
<transactionType>#transactionType#</transactionType>
|
||||
<cfif structKeyExists(arguments, "money") && !isNull(money)>
|
||||
<amount>#money.getAmount()#</amount>
|
||||
</cfif>
|
||||
|
||||
|
||||
<cfif !isNull(customer)>
|
||||
<profile>
|
||||
<customerProfileId>#customer.getCustomerProfileId()#</customerProfileId>
|
||||
|
||||
<cfif !isNull(paymentProfile)>
|
||||
<paymentProfile>
|
||||
<paymentProfileId>#paymentProfile.getCustomerPaymentProfileId()#</paymentProfileId>
|
||||
</paymentProfile>
|
||||
</cfif>
|
||||
</profile>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(options, "refTransId")>
|
||||
<refTransId>#options.refTransId#</refTransId>
|
||||
</cfif>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<cfif !IsNull(account) >
|
||||
<payment>
|
||||
<creditCard>
|
||||
<cardNumber>#account.getAccount()#</cardNumber>
|
||||
<expirationDate>#DateFormat(account.getExpirationDate(), "MM/YY")#</expirationDate>
|
||||
<cardCode>#account.getVerificationValue()#</cardCode>
|
||||
</creditCard>
|
||||
</payment>
|
||||
</cfif>
|
||||
|
||||
|
||||
|
||||
<cfif structKeyExists(options, "order")>
|
||||
<order>
|
||||
<cfif structKeyExists(options.order, "invoiceNumber")>
|
||||
<invoiceNumber>#options.order.invliceNumber#</invoiceNumber>
|
||||
</cfif>
|
||||
<cfif structKeyExists(options.order, "description")>
|
||||
<description>#options.order.description#</description>
|
||||
</cfif>
|
||||
</order>
|
||||
</cfif>
|
||||
|
||||
|
||||
<cfif structKeyExists(options, "lineItems")>
|
||||
<lineItems>
|
||||
<cfloop array="#options.lineItems#" index="itn">
|
||||
<lineItem>
|
||||
<itemId>#options.lineItems[itm].itemId#</itemId>
|
||||
<name>#options.lineItems[itm].name#</name>
|
||||
<description>#options.lineItems[itm].description#</description>
|
||||
<quantity>#options.lineItems[itm].quantity#</quantity>
|
||||
<unitPrice>#options.lineItems[itm].unitPrice#</unitPrice>
|
||||
</lineItem>
|
||||
</cfloop>
|
||||
|
||||
</lineItems>
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(options, "tax")>
|
||||
<tax>
|
||||
<amount>#options.tax.amount#</amount>
|
||||
<name>#options.tax.name#</name>
|
||||
<description>#options.tax.description#</description>
|
||||
</tax>
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(options, "shipping")>
|
||||
<shipping>
|
||||
<amount>#options.shipping.amount#</amount>
|
||||
<name>#options.shipping.name#</name>
|
||||
<description>#options.shipping.description#</description>
|
||||
</shipping>
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(options, "poNumber")>
|
||||
<poNumber>#options.poNumber#</poNumber>
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(options, "customer")>
|
||||
<customer>
|
||||
<id>#options.customer#</id>
|
||||
</customer>
|
||||
</cfif>
|
||||
|
||||
<cfif !isNull(account)>
|
||||
<billTo>
|
||||
<firstName>#account.getfirstName()#</firstName>
|
||||
<lastName>#account.getlastName()#</lastName>
|
||||
<company>#account.getCompany()#</company>
|
||||
<address>#account.getaddress()#</address>
|
||||
<city>#account.getcity()#</city>
|
||||
<state>#account.getRegion()#</state>
|
||||
<zip>#account.getPostalCode()#</zip>
|
||||
<country>#account.getcountry()#</country>
|
||||
</billTo>
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(options, "shipTo")>
|
||||
<cfset var shipTo = options.shipTo>
|
||||
<shipTo>
|
||||
<firstName>#shipTo.UserFirstName#</firstName>
|
||||
<lastName>#shipTo.LaerFirstName#</lastName>
|
||||
<company>#shipTo.company#</company>
|
||||
<address>#shipTo.address#</address>
|
||||
<city>#shipTo.city#</city>
|
||||
<state>#shipTo.state#</state>
|
||||
<zip>#shipTo.zip#</zip>
|
||||
<country>#shipTo.country#</country>
|
||||
</shipTo>
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(options, "customerIP")>
|
||||
<customerIP>#options.customerIP#</customerIP>
|
||||
</cfif>
|
||||
|
||||
<!--- Uncomment this section for Card Present Sandbox Accounts --->
|
||||
<!--- <retail><marketType>2</marketType><deviceType>1</deviceType></retail> --->
|
||||
<cfif structKeyExists(options, "transactionSettings")>
|
||||
<transactionSettings>
|
||||
<setting>
|
||||
<settingName>testRequest</settingName>
|
||||
<settingValue>false</settingValue>
|
||||
</setting>
|
||||
</transactionSettings>
|
||||
</cfif>
|
||||
|
||||
|
||||
<cfif structKeyExists(options, "userFields")>
|
||||
<userFields>
|
||||
<cfloop array="#option.userFields#" item="uf">
|
||||
<userField>
|
||||
<name>#options.userfields[uf].name#</name>
|
||||
<value>#options.userfields[uf].value#</value>
|
||||
</userField>
|
||||
</cfloop>
|
||||
</userFields>
|
||||
</cfif>
|
||||
</transactionRequest>
|
||||
</createTransactionRequest>
|
||||
|
||||
</cfoutput>
|
||||
</cfxml>
|
||||
|
||||
<cfreturn local.xml>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="createCustomerRequest" returntype="xml" hint="Creates the customer requests XML items">
|
||||
<cfargument name="requestType" hint="the type of transaction we need to carry out">
|
||||
<cfargument name="merchantAuthentication" hint="The merchant ids">
|
||||
<cfargument name="customer" required="false">
|
||||
<cfargument name="paymentProfile" required="false">
|
||||
<cfargument name="options" default="#StructNew()#">
|
||||
<cfargument name="search" default="#StructNew()#">
|
||||
|
||||
<cfif !isValidCustomerRequestType(requestType)>
|
||||
<cfthrow type="cfpayment.UnknownCustomerRequestType" message="Request type, #requestType# is not a valid request type">
|
||||
</cfif>
|
||||
|
||||
|
||||
<cfif requestType EQ "createCustomerPaymentProfileRequest">
|
||||
|
||||
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfxml variable="local.xml">
|
||||
<cfoutput>
|
||||
|
||||
|
||||
<#requestType# xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
|
||||
<merchantAuthentication>
|
||||
<name>#merchantAuthentication.name#</name>
|
||||
<transactionKey>#merchantAuthentication.transactionKey#</transactionKey>
|
||||
</merchantAuthentication>
|
||||
|
||||
<cfif ListFindNoCase("getCustomerProfileRequest,deleteCustomerProfileRequest,createCustomerPaymentProfileRequest,getCustomerPaymentProfileRequest,validateCustomerPaymentProfileRequest,updateCustomerPaymentProfileRequest,deleteCustomerPaymentProfileRequest", requestType)>
|
||||
<!--- They require it so throw a message --->
|
||||
<cfif isEmpty(customer.getCustomerProfileId())>
|
||||
<cfthrow type="cfpayment.missingAttributeException" message="The customerProfileId is required for this transaction">
|
||||
</cfif>
|
||||
<customerProfileId>#customer.getCustomerProfileId()#</customerProfileId>
|
||||
</cfif>
|
||||
|
||||
<cfif ListFindNoCase("getCustomerPaymentProfileRequest,validateCustomerPaymentProfileRequest,deleteCustomerPaymentProfileRequest", requestType)>
|
||||
<cfif isEmpty(paymentProfile.getCustomerPaymentProfileID())>
|
||||
<cfthrow type="cfpayment.missingAttributeException" message="The customerPaymentProfileId is required for this transaction">
|
||||
</cfif>
|
||||
<customerPaymentProfileId>#paymentProfile.getCustomerPaymentProfileID()#</customerPaymentProfileId>
|
||||
</cfif>
|
||||
|
||||
<cfif requestType EQ "validateCustomerPaymentProfileRequest">
|
||||
<cfset var mode = variables.testmode? "testMode" : "liveMode">
|
||||
<validationMode>#mode#</validationMode>
|
||||
</cfif>
|
||||
|
||||
|
||||
<!--- This is for searches of payment profiles --->
|
||||
<cfif requestType EQ "getCustomerPaymentProfileListRequest">
|
||||
<cfif structIsEmpty(search)>
|
||||
<cfthrow type="cfpayment.missingAttributeException" message="Thhere are no properties in the search query">
|
||||
</cfif>
|
||||
<searchType>cardsExpiringInMonth</searchType>
|
||||
<month>#search.month#</month>
|
||||
<sorting>
|
||||
<orderBy>#search.sorting.orderBy#</orderBy>
|
||||
<orderDescending>#search.sorting.orderDescending#</orderDescending>
|
||||
</sorting>
|
||||
<paging>
|
||||
<limit>#search.paging.limit#</limit>
|
||||
<offset>#search.paging.offset#</offset>
|
||||
</paging>
|
||||
</cfif>
|
||||
|
||||
|
||||
|
||||
<cfif listFindNoCase("createCustomerPaymentProfileRequest,updateCustomerPaymentProfileRequest", requestType)>
|
||||
<cfif isEmpty(paymentProfile)>
|
||||
<cfthrow type="cfpayment.missingAttributeException" message="The paymentProfile is required for this transaction">
|
||||
</cfif>
|
||||
|
||||
<cfset card = paymentProfile.getPaymentMethods()>
|
||||
|
||||
<paymentProfile>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--- If we have a billTo --->
|
||||
<cfif !isNull(paymentProfile.getBillTo())>
|
||||
<cfset billto =paymentProfile.getBillTo()>
|
||||
<billTo>
|
||||
<firstName>#billto.getfirstName()#</firstName>
|
||||
<lastName>#billto.getlastName()#</lastName>
|
||||
<company>#billto.getCompany()#</company>
|
||||
<address>#billto.getAddress()#</address>
|
||||
<city>#billto.getCity()#</city>
|
||||
<state>#billto.getstate()#</state>
|
||||
<zip>#billto.getZip()#</zip>
|
||||
<country>#billto.getCountry()#</country>
|
||||
<phoneNumber>#billto.getphoneNumber()#</phoneNumber>
|
||||
<faxNumber>#billto.getfaxNumber()#</faxNumber>
|
||||
</billTo>
|
||||
<cfelseif !isNull(card)>
|
||||
|
||||
<billTo>
|
||||
<firstName>#card.getfirstName()#</firstName>
|
||||
<lastName>#card.getlastName()#</lastName>
|
||||
<company>#card.getCompany()#</company>
|
||||
<address>#card.getAddress()#</address>
|
||||
<city>#card.getCity()#</city>
|
||||
<state>#card.getRegion()#</state>
|
||||
<zip>#card.getPostalCode()#</zip>
|
||||
<country>#card.getCountry()#</country>
|
||||
<phoneNumber>#card.getphoneNumber()#</phoneNumber>
|
||||
</billTo>
|
||||
</cfif>
|
||||
|
||||
|
||||
<cfif isObject(card) && !isNull(card)>
|
||||
<payment>
|
||||
<creditCard>
|
||||
<cardNumber>#card.getAccount()#</cardNumber>
|
||||
<expirationDate>#DateFormat(card.getExpirationDate(), "YYYY-MM")#</expirationDate>
|
||||
</creditCard>
|
||||
</payment>
|
||||
<cfelseif isStruct(card)>
|
||||
<payment>
|
||||
<creditCard>
|
||||
<cardNumber>#card.creditcard.cardNumber#</cardNumber>
|
||||
<expirationDate>#card.creditcard.expirationDate#</expirationDate>
|
||||
</creditCard>
|
||||
</payment>
|
||||
|
||||
</cfif>
|
||||
|
||||
|
||||
|
||||
<cfif requestType EQ "updateCustomerPaymentProfileRequest">
|
||||
<cfif isEmpty(paymentProfile.getCustomerPaymentProfileId())>
|
||||
<cfthrow type="cfpayment.missingAttributeException" message="The customerPaymentProfileId is required for this transaction">
|
||||
</cfif>
|
||||
<customerPaymentProfileId>#paymentProfile.getCustomerPaymentProfileId()#</customerPaymentProfileId>
|
||||
</cfif>
|
||||
|
||||
</paymentProfile>
|
||||
|
||||
<cfif variables.testmode>
|
||||
<validationMode>testMode</validationMode>
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
|
||||
<cfif ListFindNoCase("createCustomerProfileRequest,updateCustomerProfileRequest", requestType)>
|
||||
<profile>
|
||||
<cfif !isEmpty(customer.getMerchantCustomerID())>
|
||||
<merchantCustomerId>#customer.getMerchantCustomerID()#</merchantCustomerId>
|
||||
</cfif>
|
||||
<cfif !isEmpty(customer.getdescription())>
|
||||
<description>#customer.getdescription()#</description>
|
||||
</cfif>
|
||||
<cfif !isEmpty(customer.getemail())>
|
||||
<email>#customer.getemail()#</email>
|
||||
</cfif>
|
||||
|
||||
<cfif !isEmpty(customer.getCustomerProfileId())>
|
||||
<customerProfileId>#customer.getCustomerProfileId()#</customerProfileId>
|
||||
</cfif>
|
||||
|
||||
<cfset paymentProfiles = customer.getPaymentProfiles()>
|
||||
<cfif !isNull(paymentProfiles) && ArrayLen(paymentProfiles)>
|
||||
|
||||
<cfloop array="#paymentProfiles#" item="paymentProfile">
|
||||
<paymentProfiles>
|
||||
<customerType>#paymentProfile.getCustomerType()#</customerType>
|
||||
|
||||
<cfif !isNull(paymentProfile.getBillTo())>
|
||||
<cfset var billTo = paymentProfile.getBillTo()>
|
||||
<billTo>
|
||||
<firstName>#billTo.getfirstName()#</firstName>
|
||||
<lastName>#billTo.getlastName()#</lastName>
|
||||
<company>#billTo.getcompany()#</company>
|
||||
<address>#billTo.getaddress()#</address>
|
||||
<city>#billTo.getcity()#</city>
|
||||
<state>#billTo.getstate()#</state>
|
||||
<zip>#billTo.getzip()#</zip>
|
||||
<country>#billTo.getcountry()#</country>
|
||||
<phoneNumber>#billTo.getphoneNumber()#</phoneNumber>
|
||||
<faxNumber>#billTo.getfaxNumber()#</faxNumber>
|
||||
</billTo>
|
||||
</cfif>
|
||||
|
||||
|
||||
|
||||
<cfif !isNull(paymentProfile.getPaymentMethods())>
|
||||
<cfset creditcard = paymentProfile.getPaymentMethods()>
|
||||
<payment>
|
||||
<creditCard>
|
||||
<cardNumber>#creditcard.getAccount()#</cardNumber>
|
||||
<expirationDate>#DateFormat(creditcard.getExpirationDate(), "YYYY-MM")#</expirationDate>
|
||||
</creditCard>
|
||||
</payment>
|
||||
</cfif>
|
||||
</paymentProfiles>
|
||||
</cfloop>
|
||||
</cfif>
|
||||
|
||||
</profile>
|
||||
<cfif variables.testmode && !isNull(paymentProfiles) && ArrayLen(paymentProfiles)>
|
||||
<validationMode>testMode</validationMode>
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
|
||||
</#requestType#>
|
||||
</cfoutput>
|
||||
</cfxml>
|
||||
|
||||
|
||||
<cfreturn local.xml>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="isValidTransactionType" access="private" returntype="boolean" hint="Checks whether the transaction type is valid">
|
||||
<cfargument name="type" type="string">
|
||||
<cfreturn listFindNoCase(variables.validTransactions, arguments.type)>
|
||||
</cffunction>
|
||||
<cffunction name="isValidCustomerRequestType" access="private" returntype="boolean" hint="Checks whether the customer transaction type is valid">
|
||||
<cfargument name="type" type="string">
|
||||
<cfreturn listFindNoCase(variables.validCustomerRequestTypes, arguments.type)>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
31
cfpayment/api/gateway/authorizenet/address.cfc
Normal file
31
cfpayment/api/gateway/authorizenet/address.cfc
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is an address object that can be used to store billTo addresses etc.
|
||||
|
||||
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.
|
||||
*/
|
||||
component
|
||||
accessors="true"
|
||||
{
|
||||
property name="firstName" type="string" getter="true" setter="true";
|
||||
property name="lastName" type="string" getter="true" setter="true";
|
||||
property name="company" type="string" getter="true" setter="true";
|
||||
property name="address" type="string" getter="true" setter="true";
|
||||
property name="city" type="string" getter="true" setter="true";
|
||||
property name="state" type="string" getter="true" setter="true";
|
||||
property name="zip" type="string" getter="true" setter="true";
|
||||
property name="country" type="string" getter="true" setter="true";
|
||||
property name="phoneNumber" type="string" getter="true" setter="true";
|
||||
property name="faxNumber" type="string" getter="true" setter="true";
|
||||
}
|
||||
782
cfpayment/api/gateway/authorizenet/authorizenet.cfc
Normal file
782
cfpayment/api/gateway/authorizenet/authorizenet.cfc
Normal file
|
|
@ -0,0 +1,782 @@
|
|||
<!---
|
||||
|
||||
Copyright 2006-2009 Jonah Blossom (http://www.creori.com/)
|
||||
|
||||
Based on Authorizenet.cfm custom tag by Jonah Blossom, Authorize.net
|
||||
AIM ColdFusion Examples, and braintree.cfc by Brian Ghidinelli
|
||||
|
||||
Additional development by Brian Ghidinelli (http://www.ghidinelli.com)
|
||||
|
||||
|
||||
Authorize.net Advanced Integration Method (AIM) Implementation Guide:
|
||||
http://developer.authorize.net/guides/AIM/
|
||||
|
||||
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="Authorize.net AIM Interface" extends="cfpayment.api.gateway.base" hint="Authorize.net AIM Gateway" output="false">
|
||||
|
||||
<cfscript>
|
||||
variables.cfpayment.GATEWAY_NAME = "Authorize.net";
|
||||
variables.cfpayment.GATEWAY_VERSION = "4.0";
|
||||
|
||||
// The test URL requires a separate developer transKey and login
|
||||
// Request a developer account here: http://developer.authorize.net/testaccount/
|
||||
variables.cfpayment.GATEWAY_TEST_URL = "https://apitest.authorize.net/xml/v1/request.api";
|
||||
variables.cfpayment.GATEWAY_LIVE_URL = "https://api.authorize.net/xml/v1/request.api";
|
||||
variables.cfpayment.GATEWAY_responseDelimeter = "|"; // For x_delim_char - Any valid character overrides merchant interface setting if defined.
|
||||
|
||||
structInsert(variables, "authorizenet", structNew());
|
||||
structInsert(variables.authorizenet, "respReasonCodes", structNew());
|
||||
|
||||
addResponseReasonCodes(); // Sets up the response code lookup struct.
|
||||
</cfscript>
|
||||
|
||||
<!--- ------------------------------------------------------------------------------
|
||||
process wrapper with gateway/transaction error handling
|
||||
------------------------------------------------------------------------- --->
|
||||
<cffunction name="process" output="false" access="private" returntype="any">
|
||||
<cfargument name="payload" type="struct" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
|
||||
<!---
|
||||
Minimum Requirements for Authorize.net AIM:
|
||||
|
||||
|
||||
Minimum required for new API
|
||||
{
|
||||
"createTransactionRequest": {
|
||||
"merchantAuthentication": {
|
||||
"name": "4U4Vg7WFjg99",
|
||||
"transactionKey": "6Dn698bW2K8b6mah"
|
||||
},
|
||||
"refId": "123456",
|
||||
"transactionRequest": {
|
||||
"transactionType": "authCaptureTransaction",
|
||||
"amount": "5",
|
||||
"payment": {
|
||||
"creditCard": {
|
||||
"cardNumber": "5424000000000015",
|
||||
"expirationDate": "1220",
|
||||
"cardCode": "999"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
The following is the minimum set of NAME/VALUE pairs that must be submitted to the payment gateway for each credit card transaction.
|
||||
|
||||
x_login - Merchant''s Login ID
|
||||
x_tran_key - Merchant''s Transaction Key
|
||||
|
||||
x_delim_data - TRUE
|
||||
x_delim_char - Any valid character
|
||||
x_version - 3.1
|
||||
x_relay_response - FALSE
|
||||
|
||||
x_method - Payment method (CC)
|
||||
x_type - Type of transaction (AUTH_CAPTURE, AUTH_ONLY, CAPTURE_ONLY, CREDIT, VOID, PRIOR_AUTH_CAPTURE)
|
||||
x_amount - Amount of purchase inclusive of tax
|
||||
x_card_num - Customer's credit card number
|
||||
x_exp_date - Customer's credit card expiration date
|
||||
x_card_code - Any valid CVV2, CVC2, or CID value
|
||||
x_first_name - Customer's first name
|
||||
x_last_name - Customer's last name
|
||||
x_address - Customer's street address
|
||||
x_city - City for the customer's address
|
||||
x_state - State for the customer's address
|
||||
x_zip - ZIP code for the customer's address
|
||||
x_country - Country for the customer's address
|
||||
x_phone - Customer's phone number
|
||||
x_email - Customer's e-mail address
|
||||
x_customer_ip - Customer's IP address
|
||||
--->
|
||||
<cfscript>
|
||||
var response = "";
|
||||
var results = structNew();
|
||||
var pairs = "";
|
||||
var ii = 1;
|
||||
var numPairs = 0;
|
||||
p = arguments.payload; // shortcut (by reference)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//fold in any optional data
|
||||
structAppend(p, arguments.options, true);
|
||||
|
||||
// Translate to Authorize.net specific name.
|
||||
if (structKeyExists(arguments.options, "orderID"))
|
||||
structInsert(p, "x_invoice_num", arguments.options.orderID, "yes");
|
||||
|
||||
// Configure the gateway environment variables.
|
||||
structInsert(p, "x_version", variables.cfpayment.GATEWAY_VERSION, "yes");
|
||||
structInsert(p, "x_tran_key", getMerchantAccount(), "yes");
|
||||
structInsert(p, "x_login", getUsername(), "yes");
|
||||
structInsert(p, "x_delim_data", "TRUE", "yes");
|
||||
|
||||
|
||||
|
||||
// This overrides the delimeter set in the merchant interface.
|
||||
// We need to know what it is to successfully parse the response.
|
||||
structInsert(p, "x_delim_char", getResponseDelimeter(), "yes");
|
||||
|
||||
// All AIM transactions are direct response, a value of FALSE is required.
|
||||
structInsert(p, "x_relay_response", "FALSE", "yes");
|
||||
|
||||
// Authorize.net has two distinct (but overlapping) test modes.
|
||||
// The first is a developer account. Contact for them credentials and use them to connect to the host specified in GATEWAY_TEST_URL
|
||||
// The second is test mode where you can use "test" account numbers, etc. Both developer and production accounts can be set to test mode.
|
||||
// However, if set to TRUE here, you can't do any follow-on trans like CAPTURE or VOID because x_trans_id is always 0
|
||||
// But, if set to FALSE, you can't test AVS failures.
|
||||
if (NOT structKeyExists(p, "x_test_request"))
|
||||
{
|
||||
structInsert(p, "x_test_request", "FALSE", "yes");
|
||||
}
|
||||
|
||||
|
||||
// send it over the wire using the base gateway's transport function.
|
||||
response = createResponse(argumentCollection = super.process(payload = p));
|
||||
|
||||
|
||||
// do some meta-checks for gateway-level errors (as opposed to auth/decline errors)
|
||||
if (NOT response.hasError()) {
|
||||
|
||||
// we need to have a result; otherwise that's an error in itself
|
||||
if (len(response.getResult())) {
|
||||
|
||||
results = parseResponse(response.getResult());
|
||||
|
||||
// handle common response fields
|
||||
if (structKeyExists(results, "x_resp_code"))
|
||||
response.setMessage(results.x_resp_code);
|
||||
|
||||
if (structKeyExists(results, "x_reason_text"))
|
||||
response.setMessage(response.getMessage() & ": " & results.x_reason_text);
|
||||
|
||||
if (structKeyExists(results, "x_trans_ID"))
|
||||
response.setTransactionID(results.x_trans_ID);
|
||||
|
||||
if (structKeyExists(results, "x_approval_code"))
|
||||
response.setAuthorization(results.x_approval_code);
|
||||
|
||||
// handle common "success" fields
|
||||
if (structKeyExists(results, "x_AVS_code"))
|
||||
response.setAVSCode(results.x_AVS_code);
|
||||
|
||||
if (structKeyExists(results, "x_card_code_resp"))
|
||||
response.setCVVCode(results.x_card_code_resp);
|
||||
|
||||
// see if the response was successful
|
||||
switch (results.x_resp_code) {
|
||||
case "1": {
|
||||
response.setStatus(getService().getStatusSuccessful());
|
||||
break;
|
||||
}
|
||||
case "2": {
|
||||
response.setStatus(getService().getStatusDeclined());
|
||||
break;
|
||||
}
|
||||
case "4": {
|
||||
response.setStatus(5); // On hold (this status value is not currently defined in core.cfc)
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
response.setStatus(getService().getStatusFailure()); // only other known state is 3 meaning, "error in transaction data or system error"
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
response.setStatus(getService().getStatusUnknown()); // Authorize.net didn't return a response
|
||||
}
|
||||
}
|
||||
|
||||
if (response.getStatus() EQ getService().getStatusSuccessful()) {
|
||||
if (results.x_type EQ "auth_only")
|
||||
structInsert(results, "result", "APPROVED", "yes");
|
||||
else
|
||||
structInsert(results, "result", "CAPTURED", "yes");
|
||||
}
|
||||
else if (response.getStatus() EQ getService().getStatusDeclined()) {
|
||||
if (results.x_type EQ "auth_only")
|
||||
structInsert(results, "result", "NOT APPROVED", "yes");
|
||||
else
|
||||
structInsert(results, "result", "NOT CAPTURED", "yes");
|
||||
}
|
||||
else {
|
||||
structInsert(results, "result", "ERROR", "yes");
|
||||
}
|
||||
|
||||
structInsert(results, "Reference", response.getMessage(), "yes");
|
||||
structInsert(results, "Additional", "Gateway=" & getGatewayName(), "yes"); // Reply with the gateway used.
|
||||
|
||||
// store parsed result
|
||||
response.setParsedResult(results);
|
||||
|
||||
return response;
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
<!--- ------------------------------------------------------------------------------
|
||||
PUBLIC METHODS
|
||||
------------------------------------------------------------------------- --->
|
||||
<cffunction name="purchase" output="false" access="public" returntype="any" hint="Authorize + Capture in one step">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
|
||||
|
||||
|
||||
<cfscript>
|
||||
var post = structNew();
|
||||
|
||||
// set general values
|
||||
structInsert(post, "x_amount", arguments.money.getAmount(), "yes");
|
||||
structInsert(post, "x_type", "AUTH_CAPTURE", "yes");
|
||||
|
||||
switch (lcase(listLast(getMetaData(arguments.account).fullname, "."))) {
|
||||
case "creditcard": {
|
||||
// copy in name and customer details
|
||||
post = addCustomer(post = post, account = arguments.account, options = arguments.options);
|
||||
post = addCreditCard(post = post, account = arguments.account, options = arguments.options);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw("The account type #lcase(listLast(getMetaData(arguments.account).fullname, "."))# is not supported by this gateway.", "", "cfpayment.InvalidAccount");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return process(payload = post, options = arguments.options);
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="authorize" output="false" access="public" returntype="any" hint="Authorize (only) a credit card">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
<cfscript>
|
||||
var post = structNew();
|
||||
|
||||
// set general values
|
||||
structInsert(post, "x_amount", arguments.money.getAmount(), "yes");
|
||||
structInsert(post, "x_type", "AUTH_ONLY", "yes");
|
||||
|
||||
switch (lcase(listLast(getMetaData(arguments.account).fullname, "."))) {
|
||||
case "creditcard": {
|
||||
// copy in name and customer details
|
||||
post = addCustomer(post = post, account = arguments.account, options = arguments.options);
|
||||
post = addCreditCard(post = post, account = arguments.account, options = arguments.options);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw("The account type #lcase(listLast(getMetaData(arguments.account).fullname, "."))# is not supported by this gateway.", "", "cfpayment.InvalidAccount");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return process(payload = post, options = arguments.options);
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="capture" output="false" access="public" returntype="any" hint="Capture a prior authorization - set it to be settled.">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="authorization" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
<cfscript>
|
||||
var post = structNew();
|
||||
|
||||
// set required values
|
||||
structInsert(post, "x_amount", arguments.money.getAmount(), "yes");
|
||||
structInsert(post, "x_type", "PRIOR_AUTH_CAPTURE", "yes");
|
||||
structInsert(post, "x_trans_id", arguments.authorization, "yes");
|
||||
|
||||
// capture can also take optional values:
|
||||
// TODO: define optional values
|
||||
|
||||
return process(payload = post, options = arguments.options);
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="credit" output="false" access="public" returntype="any" hint="Refund all or part of a previous transaction">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="transactionid" type="any" required="false" />
|
||||
<cfargument name="account" type="any" required="false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
<cfscript>
|
||||
var post = structNew();
|
||||
|
||||
// set required values
|
||||
structInsert(post, "x_amount", arguments.money.getAmount(), "yes");
|
||||
structInsert(post, "x_type", "CREDIT", "yes");
|
||||
structInsert(post, "x_trans_id", arguments.transactionid, "yes");
|
||||
|
||||
switch (lcase(listLast(getMetaData(arguments.account).fullname, "."))) {
|
||||
case "creditcard": {
|
||||
// copy in name and customer details
|
||||
post = addCustomer(post = post, account = arguments.account, options = arguments.options);
|
||||
post = addCreditCard(post = post, account = arguments.account, options = arguments.options);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw("The account type #lcase(listLast(getMetaData(arguments.account).fullname, "."))# is not supported by this gateway.", "", "cfpayment.InvalidAccount");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// credit can also take optional values:
|
||||
// TODO: define optional values
|
||||
|
||||
return process(payload = post, options = arguments.options);
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="void" output="false" access="public" returntype="any" hint="Cancel a pending transaction - must be called on an un-settled transaction.">
|
||||
<cfargument name="transactionid" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
<cfscript>
|
||||
var post = structNew();
|
||||
|
||||
// set required values
|
||||
structInsert(post, "x_type", "VOID", "yes");
|
||||
structInsert(post, "x_trans_id", arguments.transactionid, "yes");
|
||||
|
||||
//credit can also take optional values:
|
||||
// TODO: define optional values
|
||||
|
||||
return process(payload = post, options = arguments.options);
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
<!--- ------------------------------------------------------------------------------
|
||||
CUSTOM GETTERS/SETTERS
|
||||
------------------------------------------------------------------------- --->
|
||||
<cffunction name="getResponseDelimeter" access="package" output="false" returntype="any">
|
||||
<cfreturn variables.cfpayment.GATEWAY_responseDelimeter />
|
||||
</cffunction>
|
||||
<cffunction name="setResponseDelimeter" access="package" output="false" returntype="void">
|
||||
<cfargument name="responseDelimeter" type="any" required="true" />
|
||||
<cfset variables.cfpayment.GATEWAY_responseDelimeter = arguments.responseDelimeter />
|
||||
</cffunction>
|
||||
|
||||
<!--- ------------------------------------------------------------------------------
|
||||
PRIVATE HELPER METHODS
|
||||
------------------------------------------------------------------------- --->
|
||||
<cffunction name="addCustomer" output="false" access="private" returntype="any" hint="Add customer contact details to the request object">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
<cfscript>
|
||||
structInsert(arguments.post, "x_first_name", arguments.account.getFirstName()); // Customer's first name
|
||||
structInsert(arguments.post, "x_last_name", arguments.account.getLastName()); // Customer's last name
|
||||
structInsert(arguments.post, "x_address", arguments.account.getAddress()); // Customer's street address
|
||||
structInsert(arguments.post, "x_city", arguments.account.getCity()); // City for the customer's address
|
||||
structInsert(arguments.post, "x_state", arguments.account.getRegion()); // State for the customer's address
|
||||
structInsert(arguments.post, "x_zip", arguments.account.getPostalCode()); // ZIP code for the customer's address
|
||||
structInsert(arguments.post, "x_country", arguments.account.getCountry()); // Country for the customer's address
|
||||
|
||||
if (structKeyExists(arguments.options, "address") AND structKeyExists(arguments.options.address, "phone"))
|
||||
structInsert(arguments.post, "x_phone", options.address.phone); // Customer's phone number
|
||||
else
|
||||
structInsert(arguments.post, "x_phone", ""); // No phone number
|
||||
|
||||
if (structKeyExists(arguments.options, "email"))
|
||||
structInsert(arguments.post, "x_email", arguments.options.email); // Customer's e-mail address
|
||||
else
|
||||
structInsert(arguments.post, "x_email", ""); // No email
|
||||
|
||||
if (structKeyExists(arguments.options, "IPAddress"))
|
||||
structInsert(arguments.post, "x_customer_ip", arguments.options.IPAddress); // Customer's IP address
|
||||
else
|
||||
structInsert(arguments.post, "x_customer_ip", ""); // No IP Address
|
||||
|
||||
return arguments.post;
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addCreditCard" output="false" access="private" returntype="any" hint="Add payment source fields to the request object">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
<cfscript>
|
||||
structInsert(arguments.post, "x_method", "CC"); // Payment method (CC)
|
||||
structInsert(arguments.post, "x_card_num", arguments.account.getAccount()); // credit card number
|
||||
structInsert(arguments.post, "x_exp_date", numberFormat(arguments.account.getMonth(), "00") & right(arguments.account.getYear(), 2)); // credit card expiration date
|
||||
structInsert(arguments.post, "x_card_code", arguments.account.getVerificationValue()); // Any valid CVV2, CVC2, or CID value
|
||||
|
||||
return arguments.post;
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="throw" output="true" access="public" hint="Script version of CF tag: CFTHROW">
|
||||
<cfargument name="message" required="no" default="" />
|
||||
<cfargument name="detail" required="no" default="" />
|
||||
<cfargument name="type" required="no" />
|
||||
<cfif not isSimpleValue(arguments.message)>
|
||||
<cfsavecontent variable="arguments.message">
|
||||
<cfdump var="#arguments.message#" />
|
||||
</cfsavecontent>
|
||||
</cfif>
|
||||
<cfif not isSimpleValue(arguments.detail)>
|
||||
<cfsavecontent variable="arguments.detail">
|
||||
<cfdump var="#arguments.detail#" />
|
||||
</cfsavecontent>
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments, "type")>
|
||||
<cfthrow message="#arguments.message#" detail="#arguments.detail#" type="#arguments.type#" />
|
||||
<cfelse>
|
||||
<cfthrow message="#arguments.message#" detail="#arguments.detail#" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cfscript>
|
||||
|
||||
// Parse the delimited gateway response.
|
||||
function parseResponse(gatewayResponse) {
|
||||
var results = structNew();
|
||||
|
||||
// Use Java's split because we have empty list elements which CF doesn't natively handle.
|
||||
var response = JavaCast('string', arguments.gatewayResponse).split("\#getResponseDelimeter()#");
|
||||
|
||||
// Alternatively, if you don't want to or can't use JavaCast() and split(), use this custom function:
|
||||
//var response = listToArrayInclEmpty(arguments.gatewayResponse);
|
||||
|
||||
results = insertResult(results, response, "1", "Response Code", "x_resp_code", "Error");
|
||||
results = insertResult(results, response, "2", "Response Subcode", "x_resp_subcode", "-1");
|
||||
results = insertResult(results, response, "3", "Response Reason Code:", "x_reason_code", "-1");
|
||||
results = insertResult(results, response, "4", "Response Reason Text", "x_reason_text", "There was an unknown parsing or processing error.");
|
||||
results = insertResult(results, response, "5", "Approval Code", "x_approval_code", "");
|
||||
results = insertResult(results, response, "6", "AVS Result Code", "x_AVS_code", "");
|
||||
results = insertResult(results, response, "7", "Transaction ID", "x_trans_ID", "-1");
|
||||
results = insertResult(results, response, "8", "Invoice Number", "x_invoice_num", "");
|
||||
results = insertResult(results, response, "9", "Description", "x_description", "");
|
||||
results = insertResult(results, response, "10", "Amount", "x_amount", "");
|
||||
results = insertResult(results, response, "11", "Method", "x_method", "");
|
||||
results = insertResult(results, response, "12", "Transaction Type", "x_type", "");
|
||||
results = insertResult(results, response, "13", "Customer ID", "x_cust_id", "");
|
||||
results = insertResult(results, response, "14", "Cardholder First Name", "x_first_name", "");
|
||||
results = insertResult(results, response, "15", "Cardholder Last Name", "x_last_name", "");
|
||||
results = insertResult(results, response, "16", "Company", "x_company", "");
|
||||
results = insertResult(results, response, "17", "Billing Address", "x_address", "");
|
||||
results = insertResult(results, response, "18", "City", "x_city", "");
|
||||
results = insertResult(results, response, "19", "State", "x_state", "");
|
||||
results = insertResult(results, response, "20", "ZIP", "x_zip", "");
|
||||
results = insertResult(results, response, "21", "Country", "x_country", "");
|
||||
results = insertResult(results, response, "22", "Phone", "x_phone", "");
|
||||
results = insertResult(results, response, "23", "Fax", "x_fax", "");
|
||||
results = insertResult(results, response, "24", "E-Mail", "x_email", "");
|
||||
results = insertResult(results, response, "25", "Ship-to First Name", "x_ship_to_first_name", "");
|
||||
results = insertResult(results, response, "26", "Ship-to Last Name", "x_ship_to_last_name", "");
|
||||
results = insertResult(results, response, "27", "Ship-to Company", "x_ship_to_company", "");
|
||||
results = insertResult(results, response, "28", "Ship-to Address", "x_ship_to_address", "");
|
||||
results = insertResult(results, response, "29", "Ship-to City", "x_ship_to_city", "");
|
||||
results = insertResult(results, response, "30", "Ship-to State", "x_ship_to_state", "");
|
||||
results = insertResult(results, response, "31", "Ship-to ZIP", "x_ship_to_zip", "");
|
||||
results = insertResult(results, response, "32", "Ship-to Country", "x_ship_to_country", "");
|
||||
results = insertResult(results, response, "33", "Tax Amount", "x_tax", "");
|
||||
results = insertResult(results, response, "34", "Duty Amount", "x_duty", "");
|
||||
results = insertResult(results, response, "35", "Freight Amount", "x_freight", "");
|
||||
results = insertResult(results, response, "36", "Tax Exempt Flag", "x_tx_exempt", "");
|
||||
results = insertResult(results, response, "37", "PO Number", "x_po_num", "");
|
||||
results = insertResult(results, response, "38", "MD5 Hash:", "x_MD5_Hash", "");
|
||||
results = insertResult(results, response, "39", "Card Code Response", "x_card_code_resp", "");
|
||||
/*results = insertResult(results, response, "40", "Reserved for future use", "x_future_40", "");
|
||||
results = insertResult(results, response, "41", "Reserved for future use", "x_future_41", "");
|
||||
results = insertResult(results, response, "42", "Reserved for future use", "x_future_42", "");
|
||||
results = insertResult(results, response, "43", "Reserved for future use", "x_future_43", "");
|
||||
results = insertResult(results, response, "44", "Reserved for future use", "x_future_44", "");
|
||||
results = insertResult(results, response, "45", "Reserved for future use", "x_future_45", "");
|
||||
results = insertResult(results, response, "46", "Reserved for future use", "x_future_46", "");
|
||||
results = insertResult(results, response, "47", "Reserved for future use", "x_future_47", "");
|
||||
results = insertResult(results, response, "48", "Reserved for future use", "x_future_48", "");
|
||||
results = insertResult(results, response, "49", "Reserved for future use", "x_future_49", "");
|
||||
results = insertResult(results, response, "50", "Reserved for future use", "x_future_50", "");
|
||||
results = insertResult(results, response, "51", "Reserved for future use", "x_future_51", "");
|
||||
results = insertResult(results, response, "52", "Reserved for future use", "x_future_52", "");
|
||||
results = insertResult(results, response, "53", "Reserved for future use", "x_future_53", "");
|
||||
results = insertResult(results, response, "54", "Reserved for future use", "x_future_54", "");
|
||||
results = insertResult(results, response, "55", "Reserved for future use", "x_future_55", "");
|
||||
results = insertResult(results, response, "56", "Reserved for future use", "x_future_56", "");
|
||||
results = insertResult(results, response, "57", "Reserved for future use", "x_future_57", "");
|
||||
results = insertResult(results, response, "58", "Reserved for future use", "x_future_58", "");
|
||||
results = insertResult(results, response, "59", "Reserved for future use", "x_future_59", "");
|
||||
results = insertResult(results, response, "60", "Reserved for future use", "x_future_60", "");
|
||||
results = insertResult(results, response, "61", "Reserved for future use", "x_future_61", "");
|
||||
results = insertResult(results, response, "62", "Reserved for future use", "x_future_62", "");
|
||||
results = insertResult(results, response, "63", "Reserved for future use", "x_future_63", "");
|
||||
results = insertResult(results, response, "64", "Reserved for future use", "x_future_64", "");
|
||||
results = insertResult(results, response, "65", "Reserved for future use", "x_future_65", "");
|
||||
results = insertResult(results, response, "66", "Reserved for future use", "x_future_66", "");
|
||||
results = insertResult(results, response, "67", "Reserved for future use", "x_future_67", "");
|
||||
results = insertResult(results, response, "68", "Reserved for future use", "x_future_68", "");*/
|
||||
results = insertResult(results, response, "69", "Merchant defined value", "x_merchant_69", "");
|
||||
results = insertResult(results, response, "70", "Merchant defined value", "x_merchant_70", "");
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Helper function for parseResponse();
|
||||
function insertResult(results, response, listPosition, FieldName, fieldKey, defaultValue) {
|
||||
var value = arguments.defaultValue;
|
||||
|
||||
if (arrayLen(arguments.response) GTE arguments.listPosition AND len(arguments.response[arguments.listPosition]))
|
||||
value = arguments.response[arguments.listPosition];
|
||||
|
||||
if (len(arguments.fieldKey)) {
|
||||
if (structKeyExists(arguments.results, arguments.fieldKey))
|
||||
structInsert(arguments.results, "#arguments.fieldKey##arguments.listPosition#", value);
|
||||
else
|
||||
structInsert(arguments.results, "#arguments.fieldKey#", value);
|
||||
}
|
||||
else if (len(arguments.FieldName)) {
|
||||
if (structKeyExists(arguments.results, arguments.FieldName))
|
||||
structInsert(arguments.results, "#arguments.FieldName##arguments.listPosition#", value);
|
||||
else
|
||||
structInsert(arguments.results, "#arguments.FieldName#", value);
|
||||
}
|
||||
return arguments.results;
|
||||
}
|
||||
|
||||
// Helper function for addResponseReasonCodes();
|
||||
function addResponseReasonCode(respCode, respReasonCode, respReasonText, notes) {
|
||||
var resp = structNew();
|
||||
structInsert(resp, "respCode", arguments.respCode);
|
||||
structInsert(resp, "respReasonCode", arguments.respReasonCode);
|
||||
structInsert(resp, "respReasonText", arguments.respReasonText);
|
||||
structInsert(resp, "notes", arguments.notes);
|
||||
|
||||
structInsert(variables.authorizenet.respReasonCodes, arguments.respReasonCode, resp, "no");
|
||||
|
||||
return variables.authorizenet.respReasonCodes;
|
||||
}
|
||||
|
||||
function getResponseReasonCode(respReasonCode) {
|
||||
var resp = structNew();
|
||||
if (structKeyExists(variables.authorizenet.respReasonCodes, arguments.respReasonCode)) {
|
||||
resp = variables.authorizenet.respReasonCodes[arguments.respReasonCode];
|
||||
}
|
||||
else {
|
||||
structInsert(resp, "respCode", "");
|
||||
structInsert(resp, "respReasonCode", "");
|
||||
structInsert(resp, "respReasonText", "");
|
||||
structInsert(resp, "notes", "");
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
// Called when this CFC is created to setup the response code lookup structure.
|
||||
function addResponseReasonCodes() {
|
||||
|
||||
addResponseReasonCode("1", "1", "This transaction has been approved.", "");
|
||||
|
||||
addResponseReasonCode("2", "2", "This transaction has been declined.", "");
|
||||
addResponseReasonCode("2", "3", "This transaction has been declined.", "");
|
||||
addResponseReasonCode("2", "4", "This transaction has been declined.", "The code returned from the processor indicating that the card used needs to be picked up. ");
|
||||
addResponseReasonCode("2", "27", "The transaction resulted in an AVS mismatch. The address provided does not match billing address of cardholder.", "");
|
||||
addResponseReasonCode("2", "41", "This transaction has been declined.", "Only merchants set up for the FraudScreen.Net service would receive this decline. This code will be returned if a given transaction's fraud score is higher than the threshold set by the merchant. ");
|
||||
addResponseReasonCode("2", "44", "This transaction has been declined.", "The merchant would receive this error if the Card Code filter has been set in the Merchant Interface and the transaction received an error code from the processor that matched the rejection criteria set by the merchant. ");
|
||||
addResponseReasonCode("2", "45", "This transaction has been declined.", "This error would be returned if the transaction received a code from the processor that matched the rejection criteria set by the merchant for boththe AVS and Card Code filters. ");
|
||||
addResponseReasonCode("2", "65", "This transaction has been declined.", "The transaction was declined because the merchant configured their account through the Merchant Interface to reject transactions with certain values for a Card Code mismatch. ");
|
||||
addResponseReasonCode("2", "127", "The transaction resulted in an AVS mismatch. The address provided does not match billing address of cardholder.", "The system-generated void for the original AVS-rejected transaction failed. ");
|
||||
addResponseReasonCode("2", "141", "This transaction has been declined.", "The system-generated void for the original FraudScreen-rejected transaction failed. ");
|
||||
addResponseReasonCode("2", "145", "This transaction has been declined.", "The system-generated void for the original card code-rejected and AVS-rejected transaction failed. ");
|
||||
addResponseReasonCode("2", "165", "This transaction has been declined.", "The system-generated void for the original card code-rejected transaction failed. ");
|
||||
addResponseReasonCode("2", "200", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The credit card number is invalid. ");
|
||||
addResponseReasonCode("2", "201", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The expiration date is invalid. ");
|
||||
addResponseReasonCode("2", "202", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The transaction type is invalid. ");
|
||||
addResponseReasonCode("2", "203", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The value submitted in the amount field is invalid. ");
|
||||
addResponseReasonCode("2", "204", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The department code is invalid. ");
|
||||
addResponseReasonCode("2", "205", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The value submitted in the merchant number field is invalid. ");
|
||||
addResponseReasonCode("2", "206", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The merchant is not on file. ");
|
||||
addResponseReasonCode("2", "207", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The merchant account is closed. ");
|
||||
addResponseReasonCode("2", "208", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The merchant is not on file. ");
|
||||
addResponseReasonCode("2", "209", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. Communication with the processor could not be established.");
|
||||
addResponseReasonCode("2", "210", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The merchant type is incorrect. ");
|
||||
addResponseReasonCode("2", "211", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The cardholder is not on file. ");
|
||||
addResponseReasonCode("2", "212", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The bank configuration is not on file ");
|
||||
addResponseReasonCode("2", "213", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The merchant assessment code is incorrect. ");
|
||||
addResponseReasonCode("2", "214", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. This function is currently unavailable. ");
|
||||
addResponseReasonCode("2", "215", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The encrypted PIN field format is invalid. ");
|
||||
addResponseReasonCode("2", "216", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The ATM term ID is invalid. ");
|
||||
addResponseReasonCode("2", "217", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. This transaction experienced a general message format problem. ");
|
||||
addResponseReasonCode("2", "218", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The PIN block format or PIN availability value is invalid. ");
|
||||
addResponseReasonCode("2", "219", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The ETC void is unmatched. ");
|
||||
addResponseReasonCode("2", "220", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The primary CPU is not available. ");
|
||||
addResponseReasonCode("2", "221", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. The SE number is invalid. ");
|
||||
addResponseReasonCode("2", "222", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. Duplicate auth request (from INAS). ");
|
||||
addResponseReasonCode("2", "223", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. This transaction experienced an unspecified error. ");
|
||||
addResponseReasonCode("2", "224", "This transaction has been declined.", "This error code applies only to merchants on FDC Omaha. Please re-enter the transaction. ");
|
||||
addResponseReasonCode("2", "250", "This transaction has been declined.", "This transaction was submitted from a blocked IP address. ");
|
||||
addResponseReasonCode("2", "251", "This transaction has been declined.", "The transaction was declined as a result of triggering a Fraud Detection Suite filter. ");
|
||||
addResponseReasonCode("2", "254", "Your transaction has been declined.", "The transaction was declined after manual review. ");
|
||||
|
||||
|
||||
addResponseReasonCode("3", "5", "A valid amount is required.", "The value submitted in the amount field did not pass validation for a number. ");
|
||||
addResponseReasonCode("3", "6", "The credit card number is invalid.", "");
|
||||
addResponseReasonCode("3", "7", "The credit card expiration date is invalid.", "The format of the date submitted was incorrect. ");
|
||||
addResponseReasonCode("3", "8", "The credit card has expired.", "");
|
||||
addResponseReasonCode("3", "9", "The ABA code is invalid.", "The value submitted in the x_bank_aba_code field did not pass validation or was not for a valid financial institution. ");
|
||||
addResponseReasonCode("3", "10", "The account number is invalid.", "The value submitted in the x_bank_acct_num field did not pass validation. ");
|
||||
addResponseReasonCode("3", "11", "A duplicate transaction has been submitted.", "A transaction with identical amount and credit card information was submitted two minutes prior. ");
|
||||
addResponseReasonCode("3", "12", "An authorization code is required but not present.", "A transaction that required x_auth_code to be present was submitted without a value. ");
|
||||
addResponseReasonCode("3", "13", "The merchant Login ID is invalid or the account is inactive.", "");
|
||||
addResponseReasonCode("3", "14", "The Referrer or Relay Response URL is invalid.", "Applicable only to SIM and WebLink APIs. The Relay Response or Referrer URL does not matchthe merchant's configured value(s) or is absent. ");
|
||||
addResponseReasonCode("3", "15", "The transaction ID is invalid.", "The transaction ID value is non-numeric or was not present for a transaction that requires it (i.e., VOID, PRIOR_AUTH_CAPTURE, and CREDIT). ");
|
||||
addResponseReasonCode("3", "16", "The transaction was not found.", "The transaction ID sent in was properly formatted but the gateway had no record of the transaction. ");
|
||||
addResponseReasonCode("3", "17", "The merchant does not accept this type of credit card.", "The merchant was not configured to accept the credit card submitted in the transaction. ");
|
||||
addResponseReasonCode("3", "18", "ACH transactions are not accepted by this merchant.", "The merchant does not accept electronic checks. ");
|
||||
addResponseReasonCode("3", "19", "An error occurred during processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "20", "An error occurred during processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "21", "An error occurred during processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "22", "An error occurred during processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "23", "An error occurred during processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "24", "The Nova Bank Number or Terminal ID is incorrect. Call Merchant Service Provider.", "");
|
||||
addResponseReasonCode("3", "25", "An error occurred during processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "26", "An error occurred during processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "28", "The merchant does not accept this type of credit card.", "The Merchant ID at the processor was not configured to accept this card type. ");
|
||||
addResponseReasonCode("3", "29", "The PaymentTech identification numbers are incorrect. Call Merchant Service Provider.", "");
|
||||
addResponseReasonCode("3", "30", "The configuration with the processor is invalid. Call Merchant Service Provider.", "");
|
||||
addResponseReasonCode("3", "31", "The FDC Merchant ID or Terminal ID is incorrect. Call Merchant Service Provider.", "The merchant was incorrectly set up at the processor. ");
|
||||
addResponseReasonCode("3", "32", "This reason code is reserved or not applicable to this API.", "");
|
||||
addResponseReasonCode("3", "33", "FIELD cannot be left blank.", "The word FIELD will be replaced by an actual field name. This error indicates that a field the merchant specified as required was not filled in.");
|
||||
addResponseReasonCode("3", "34", "The VITAL identification numbers are incorrect. Call Merchant Service Provider.", "The merchant was incorrectly set up at the processor. ");
|
||||
addResponseReasonCode("3", "35", "An error occurred during processing. Call Merchant Service Provider.", "The merchant was incorrectly set up at the processor. ");
|
||||
addResponseReasonCode("3", "36", "The authorization was approved, but settlement failed.", "");
|
||||
addResponseReasonCode("3", "37", "The credit card number is invalid.", "");
|
||||
addResponseReasonCode("3", "38", "The Global Payment System identification numbers are incorrect. Call Merchant Service Provider.", "The merchant was incorrectly set up at the processor. ");
|
||||
addResponseReasonCode("3", "39", "The supplied currency code is either invalid, not supported, not allowed for this merchant or doesn't have an exchange rate.", "");
|
||||
addResponseReasonCode("3", "40", "This transaction must be encrypted.", "");
|
||||
addResponseReasonCode("3", "43", "The merchant was incorrectly set up at the processor. Call your Merchant Service Provider.", "The merchant was incorrectly set up at the processor. ");
|
||||
addResponseReasonCode("3", "46", "Your session has expired or does not exist. You must log in to continue working.", "");
|
||||
addResponseReasonCode("3", "47", "The amount requested for settlement may not be greater than the original amount authorized.", "This occurs if the merchant tries to capture fundsgreater than the amount of the original authorization-only transaction. ");
|
||||
addResponseReasonCode("3", "48", "This processor does not accept partial reversals.", "The merchant attempted to settle for less than the originally authorized amount. ");
|
||||
addResponseReasonCode("3", "49", "A transaction amount greater than $99,999 will not be accepted.", "");
|
||||
addResponseReasonCode("3", "50", "This transaction is awaiting settlement and cannot be refunded.", "Credits or refunds may only be performed against settled transactions. The transaction against which the credit/refund was submitted has not been settled, so a credit cannot be issued.");
|
||||
addResponseReasonCode("3", "51", "The sum of all credits against this transaction is greater than the original transaction amount.", "");
|
||||
addResponseReasonCode("3", "52", "The transaction was authorized, but the client could not be notified; the transaction will not be settled.", "");
|
||||
addResponseReasonCode("3", "53", "The transaction type was invalid for ACH transactions.", "If x_method = ECHECK, x_type cannot be set to CAPTURE_ONLY. ");
|
||||
addResponseReasonCode("3", "54", "The referenced transaction does not meet the criteria for issuing a credit.", "");
|
||||
addResponseReasonCode("3", "55", "The sum of credits against the referenced transaction would exceed the original debit amount.", "The transaction is rejected if the sum of this credit and prior credits exceeds the original debitamount. ");
|
||||
addResponseReasonCode("3", "56", "This merchant accepts ACH transactions only; no credit card transactions are accepted.", "The merchant processes eCheck.Net transactionsonly and does not accept credit cards. ");
|
||||
addResponseReasonCode("3", "57", "An error occurred in processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "58", "An error occurred in processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "59", "An error occurred in processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "60", "An error occurred in processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "61", "An error occurred in processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "62", "An error occurred in processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "63", "An error occurred in processing. Please try again in 5 minutes.", "");
|
||||
addResponseReasonCode("3", "66", "This transaction cannot be accepted for processing.", "The transaction did not meet gateway security guidelines. ");
|
||||
addResponseReasonCode("3", "68", "The version parameter is invalid.", "The value submitted in x_version was invalid. ");
|
||||
addResponseReasonCode("3", "69", "The transaction type is invalid.", "The value submitted in x_type was invalid. ");
|
||||
addResponseReasonCode("3", "70", "The transaction method is invalid.", "The value submitted in x_method was invalid. ");
|
||||
addResponseReasonCode("3", "71", "The bank account type is invalid.", "The value submitted in x_bank_acct_type was invalid. ");
|
||||
addResponseReasonCode("3", "72", "The authorization code is invalid.", "The value submitted in x_auth_code was more than six characters in length. ");
|
||||
addResponseReasonCode("3", "73", "The driver's license date of birth is invalid.", "The format of the value submitted in x_drivers_license_num was invalid. ");
|
||||
addResponseReasonCode("3", "74", "The duty amount is invalid.", "The value submitted in x_duty failed format validation. ");
|
||||
addResponseReasonCode("3", "75", "The freight amount is invalid.", "The value submitted in x_freight failed format validation. ");
|
||||
addResponseReasonCode("3", "76", "The tax amount is invalid.", "The value submitted in x_tax failed format validation. ");
|
||||
addResponseReasonCode("3", "77", "The SSN or tax ID is invalid.", "The value submitted in x_customer_tax_id failedvalidation. ");
|
||||
addResponseReasonCode("3", "78", "The card code (CVV2/CVC2/CID) is invalid.", "The value submitted in x_card_code failed format validation. ");
|
||||
addResponseReasonCode("3", "79", "The driver's license number is invalid.", "The value submitted in x_drivers_license_num failed format validation. ");
|
||||
addResponseReasonCode("3", "80", "The driver's license state is invalid.", "The value submitted in x_drivers_license_state failed format validation. ");
|
||||
addResponseReasonCode("3", "81", "The requested form type is invalid.", "The merchant requested an integration method not compatible with the AIM API. ");
|
||||
addResponseReasonCode("3", "82", "Scripts are only supported in version 2.5.", "The system no longer supports version 2.5; requests cannot be posted to scripts. ");
|
||||
addResponseReasonCode("3", "83", "The requested script is either invalid or no longer supported.", "The system no longer supports version 2.5; requests cannot be posted to scripts.");
|
||||
addResponseReasonCode("3", "84", "This reason code is reserved or not applicable to this API.", "");
|
||||
addResponseReasonCode("3", "85", "This reason code is reserved or not applicable to this API.", "");
|
||||
addResponseReasonCode("3", "86", "This reason code is reserved or not applicable to this API.", "");
|
||||
addResponseReasonCode("3", "87", "This reason code is reserved or not applicable to this API.", "");
|
||||
addResponseReasonCode("3", "88", "This reason code is reserved or not applicable to this API.", "");
|
||||
addResponseReasonCode("3", "89", "This reason code is reserved or not applicable to this API.", "");
|
||||
addResponseReasonCode("3", "90", "This reason code is reserved or not applicable to this API.", "");
|
||||
addResponseReasonCode("3", "91", "Version 2.5 is no longer supported.", "");
|
||||
addResponseReasonCode("3", "92", "The gateway no longer supports the requested method of integration.", "");
|
||||
addResponseReasonCode("3", "97", "This transaction cannot be accepted.", "Applicable only to SIM API. Fingerprints are only valid for a short period of time. This code indicates that the transaction fingerprint has expired. ");
|
||||
addResponseReasonCode("3", "98", "This transaction cannot be accepted.", "Applicable only to SIM API. The transaction fingerprint has already been used. ");
|
||||
addResponseReasonCode("3", "99", "This transaction cannot be accepted.", "Applicable only to SIM API. The server-generated fingerprint does not match the merchant-specified fingerprint in the x_fp_hash field. ");
|
||||
addResponseReasonCode("3", "100", "The eCheck.Net type is invalid.", "Applicable only to eCheck.Net. The value specified in the x_echeck_type field is invalid. ");
|
||||
addResponseReasonCode("3", "101", "The given name on the account and/or the account type does not match the actual account.", "Applicable only to eCheck.Net. The specified name on the account and/or the account type do not match the NOC record for this account. ");
|
||||
addResponseReasonCode("3", "102", "This request cannot be accepted. ", "A transaction key was submitted with this WebLink request. ");
|
||||
addResponseReasonCode("3", "103", "This transaction cannot be accepted.", "A valid fingerprint, or transaction key is requiredfor this transaction. ");
|
||||
addResponseReasonCode("3", "104", "This transaction is currently under review.", "Applicable only to eCheck.Net. The value submitted for country failed validation. ");
|
||||
addResponseReasonCode("3", "105", "This transaction is currently under review.", "Applicable only to eCheck.Net. The values submitted for city and country failed validation. ");
|
||||
addResponseReasonCode("3", "106", "This transaction is currently under review.", "Applicable only to eCheck.Net. The value submitted for company failed validation. ");
|
||||
addResponseReasonCode("3", "107", "This transaction is currently under review.", "Applicable only to eCheck.Net. The value submitted for bank account name failed validation. ");
|
||||
addResponseReasonCode("3", "108", "This transaction is currently under review.", "Applicable only to eCheck.Net. The values submitted for first name and last name failed validation. ");
|
||||
addResponseReasonCode("3", "109", "This transaction is currently under review.", "Applicable only to eCheck.Net. The values submitted for first name and last name failed validation. ");
|
||||
addResponseReasonCode("3", "110", "This transaction is currently under review.", "The value submitted for bank account name doesnot contain valid characters. ");
|
||||
addResponseReasonCode("3", "116", "The authentication indicator is invalid.", "This code is applicable only to merchants that include the x_authentication_indicator in the transaction request. The ECI value for a Visa transaction; or the UCAF indicator for a MasterCard transaction submitted in the x_authentication_indicator field is invalid. ");
|
||||
addResponseReasonCode("3", "117", "The cardholder authentication value is invalid.", "This code is applicable only to merchants that include the x_cardholder_authentication_value in the transaction request. The CAVV for a Visa transaction; or the AVV/UCAF for a MasterCardtransaction is invalid. ");
|
||||
addResponseReasonCode("3", "118", "The combination of authentication indicator and cardholder authentication value is invalid.", "This code is applicable only to merchants that include the x_authentication_indicator and x_authentication_value in the transaction request. The combination of authentication indicator and cardholder authentication value for a Visa or MasterCard transaction is invalid. ");
|
||||
addResponseReasonCode("3", "119", "Transactions having cardholder authentication values cannot be marked as recurring.", "This code is applicable only to merchants that include the x_authentication_indicator and x_recurring_billing in the transaction request. Transactions submitted with a value in x_authentication_indicator AND x_recurring_billing =YES will be rejected. ");
|
||||
addResponseReasonCode("3", "120", "An error occurred during processing. Please try again.", "The system-generated void for the original timed-out transaction failed. (The original transaction timed out while waiting for a response from the authorizer.) ");
|
||||
addResponseReasonCode("3", "121", "An error occurred during processing. Please try again.", "The system-generated void for the original errored transaction failed. (The original transaction experienced a database error.) ");
|
||||
addResponseReasonCode("3", "122", "An error occurred during processing. Please try again.", "The system-generated void for the original errored transaction failed. (The original transaction experienced a processing error.) ");
|
||||
addResponseReasonCode("3", "128", "This transaction cannot be processed.", "The customer's financial institution does not currently allow transactions for this account. ");
|
||||
addResponseReasonCode("3", "152", "The transaction was authorized, but the client could not be notified; the transaction will not be settled.", "The system-generated void for the original transaction failed. The response for the original transaction could not be communicated to the client. ");
|
||||
addResponseReasonCode("3", "170", "An error occurred during processing. Please contact the merchant.", "Concord EFS ' Provisioning at the processor hasnot been completed. ");
|
||||
addResponseReasonCode("3", "171", "An error occurred during processing. Please contact the merchant.", "Concord EFS ' This request is invalid. ");
|
||||
addResponseReasonCode("3", "172", "An error occurred during processing. Please contact the merchant.", "Concord EFS ' The store ID is invalid. ");
|
||||
addResponseReasonCode("3", "173", "An error occurred during processing. Please contact the merchant.", "Concord EFS ' The store key is invalid. ");
|
||||
addResponseReasonCode("3", "174", "The transaction type is invalid. Please contact the merchant.", "Concord EFS ' This transaction type is not accepted by the processor. ");
|
||||
addResponseReasonCode("3", "175", "The processor does not allow voiding of credits.", "Concord EFS ' This transaction is not allowed. The Concord EFS processing platform does not support voiding credit transactions. Please debit the credit card instead of voiding the credit. ");
|
||||
addResponseReasonCode("3", "180", "An error occurred during processing. Please try again.", "The processor response format is invalid. ");
|
||||
addResponseReasonCode("3", "181", "An error occurred during processing. Please try again.", "The system-generated void for the original invalid transaction failed. (The original transaction included an invalid processor response format.) ");
|
||||
addResponseReasonCode("3", "185", "This reason code is reserved or not applicable to this API.", "");
|
||||
addResponseReasonCode("3", "243", "Recurring billing is not allowed for this eCheck.Net type.", "The combination of values submitted for x_recurring_billing and x_echeck_type is not allowed. ");
|
||||
addResponseReasonCode("3", "244", "This eCheck.Net type is not allowed for this Bank Account Type.", "The combination of values submitted for x_bank_acct_type and x_echeck_type is not allowed. ");
|
||||
addResponseReasonCode("3", "245", "This eCheck.Net type is not allowed when using the payment gateway hosted payment form.", "The value submitted for x_echeck_type is not allowed when using the payment gateway hostedpayment form. ");
|
||||
addResponseReasonCode("3", "246", "This eCheck.Net type is not allowed.", "The merchant's payment gateway account is not enabled to submit the eCheck.Net type. ");
|
||||
addResponseReasonCode("3", "247", "This eCheck.Net type is not allowed.", "The combination of values submitted for x_type and x_echeck_type is not allowed. ");
|
||||
addResponseReasonCode("3", "261", "An error occurred during processing. Please try again.", "The transaction experienced an error during sensitive data encryption and was not processed. Please try again. ");
|
||||
addResponseReasonCode("3", "270", "The line item [item number] is invalid.", "A value submitted in x_line_item for the item referenced is invalid. ");
|
||||
addResponseReasonCode("3", "271", "The number of line items submitted is not allowed. A maximum of 30 line items can be submitted.", "The number of line items submitted in x_line_item exceeds the allowed maximum of 30. ");
|
||||
|
||||
|
||||
addResponseReasonCode("4", "193", "The transaction is currently under review.", "The transaction was placed under review by the risk management system. ");
|
||||
addResponseReasonCode("4", "252", "Your order has been received. Thank you for your business!", "The transaction was accepted, but is being held for merchant review. The merchant may customize the customer response in the Merchant Interface. ");
|
||||
addResponseReasonCode("4", "253", "Your order has been received. Thank you for your business!", "The transaction was accepted and was authorized, but is being held for merchant review. The merchant may customize the customer response in the Merchant Interface. ");
|
||||
}
|
||||
|
||||
// Coyright Jonah Blossom (info@creori.com)
|
||||
// Helper function for parseResponse();
|
||||
function listToArrayInclEmpty(list) {
|
||||
var delim = iif(arrayLen(arguments) gt 1, de("#arguments[2]#"), de(","));
|
||||
|
||||
var strlen = len(arguments.list);
|
||||
var ary = arrayNew(1);
|
||||
var i = 0;
|
||||
var p = 1;
|
||||
|
||||
arguments.list = arguments.list & delim;
|
||||
|
||||
while(i LTE strlen) {
|
||||
i = i + 1;
|
||||
l = find(delim, arguments.list, i);
|
||||
if (l) {
|
||||
arrayAppend(ary, mid(arguments.list, i, l - i));
|
||||
i = l;
|
||||
}
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
</cfscript>
|
||||
</cfcomponent>
|
||||
921
cfpayment/api/gateway/authorizenet/authorizenet2016.cfc
Normal file
921
cfpayment/api/gateway/authorizenet/authorizenet2016.cfc
Normal file
|
|
@ -0,0 +1,921 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is a updated implementation of the authorize.net API.
|
||||
See:
|
||||
http://developer.authorize.net/api/reference/index.html
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
component
|
||||
extends="cfpayment.api.gateway.base"
|
||||
displayname="Authorize.net AIM Interface"
|
||||
hint="Authorize.net Gateway see http://developer.authorize.net/api/reference/"
|
||||
|
||||
{
|
||||
|
||||
|
||||
variables.cfpayment.GATEWAY_NAME = "Authorize.net";
|
||||
variables.cfpayment.GATEWAY_VERSION = "4.0";
|
||||
|
||||
// The test URL requires a separate developer transKey and login
|
||||
// Request a developer account here: http://developer.authorize.net/testaccount/
|
||||
variables.cfpayment.GATEWAY_TEST_URL = "https://apitest.authorize.net/xml/v1/request.api";
|
||||
variables.cfpayment.GATEWAY_LIVE_URL = "https://api.authorize.net/xml/v1/request.api";
|
||||
|
||||
/**
|
||||
Check that the credentials are correct
|
||||
*/
|
||||
public boolean function hasValidCredentials(){
|
||||
//Should do a purchase with a test card
|
||||
var expDate = dateAdd("m", randRange(1, 20), Now());
|
||||
var money = getService().createMoney(5000);
|
||||
var account = getService().createCreditCard();
|
||||
account.setAccount("4111111111111111");
|
||||
account.setMonth(Month(expDate));
|
||||
account.setYear(Year(expDate));
|
||||
account.setVerificationValue(900);
|
||||
|
||||
var options = {
|
||||
"refId": getTickCount() //Authorize.net requires a unique order id for each transaction.
|
||||
};
|
||||
|
||||
var ret = purchase(money=money,account=account,options=options);
|
||||
|
||||
//Make sure it's just the credentials
|
||||
|
||||
|
||||
if(ret.getMessageText() EQ "User authentication failed due to invalid authentication values."){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ret.getMessageCode() EQ "E00007"){
|
||||
return false;
|
||||
}
|
||||
|
||||
//There could be other errors but we are ignoring it
|
||||
|
||||
return true;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// private any function createValidCard(svc, card="4111111111111111", CVV=900, expDate=dateAdd("m", randRange(1, 20), Now()), ZipCode=46201){
|
||||
//
|
||||
// var account = svc.createCreditCard();
|
||||
// account.setAccount(card);
|
||||
// account.setMonth(Month(expDate));
|
||||
// account.setYear(Year(expDate));
|
||||
// account.setVerificationValue(CVV);
|
||||
// account.setFirstName("John");
|
||||
// account.setLastName("Doe");
|
||||
// account.setAddress(getTickCount() & " Boulevard Road"); //Hopefully avoids duplicate transaction errors
|
||||
// account.setPostalCode(ZipCode);
|
||||
// return account;
|
||||
// }
|
||||
|
||||
function purchase(required Any money, Any account=nullValue(), Any customer=nullValue(), Any paymentProfile=nullValue(), Struct options={}){
|
||||
|
||||
//we either need an account (ergo a creditcard) OR a (customer and payment profile)
|
||||
|
||||
if(!isNull(account)){
|
||||
if(lcase(listLast(getMetaData(arguments.account).fullname, ".")) NEQ "creditcard"){
|
||||
throw("The account type #lcase(listLast(getMetaData(arguments.account).fullname, "."))# is not supported by this gateway.", "", "cfpayment.InvalidAccount");
|
||||
}
|
||||
}
|
||||
|
||||
if(isNull(account) && isNull(customer) && isNull(paymentProfile)){
|
||||
throw("Either a creditcard/account is needed or a customer and payment profile. None of these have been passed in");
|
||||
}
|
||||
//need a refID presume?
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
|
||||
var argumentColls = {
|
||||
"transactionType" : "authCaptureTransaction",
|
||||
"merchantAuthentication" : getMerchantAuthentication(),
|
||||
"money" : arguments.money,
|
||||
"options" : arguments.options,
|
||||
"paymentProfile": arguments.paymentProfile
|
||||
};
|
||||
|
||||
if(!IsNull(account)){
|
||||
argumentColls["account"] = account;
|
||||
}
|
||||
|
||||
if(!IsNull(customer)){
|
||||
argumentColls["customer"] = customer;
|
||||
}
|
||||
|
||||
var payload = RequestXMLProcessor.createTransactionRequest(
|
||||
argumentCollection=argumentColls
|
||||
);
|
||||
|
||||
|
||||
var results = {};
|
||||
|
||||
//Now go and process it
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
var resp = new transactionResponse(argumentCollection=result);
|
||||
|
||||
|
||||
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
function function canSwipe(){
|
||||
return false;
|
||||
}
|
||||
|
||||
function authorize(required Any money, Any requred account, Struct options={}){
|
||||
if(lcase(listLast(getMetaData(arguments.account).fullname, ".")) NEQ "creditcard"){
|
||||
throw("The account type #lcase(listLast(getMetaData(arguments.account).fullname, "."))# is not supported by this gateway.", "", "cfpayment.InvalidAccount");
|
||||
}
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createTransactionRequest(
|
||||
transactionType="authOnlyTransaction",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
money=arguments.money,
|
||||
account=account,
|
||||
options=options);
|
||||
|
||||
//Now go and process it
|
||||
var result = super.process(payload = payload);
|
||||
var resp = createResponse(argumentCollection=result);
|
||||
|
||||
// do some meta-checks for gateway-level errors (as opposed to auth/decline errors)
|
||||
if (NOT resp.hasError()) {
|
||||
|
||||
// we need to have a result; otherwise that's an error in itself
|
||||
if (len(resp.getResult())) {
|
||||
var xmlResponse = XMLParse(resp.getResult());
|
||||
resp.setParsedResult(xmlResponse);
|
||||
|
||||
//Successful response, deal with the actual codes.
|
||||
var hasTransactionResponse = structKeyExists(xmlResponse, "createTransactionResponse") && structKeyExists(xmlResponse.createTransactionResponse, "transactionResponse");
|
||||
|
||||
var hasErrorRsponse = structKeyExists(xmlResponse, "ErrorResponse");
|
||||
|
||||
if(hasTransactionResponse){
|
||||
processTransactionResponse(xmlResponse, resp);
|
||||
}
|
||||
|
||||
else if(hasErrorRsponse) {
|
||||
|
||||
processErrorResponse(xmlResponse, resp);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
resp.setStatus(getService().getStatusUnknown()); // Authorize.net didn't return a response
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (resp.getStatus() EQ getService().getStatusSuccessful()) {
|
||||
result["result"] = "CAPTURED";
|
||||
}
|
||||
else if (resp.getStatus() EQ getService().getStatusDeclined()) {
|
||||
result["result"] = "NOT CAPTURED";
|
||||
|
||||
}
|
||||
else {
|
||||
result["result"] = "ERROR";
|
||||
|
||||
}
|
||||
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
function capture(required Any money, String required authorization, Struct options={}){
|
||||
options.refTransID = authorization;
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createTransactionRequest(
|
||||
transactionType="priorAuthCaptureTransaction",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
money=money,
|
||||
account=nullValue(),
|
||||
options=options);
|
||||
var result = super.process(payload = payload);
|
||||
var resp = createResponse(argumentCollection=result);
|
||||
|
||||
// do some meta-checks for gateway-level errors (as opposed to auth/decline errors)
|
||||
if (NOT resp.hasError()) {
|
||||
|
||||
// we need to have a result; otherwise that's an error in itself
|
||||
if (len(resp.getResult())) {
|
||||
var xmlResponse = XMLParse(resp.getResult());
|
||||
resp.setParsedResult(xmlResponse);
|
||||
|
||||
//Successful response, deal with the actual codes.
|
||||
var hasTransactionResponse = structKeyExists(xmlResponse, "createTransactionResponse") && structKeyExists(xmlResponse.createTransactionResponse, "transactionResponse");
|
||||
|
||||
var hasErrorRsponse = structKeyExists(xmlResponse, "ErrorResponse");
|
||||
|
||||
if(hasTransactionResponse){
|
||||
processTransactionResponse(xmlResponse, resp);
|
||||
}
|
||||
|
||||
else if(hasErrorRsponse) {
|
||||
|
||||
processErrorResponse(xmlResponse, resp);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
resp.setStatus(getService().getStatusUnknown()); // Authorize.net didn't return a response
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (resp.getStatus() EQ getService().getStatusSuccessful()) {
|
||||
result["result"] = "CAPTURED";
|
||||
}
|
||||
else if (resp.getStatus() EQ getService().getStatusDeclined()) {
|
||||
result["result"] = "NOT CAPTURED";
|
||||
|
||||
}
|
||||
else {
|
||||
result["result"] = "ERROR";
|
||||
|
||||
}
|
||||
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
function credit(Any required transactionID, Any required money, Any requred account, Struct options={}) {
|
||||
|
||||
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createTransactionRequest(
|
||||
transactionType="refundTransaction",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
money=money,
|
||||
account=account,
|
||||
options=options);
|
||||
var result = super.process(payload = payload);
|
||||
var resp = createResponse(argumentCollection=result);
|
||||
|
||||
// do some meta-checks for gateway-level errors (as opposed to auth/decline errors)
|
||||
if (NOT resp.hasError()) {
|
||||
|
||||
// we need to have a result; otherwise that's an error in itself
|
||||
if (len(resp.getResult())) {
|
||||
var xmlResponse = XMLParse(resp.getResult());
|
||||
resp.setParsedResult(xmlResponse);
|
||||
|
||||
//Successful response, deal with the actual codes.
|
||||
var hasTransactionResponse = structKeyExists(xmlResponse, "createTransactionResponse") && structKeyExists(xmlResponse.createTransactionResponse, "transactionResponse");
|
||||
|
||||
var hasErrorRsponse = structKeyExists(xmlResponse, "ErrorResponse");
|
||||
|
||||
if(hasTransactionResponse){
|
||||
processTransactionResponse(xmlResponse, resp);
|
||||
}
|
||||
|
||||
else if(hasErrorRsponse) {
|
||||
|
||||
processErrorResponse(xmlResponse, resp);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
resp.setStatus(getService().getStatusUnknown()); // Authorize.net didn't return a response
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (resp.getStatus() EQ getService().getStatusSuccessful()) {
|
||||
result["result"] = "REFUNDED";
|
||||
}
|
||||
else if (resp.getStatus() EQ getService().getStatusDeclined()) {
|
||||
result["result"] = "NOT REFUNDED";
|
||||
|
||||
}
|
||||
else {
|
||||
result["result"] = "ERROR";
|
||||
|
||||
}
|
||||
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
function void(Any required transactionID, Struct options={}) {
|
||||
|
||||
options.refTransID = transactionID;
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createTransactionRequest(
|
||||
transactionType="voidTransaction",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
money=nullValue(),
|
||||
account=nullValue(),
|
||||
options=options);
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
var resp = createResponse(argumentCollection=result);
|
||||
|
||||
// do some meta-checks for gateway-level errors (as opposed to auth/decline errors)
|
||||
if (NOT resp.hasError()) {
|
||||
|
||||
// we need to have a result; otherwise that's an error in itself
|
||||
if (len(resp.getResult())) {
|
||||
var xmlResponse = XMLParse(resp.getResult());
|
||||
resp.setParsedResult(xmlResponse);
|
||||
|
||||
//Successful response, deal with the actual codes.
|
||||
var hasTransactionResponse = structKeyExists(xmlResponse, "createTransactionResponse") && structKeyExists(xmlResponse.createTransactionResponse, "transactionResponse");
|
||||
|
||||
var hasErrorRsponse = structKeyExists(xmlResponse, "ErrorResponse");
|
||||
|
||||
if(hasTransactionResponse){
|
||||
processTransactionResponse(xmlResponse, resp);
|
||||
}
|
||||
|
||||
else if(hasErrorRsponse) {
|
||||
|
||||
processErrorResponse(xmlResponse, resp);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
resp.setStatus(getService().getStatusUnknown()); // Authorize.net didn't return a response
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (resp.getStatus() EQ getService().getStatusSuccessful()) {
|
||||
result["result"] = "VOIDED";
|
||||
}
|
||||
else if (resp.getStatus() EQ getService().getStatusDeclined()) {
|
||||
result["result"] = "NOT VOIDED";
|
||||
|
||||
}
|
||||
else {
|
||||
result["result"] = "ERROR";
|
||||
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
//shortcut to storeCustomer
|
||||
function store(){
|
||||
return storeCustomer(argumentCollection=arguments);
|
||||
}
|
||||
|
||||
//shortcut to deleteCustomer
|
||||
function unstore(){
|
||||
return deleteCustomer(argumentCollection=arguments);
|
||||
}
|
||||
|
||||
/*
|
||||
Creates a new customer record
|
||||
*/
|
||||
|
||||
function storeCustomer(required customer) {
|
||||
|
||||
if(!customer.hasValidID()){
|
||||
throw("No valid id defined in customer");
|
||||
}
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="createCustomerProfileRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=customer,
|
||||
options={});
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
|
||||
|
||||
//if there isnt an http error, go and process the response:
|
||||
if (NOT resp.hasError()) {
|
||||
|
||||
|
||||
|
||||
var xmlResponse = XMLParse(resp.getResult());
|
||||
|
||||
var messages = XMLSearch(xmlResponse, "//:messages")[1]; //Should work, always you get a message
|
||||
|
||||
|
||||
|
||||
|
||||
//There should generally always be a messsage
|
||||
resp.setResultCode(messages.resultCode.xmlText);
|
||||
resp.setMessageCode(messages.message.code.xmlText);
|
||||
resp.setMessageText(messages.message.text.xmlText);
|
||||
resp.setMessage(resp.getMessageCode() & ": " & resp.getMessageText());
|
||||
|
||||
|
||||
if(resp.getResultCode() EQ "OK"){
|
||||
//Move this to the constructor of the response
|
||||
var customerID = XMLSearch(xmlResponse, "//:customerProfileId"); //Might not work if it fails right?
|
||||
|
||||
resp.setCustomerProfileId(customerID[1].xmlText);
|
||||
|
||||
var customerPaymentProfileIdList = XMLSearch(xmlResponse, "//:customerPaymentProfileIdList/:numericString");
|
||||
|
||||
//Loop through the xmlChildren
|
||||
for(var ppid in customerPaymentProfileIdList){
|
||||
resp.addCustomerPaymentProfileId(ppid.xmlText);
|
||||
}
|
||||
|
||||
var customerShippingAddressIdList = XMLSearch(xmlResponse, "//:customerShippingAddressIdList/:numericString");
|
||||
|
||||
//Loop through the xmlChildren
|
||||
for(var shipid in customerShippingAddressIdList){
|
||||
resp.addCustomerShippingAddressId(shipid.xmlText);
|
||||
}
|
||||
|
||||
|
||||
var validationDirectResponseList = XMLSearch(xmlResponse, "//:validationDirectResponseList/:string");
|
||||
for(var directResponse in validationDirectResponseList){
|
||||
resp.addvalidationDirectResponse(directResponse.xmlText);
|
||||
}
|
||||
resp.setStatus(getService().getStatusSuccessful());
|
||||
}
|
||||
else {
|
||||
resp.setStatus(getService().getStatusFailure());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
function getCustomer(required customerId) {
|
||||
|
||||
|
||||
//Create a fake customer just for the request:
|
||||
|
||||
var customer = createCustomer();
|
||||
customer.setCustomerProfileId(customerId);
|
||||
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="getCustomerProfileRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=customer,
|
||||
options={});
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
|
||||
if (NOT resp.hasError()) {
|
||||
var xmlResponse = XMLParse(resp.getResult());
|
||||
|
||||
var messages = XMLSearch(xmlResponse, "//:messages")[1]; //Should work, always you get a message
|
||||
|
||||
//There should generally always be a messsage
|
||||
resp.setResultCode(messages.resultCode.xmlText);
|
||||
resp.setMessageCode(messages.message.code.xmlText);
|
||||
resp.setMessageText(messages.message.text.xmlText);
|
||||
resp.setMessage(resp.getMessageCode() & ": " & resp.getMessageText());
|
||||
|
||||
|
||||
if(resp.getResultCode() EQ "OK"){
|
||||
//Parse the thing
|
||||
|
||||
resp.setCustomer(createCustomer().populate(xmlResponse));
|
||||
|
||||
|
||||
|
||||
resp.setStatus(getService().getStatusSuccessful());
|
||||
}
|
||||
else {
|
||||
resp.setStatus(getService().getStatusFailure());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
function listCustomerIds() {
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="getCustomerProfileIdsRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=nullValue(),
|
||||
options={});
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
//Does this actually need a customer response?
|
||||
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
|
||||
|
||||
var ret = resp.getIds();
|
||||
return ret;
|
||||
}
|
||||
|
||||
function updateCustomer(required customer) {
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="updateCustomerProfileRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=customer,
|
||||
options={});
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
//Does this actually need a customer response?
|
||||
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
function deleteCustomer(required customer){
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="deleteCustomerProfileRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=customer,
|
||||
options={});
|
||||
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
function addPaymentProfile(required customer, required paymentProfile){
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="createCustomerPaymentProfileRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=customer,
|
||||
paymentProfile=paymentProfile,
|
||||
options={});
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
function getPaymentProfile(required customerId, required paymentProfileId){
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
|
||||
//Creeate a mock customer and a mock pauyment profile
|
||||
var customer = createCustomer();
|
||||
customer.setCustomerProfileId(customerID);
|
||||
var profile = createPaymentProfile();
|
||||
profile.setCustomerPaymentProfileId(paymentProfileId);
|
||||
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="getCustomerPaymentProfileRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=customer,
|
||||
paymentProfile=profile,
|
||||
options={});
|
||||
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
|
||||
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
function getPaymentProfileList(Date required expiryMonth, string orderBy="id",boolean orderDescending=false,numeric limit=1000,numeric offset=1){
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var search = {
|
||||
"month":DateFormat(expiryMonth, "YYYY-MM"),
|
||||
"sorting": {
|
||||
"orderBy": orderBy,
|
||||
"orderDescending" : orderDescending
|
||||
},
|
||||
"paging": {
|
||||
"limit": limit,
|
||||
"offset": offset
|
||||
}
|
||||
};
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="getCustomerPaymentProfileListRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
search=search
|
||||
);
|
||||
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
function validatePaymentProfile(required customerId, required paymentProfileId){
|
||||
|
||||
var customer = createCustomer();
|
||||
customer.setCustomerProfileId(customerID);
|
||||
var profile = createPaymentProfile();
|
||||
profile.setCustomerPaymentProfileId(paymentProfileId);
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="validateCustomerPaymentProfileRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=customer,
|
||||
paymentProfile=profile,
|
||||
options={});
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
function updatePaymentProfile(required customerId, required paymentProfile){
|
||||
|
||||
var customer = createCustomer();
|
||||
customer.setCustomerProfileId(customerID);
|
||||
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="updateCustomerPaymentProfileRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=customer,
|
||||
paymentProfile=paymentProfile,
|
||||
options={});
|
||||
|
||||
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
function deletePaymentProfile(required customerId, required paymentProfileId){
|
||||
|
||||
var customer = createCustomer();
|
||||
customer.setCustomerProfileId(customerID);
|
||||
var profile = createPaymentProfile();
|
||||
profile.setCustomerPaymentProfileId(paymentProfileId);
|
||||
|
||||
var RequestXMLProcessor = new AuthorizenetXMlRequest(getTestMode());
|
||||
var payload = RequestXMLProcessor.createCustomerRequest(
|
||||
requestType="deleteCustomerPaymentProfileRequest",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=customer,
|
||||
paymentProfile=profile,
|
||||
options={});
|
||||
|
||||
|
||||
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
var resp = new customerResponse(argumentCollection=result);
|
||||
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
PRIVATE FUNCTIONS
|
||||
**/
|
||||
|
||||
private void function processCustomerResponseMessages(respObject, xmlResponse){
|
||||
|
||||
}
|
||||
private customerResponse function createCustomerResponse(XML xmlResponse){
|
||||
|
||||
var resp = new customerResponse();
|
||||
//var messages = XMLSearch(xmlResponse, "//*messages");
|
||||
return resp;
|
||||
}
|
||||
|
||||
public customer function createCustomer(){
|
||||
arguments.service = getService();
|
||||
return new customer(argumentCollection=arguments);
|
||||
}
|
||||
|
||||
public PaymentProfile function createPaymentProfile(){
|
||||
arguments.service = getService();
|
||||
return new PaymentProfile(argumentCollection=arguments);
|
||||
}
|
||||
|
||||
public address function createAddress(){
|
||||
return new address(argumentCollection=arguments);
|
||||
}
|
||||
|
||||
|
||||
private void function processTransactionResponse(XML xmlResponse, Any resultObj){
|
||||
|
||||
var transResponse = xmlResponse.createTransactionResponse.transactionResponse;
|
||||
// handle common response fields
|
||||
if(structKeyExists(transResponse, "responseCode")){
|
||||
resultObj.setMessage(transResponse.responseCode.XMLText);
|
||||
}
|
||||
if (structKeyExists(transResponse, "transId")){
|
||||
resultObj.setTransactionID(transResponse.transId.XMLText);
|
||||
}
|
||||
|
||||
if (structKeyExists(transResponse, "authCode")){
|
||||
resultObj.setAuthorization(transResponse.authCode.XmlText);
|
||||
}
|
||||
// handle common "success" fields
|
||||
if (structKeyExists(transResponse, "avsResultCode")){
|
||||
resultObj.setAVSCode(transResponse.avsResultCode.XmlText);
|
||||
}
|
||||
|
||||
if (structKeyExists(transResponse, "cvvResultCode")){
|
||||
resultObj.setCVVCode(transResponse.cvvResultCode.XmlText);
|
||||
}
|
||||
if (isDefined("transResponse.errors.error.errorText")){
|
||||
resultObj.setMessage(resultObj.getMessage() & ": " & transResponse.errors.error.errorText.XMLText);
|
||||
}
|
||||
|
||||
// see if the response was successful
|
||||
switch (transResponse.responseCode.XmlText) {
|
||||
case "1": {
|
||||
resultObj.setStatus(getService().getStatusSuccessful());
|
||||
break;
|
||||
}
|
||||
case "2": {
|
||||
resultObj.setStatus(getService().getStatusDeclined());
|
||||
break;
|
||||
}
|
||||
case "4": {
|
||||
resultObj.setStatus(5); // On hold (this status value is not currently defined in core.cfc)
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
resultObj.setStatus(getService().getStatusFailure()); // only other known state is 3 meaning, "error in transaction data or system error"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void function processErrorResponse(XML xmlResponse, Any resultObj){
|
||||
|
||||
resultObj.setStatus(getService().getStatusFailure());
|
||||
|
||||
|
||||
resultObj.setMessage("There has been an error");
|
||||
|
||||
|
||||
|
||||
|
||||
if(isDefined("xmlResponse.ErrorResponse.messages.message")){
|
||||
if(structKeyExists(xmlResponse.ErrorResponse.messages.message, "code")){
|
||||
resultObj.setMessage(xmlResponse.ErrorResponse.messages.message.code.xmlText);
|
||||
}
|
||||
if(structKeyExists(xmlResponse.ErrorResponse.messages.message, "text")){
|
||||
resultObj.setMessage(resultObj.getMessage() & ": " & xmlResponse.ErrorResponse.messages.message.text.xmlText);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
@hint: wrapper around the http call
|
||||
*/
|
||||
private Struct function doHttpCall(
|
||||
String required url,
|
||||
String method="GET",
|
||||
numeric required timeout,
|
||||
struct headers={},
|
||||
XML payload={},
|
||||
boolean encoded=true,
|
||||
Struct files={}){
|
||||
|
||||
|
||||
|
||||
var CFHTTP = "";
|
||||
var key = "";
|
||||
var keylist = "";
|
||||
var skey = "";
|
||||
var paramType = "body";
|
||||
|
||||
var ValidMethodTypes = "URL,GET,POST,PUT,DELETE";
|
||||
if(!listFindNoCase(ValidMethodTypes, arguments.method)){
|
||||
throw(message="Invalid Method",type="cfpayment.InvalidParameter.Method");
|
||||
}
|
||||
|
||||
if(arguments.method EQ "URL"){
|
||||
paramType = "url";
|
||||
}
|
||||
|
||||
var PayloadToSend = "";
|
||||
|
||||
var HTTP = new HTTP(url=arguments.url, method=arguments.method, timeout=arguments.timeout, throwonerror="no");
|
||||
|
||||
for(var h in headers){
|
||||
HTTP.addParam(name=h, value=headers[h], type="header");
|
||||
}
|
||||
|
||||
//The actual XML content
|
||||
HTTP.addParam(value=toString(payload), type=paramType);
|
||||
|
||||
for(var f in files){
|
||||
HTTP.addParam(name=f, file=files[f], type="file");
|
||||
}
|
||||
|
||||
var res = HTTP.send();
|
||||
|
||||
return res.getPrefix();
|
||||
}
|
||||
|
||||
/*
|
||||
@hint: intercepts the call so that the result can be parsed nicer-er
|
||||
*/
|
||||
function createResponse(){
|
||||
|
||||
|
||||
|
||||
|
||||
return super.createResponse(argumentCollection=arguments);
|
||||
}
|
||||
|
||||
function getMerchantAuthentication(){
|
||||
return {
|
||||
"name":variables.cfpayment.username,
|
||||
"transactionKey": variables.cfpayment.merchantAccount
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
1126
cfpayment/api/gateway/authorizenet/authorizenet2016_bak.cfc
Normal file
1126
cfpayment/api/gateway/authorizenet/authorizenet2016_bak.cfc
Normal file
File diff suppressed because it is too large
Load diff
97
cfpayment/api/gateway/authorizenet/customer.cfc
Normal file
97
cfpayment/api/gateway/authorizenet/customer.cfc
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is a customer that can be loaded and saved to the authorize.net system
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
component accessors="true" {
|
||||
|
||||
//primary id set by authorise.net
|
||||
property name="customerProfileId" getter="true" setter="true";
|
||||
property name="merchantCustomerId" getter="true" setter="true";
|
||||
property name="description" getter="true" setter="true";
|
||||
property name="email" getter="true" setter="true";
|
||||
property name="service" getter="true" setter="true";
|
||||
|
||||
|
||||
property name="paymentProfiles" type="array" getter="true" setter="true";
|
||||
|
||||
|
||||
function init(service){
|
||||
setService(service);
|
||||
return this;
|
||||
}
|
||||
/*
|
||||
The id can either be merchantCustomerId, description or email, if they are all null then it is not valid
|
||||
*/
|
||||
public boolean function hasValidID(){
|
||||
|
||||
if(!isNull(getMerchantCustomerId()) && !isEmpty(getMerchantCustomerId())){
|
||||
return true;
|
||||
}
|
||||
if(!isNull(getDescription()) && !isEmpty(getDescription())){
|
||||
return true;
|
||||
}
|
||||
if(!isNull(getEmail()) && !isEmpty(getEmail())){
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!isNull(getCustomerProfileId()) && !isEmpty(getCustomerProfileId())){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public customer function populate(XML responseXML){
|
||||
|
||||
|
||||
setMerchantCustomerId(getXMLElementText(responseXML, "merchantCustomerId"));
|
||||
setDescription(getXMLElementText(responseXML, "description"));
|
||||
setEmail(getXMLElementText(responseXML, "email"));
|
||||
setCustomerProfileId(getXMLElementText(responseXML, "customerProfileId"));
|
||||
|
||||
|
||||
//TODO: find out if this is actually correct and we get an array of paymentProfiles back, documentation is lacking at this point:
|
||||
//http://developer.authorize.net/api/reference/#customer-profiles-create-customer-profile
|
||||
|
||||
var paymentProfiles = XMLSearch(responseXML, "//:paymentProfiles");
|
||||
for(var paymentProfile in paymentProfiles){
|
||||
var pp = new paymentProfile(service=getService()).populate(paymentProfile);
|
||||
addPaymentProfile(pp);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private function getXMLElementText(XML responseXML, String elementName, default=""){
|
||||
var searchItem = XMLSearch(responseXML, "//:#elementName#");
|
||||
return ArrayLen(searchItem)?searchItem[1].xmlText : default;
|
||||
}
|
||||
|
||||
public void function addPaymentProfile(PaymentProfile profile){
|
||||
|
||||
var profiles = getPaymentProfiles();
|
||||
profiles = isNull(profiles) ? [] : profiles;
|
||||
|
||||
profiles.append(profile);
|
||||
setPaymentProfiles(profiles);
|
||||
}
|
||||
}
|
||||
184
cfpayment/api/gateway/authorizenet/customerResponse.cfc
Normal file
184
cfpayment/api/gateway/authorizenet/customerResponse.cfc
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is a a response object that is returned from the authorize.net system whenever
|
||||
we have interactions with the customer based actions.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
component
|
||||
accessors="true"
|
||||
extends="cfpayment.api.model.response"
|
||||
{
|
||||
property name="resultCode" getter="true" setter="true";
|
||||
property name="messageCode" getter="true" setter="true";
|
||||
property name="messageText" getter="true" setter="true";
|
||||
property name="responseType" type="string" getter="true" setter="true";
|
||||
property name="customerProfileId" getter="true" setter="true";
|
||||
property name="customerPaymentProfileId" getter="true" setter="true";
|
||||
property name="customer" type="customer" getter="true" setter="true";
|
||||
property name="customerPaymentProfileIdList" type="array" getter="true" setter="true";
|
||||
property name="customerShippingAddressIdList" type="array" getter="true" setter="true";
|
||||
property name="validationDirectResponseList" type="array" getter="true" setter="true";
|
||||
property name="directResponse" type="string" getter="true" setter="true";
|
||||
property name="ids" type="array" getter="true" setter="true";
|
||||
property name="paymentProfiles" type="array" getter="true" setter="true";
|
||||
property name="totalNumInResultSet" type="numeric" getter="true" setter="true";
|
||||
|
||||
|
||||
function init(){
|
||||
super.init(argumentCollection=arguments);
|
||||
|
||||
|
||||
|
||||
|
||||
if(!hasError()){
|
||||
var xmlResponse = XMLParse(getResult());
|
||||
setParsedResult(xmlResponse);
|
||||
var messages = XMLSearch(xmlResponse, "//:messages")[1]; //Should work, always you get a message
|
||||
|
||||
//If this errors is because the service didn't actually respond which means hasError() should be true;
|
||||
setResultCode(messages.resultCode.xmlText);
|
||||
setMessageCode(messages.message.code.xmlText);
|
||||
setMessageText(messages.message.text.xmlText);
|
||||
setMessage(getMessageCode() & ": " & getMessageText());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Both HTTP call and actual call were ok
|
||||
if(getResultCode() EQ "OK"){
|
||||
setStatus(getService().getStatusSuccessful());
|
||||
setResponseType(xmlResponse.XmlRoot.xmlName);
|
||||
|
||||
//If anything is in the response set it
|
||||
setCustomerProfileId(getXMLElementText(xmlResponse, "customerProfileId"));
|
||||
setCustomerPaymentProfileId(getXMLElementText(xmlResponse, "customerPaymentProfileId"));
|
||||
addValidationDirectResponse(getXMLElementText(xmlResponse, "validationDirectResponse"));
|
||||
setDirectResponse(getXMLElementText(xmlResponse, "directResponse"));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(getResponseType() EQ "getCustomerPaymentProfileResponse"){
|
||||
var paymentProfiles = XMlSearch(xmlResponse, "//:paymentProfile");
|
||||
var paymentProfile = new paymentProfile(service=getService());
|
||||
|
||||
if(ArrayLen(paymentProfiles)){
|
||||
paymentProfile.populate(paymentProfiles[1]);
|
||||
}
|
||||
|
||||
|
||||
setPaymentProfiles([paymentProfile]);
|
||||
|
||||
}
|
||||
|
||||
//Handle specific data types
|
||||
if(getResponseType() EQ "getCustomerProfileIdsResponse"){
|
||||
var ids = XMlSearch(xmlResponse, "//:ids");
|
||||
if(ArrayLen(ids)){
|
||||
var iditems = ids[1].xmlChildren;
|
||||
var items = [];
|
||||
for(var id in iditems){
|
||||
items.append(id.xmltext);
|
||||
}
|
||||
setIds(items);
|
||||
}
|
||||
}
|
||||
|
||||
if(getResponseType() EQ "getCustomerPaymentProfileListResponse"){
|
||||
setTotalNumInResultSet(getXMLElementText(xmlResponse, "totalNumInResultSet", nullValue()));
|
||||
|
||||
var paymentProfiles = XMlSearch(xmlResponse, "//:paymentProfile");
|
||||
|
||||
var profiles = [];
|
||||
|
||||
for(var profile in paymentProfiles){
|
||||
var paymentProfile = generatePaymentProfile(profile)
|
||||
paymentProfile.setCustomerProfileId(getCustomerProfileID());
|
||||
profiles.append(paymentProfile);
|
||||
}
|
||||
|
||||
setPaymentProfiles(profiles);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
else{
|
||||
setStatus(getService().getStatusFailure());
|
||||
}
|
||||
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//Add items to arrays
|
||||
public void function addCustomerPaymentProfileId(String id){
|
||||
|
||||
var paymentProfileList = getCustomerPaymentProfileIdList();
|
||||
paymentProfileList = isNull(paymentProfileList) ? [] : paymentProfileList;
|
||||
|
||||
paymentProfileList.append(id);
|
||||
setCustomerPaymentProfileIdList(paymentProfileList);
|
||||
}
|
||||
public void function addCustomerShippingAddressId(Any id){
|
||||
var shipIDList = getCustomerPaymentProfileIdList();
|
||||
shipIDList = isNull(shipIDList) ? [] : shipIDList;
|
||||
|
||||
shipIDList.append(id);
|
||||
setCustomerShippingAddressIdList(shipIDList);
|
||||
}
|
||||
|
||||
public void function addvalidationDirectResponse(String directResponse){
|
||||
var directResponseList = getValidationDirectResponseList();
|
||||
directResponseList = isNull(directResponseList) ? [] : directResponseList;
|
||||
|
||||
directResponseList.append(directResponse);
|
||||
setValidationDirectResponseList(directResponseList);
|
||||
}
|
||||
|
||||
//PRIVATE HELPERS
|
||||
private function generatePaymentProfile(XML profile){
|
||||
|
||||
var paymentProfile = new paymentProfile();
|
||||
paymentProfile.setCustomerPaymentProfileId(getXMLElementText(profile, "customerPaymentProfileId"));
|
||||
paymentProfile.setCustomerProfileId(getXMLElementText(profile, "customerProfileId"));
|
||||
|
||||
|
||||
//This should be a card, not just
|
||||
var paymentMethod = {
|
||||
"creditCard":{
|
||||
"cardNumber": getXMLElementText(profile, "cardNumber"),
|
||||
"expirationDate": getXMLElementText(profile, "expirationDate")
|
||||
}
|
||||
};
|
||||
|
||||
//if we have a billTo, we should add it too.
|
||||
|
||||
|
||||
paymentProfile.setPaymentMethods(paymentMethod);
|
||||
return paymentProfile;
|
||||
}
|
||||
|
||||
private function getXMLElementText(XML responseXML, String elementName, default=""){
|
||||
var searchItem = XMLSearch(responseXML, "//:#elementName#");
|
||||
|
||||
|
||||
return ArrayLen(searchItem) ? searchItem[1].xmlText : default;
|
||||
}
|
||||
}
|
||||
118
cfpayment/api/gateway/authorizenet/paymentProfile.cfc
Normal file
118
cfpayment/api/gateway/authorizenet/paymentProfile.cfc
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is a customer that can be loaded and saved to the authorize.net system
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
component accessors="true"
|
||||
{
|
||||
|
||||
property name="customerType" type="string" getter="true" setter="true";
|
||||
property name="billTo" type="struct" getter="true" setter="true";
|
||||
property name="service" getter="true" setter="true";
|
||||
property name="customerProfileId" type="string" getter="true" setter="true";
|
||||
property name="customerPaymentProfileId" type="string" getter="true" setter="true";
|
||||
property name="paymentMethods" type="struct" getter="true" setter="true" hint="Card that we can use with this profile";
|
||||
|
||||
variables.custTypes = "individual,business";
|
||||
|
||||
|
||||
public function setCustomerType(String type){
|
||||
|
||||
if(!listFindNoCase(variables.custTypes, type)){
|
||||
throw(type="cfpayment.authorizenet.illegalArgumentException", message="CustomerType can only be individual or business");
|
||||
}
|
||||
variables.customerType = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public paymentProfile function populate(XML responseXML){
|
||||
|
||||
|
||||
getXMLElementText(responseXML, "customerType", "", setCustomerType);
|
||||
setCustomerPaymentProfileId(getXMLElementText(responseXML, "customerPaymentProfileId"));
|
||||
|
||||
var billToXML = XMLSearch(responseXML, "//:billTo");
|
||||
|
||||
|
||||
if(ArrayLen(billToXML)){
|
||||
var billTo = {
|
||||
"firstName": getXMLElementText( billToXML[1], "firstName"),
|
||||
"lastName": getXMLElementText( billToXML[1], "lastName"),
|
||||
"company": getXMLElementText( billToXML[1], "company"),
|
||||
"address": getXMLElementText( billToXML[1], "address"),
|
||||
"city": getXMLElementText( billToXML[1], "city"),
|
||||
"state": getXMLElementText( billToXML[1], "state"),
|
||||
"zip": getXMLElementText( billToXML[1], "zip"),
|
||||
"country": getXMLElementText( billToXML[1], "country"),
|
||||
"phoneNumber": getXMLElementText( billToXML[1], "phoneNumber"),
|
||||
"faxNumber": getXMLElementText( billToXML[1], "faxNumber"),
|
||||
};
|
||||
|
||||
setBillTo(new address(argumentCollection=billTo));
|
||||
}
|
||||
|
||||
|
||||
|
||||
var creditCard = XMLSearch(responseXML, "//:creditCard");
|
||||
if(ArrayLen(creditCard)){
|
||||
//This should be a card object no?
|
||||
//No. The api doesn't return actual cards it seems. So this clashes with this api
|
||||
|
||||
// var card = getService().createCreditCard();
|
||||
// card.setAccount(creditCard[1].cardNumber.xmltext);
|
||||
// card.setMonth(Left(creditCard[1].expirationDate.xmltext, 2));
|
||||
// card.setYear(Right(creditCard[1].expirationDate.xmltext, 2));
|
||||
|
||||
|
||||
|
||||
var paymentMethod = {
|
||||
"creditCard":{
|
||||
"cardNumber": creditCard[1].cardNumber.xmltext,
|
||||
"expirationDate": creditCard[1].expirationDate.xmltext
|
||||
}
|
||||
};
|
||||
setPaymentMethods(paymentMethod);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private function getXMLElementText(XML responseXML, String elementName, default="",Function callback ){
|
||||
var searchItem = XMLSearch(responseXML, "//:#elementName#");
|
||||
|
||||
//Deal with callbacks.
|
||||
if( structKeyExists(arguments, "callback")
|
||||
&& !isNull(arguments.callback)
|
||||
&& isValid("Function", callback)
|
||||
&& ArrayLen(searchItem)
|
||||
){
|
||||
|
||||
callback(searchItem[1].xmlText);
|
||||
|
||||
}
|
||||
|
||||
return ArrayLen(searchItem)?searchItem[1].xmlText : default;
|
||||
}
|
||||
}
|
||||
380
cfpayment/api/gateway/authorizenet/tests/AuthorizenetTest.cfc
Normal file
380
cfpayment/api/gateway/authorizenet/tests/AuthorizenetTest.cfc
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
<cfcomponent name="AuthorizenetTest" extends="mxunit.framework.TestCase" output="false" hint="Basically the Braintree tests, but a couple additions">
|
||||
<!---
|
||||
Test transactions can be submitted with the following information:
|
||||
|
||||
Visa 4111111111111111
|
||||
MasterCard 5431111111111111
|
||||
DiscoverCard 6011601160116611
|
||||
American Express 341111111111111
|
||||
Credit Card Expiration 10/10
|
||||
eCheck Acct & Routing: 123123123
|
||||
Amount >1.00
|
||||
|
||||
|
||||
By placing the merchant’s payment gateway account in Test Mode in the Merchant Interface.
|
||||
New payment gateway accounts are placed in Test Mode by default. For more information
|
||||
about Test Mode, see the Merchant Integration Guide at
|
||||
http://www.authorize.net/support/Merchant/default.htm. Please note that when processing
|
||||
test transactions in Test Mode, the payment gateway will return a transaction ID of “0.”
|
||||
This means you cannot test follow-on transactions, e.g. credits, voids, etc., while in
|
||||
Test Mode. To test follow-on transactions, you can either submit x_test_request=TRUE as
|
||||
indicated above, or process a test transaction with any valid credit card number in live
|
||||
mode, as explained below.
|
||||
--->
|
||||
<cffunction name="setUp" returntype="void" access="public" output="false">
|
||||
<cfscript>
|
||||
var gw = structNew();
|
||||
|
||||
variables.svc = createObject("component", "cfpayment.api.core");
|
||||
|
||||
gw.path = "authorizenet.authorizenet";
|
||||
// Request a test account here: http://developer.authorize.net/testaccount/
|
||||
gw.MerchantAccount = "2JC6bA988aq2s7Vk"; // Insert your developer or production merchant account number here.
|
||||
gw.Username = "4ffrBT36La"; // Insert your developer or production username here.
|
||||
gw.TestMode = true; // defaults to true
|
||||
|
||||
// create gw and get reference
|
||||
variables.svc.init(gw);
|
||||
variables.gw = variables.svc.getGateway();
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testPurchase" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
<cfset options.orderid = getTickCount() /><!---Authorize.net requires a unique order id for each transaction.--->
|
||||
|
||||
<!--- test the purchase method --->
|
||||
<cfset response = gw.purchase(money = money, account = createValidCard(), options = options) />
|
||||
<!---<cfset debug(response.getMemento()) />--->
|
||||
<cfset debug("AVSMessage: #response.getAVSMessage()#") />
|
||||
<cfset assertTrue(response.getSuccess(), "The purchase failed (1)") />
|
||||
|
||||
<!--- this will be rejected by gateway because the card number is not valid --->
|
||||
<cfset response = gw.purchase(money = money, account = createInvalidCard(), options = options) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "The authorization did succeed (3)") />
|
||||
|
||||
|
||||
<cfset response = gw.purchase(money = variables.svc.createMoney(5010), account = createValidCardWithoutCVV(), options = options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed (4)") />
|
||||
<cfset debug("No CVV Message: " & response.getCVVMessage()) />
|
||||
<cfset assertTrue(response.getCVVCode() EQ "", "No CVV was passed so no answer should be provided but was: '#response.getCVVCode()#'") />
|
||||
|
||||
|
||||
<cfset response = gw.purchase(money = variables.svc.createMoney(5020), account = createValidCardWithBadCVV(), options = options) />
|
||||
<cfset debug("Bad CVV Message:" & response.getCVVMessage()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed (5)") />
|
||||
<cfset assertTrue(NOT response.isValidCVV(), "Bad CVV was passed so non-matching answer should be provided but was: '#response.getCVVCode()#'") />
|
||||
|
||||
|
||||
<cfset response = gw.purchase(money = variables.svc.createMoney(5030), account = createValidCardWithoutStreetMatch(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed (6)") />
|
||||
<cfset debug(response.getAVSMessage()) />
|
||||
<cfset assertTrue(response.isValidAVS(), "AVS Zip match only should be found") />
|
||||
|
||||
|
||||
<cfset response = gw.purchase(money = variables.svc.createMoney(5040), account = createValidCardWithoutZipMatch(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed (7)") />
|
||||
<cfset debug(response.getAVSMessage()) />
|
||||
<cfset assertTrue(response.isValidAVS(), "AVS Street match only should be found") />
|
||||
|
||||
|
||||
<!--- test specific response codes, requires enabling psuedo-test mode --->
|
||||
<cfset options["x_test_request"] = true />
|
||||
|
||||
<!--- pass in 2.00 for a decline code --->
|
||||
<cfset response = gw.purchase(money = variables.svc.createMoney(200), account = createCardForErrorResponse(), options = options) />
|
||||
<cfset debug(response.getMessage()) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "The purchase should have failed (2)") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testAuthorizeOnly" access="public" returntype="void" output="false">
|
||||
<cfset var money = variables.svc.createMoney(5132) /><!--- in cents --->
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.orderid = getTickCount() />
|
||||
|
||||
<cfset response = gw.authorize(money = money, account = createValidCard(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset debug("Status=#response.getStatus()#, #response.getMessage()#") />
|
||||
<cfset debug("AVS1=#response.getAVSCode()#, #response.getAVSMessage()#") />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization failed") />
|
||||
<cfset assertTrue(response.getAVSCode() EQ "Y", "Street address + zip should match (Y)") />
|
||||
|
||||
<!--- this will be rejected by gateway because the card number is not valid --->
|
||||
<cfset options.orderid++ />
|
||||
<cfset response = gw.authorize(money = money, account = createInvalidCard(), options = options) />
|
||||
<cfset debug("Success2=#response.getSuccess()#") />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "The authorization shouldn't have succeeded (2)") />
|
||||
|
||||
<!---Test mode doesn't appear to fail on cvv or avs--->
|
||||
<!---<cfset options.orderid++ />
|
||||
<cfset response = gw.authorize(money = variables.svc.createMoney(2700), account = createCardForErrorResponse(), options = options) /><!---invalid avs--->
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed 3") />
|
||||
<cfset debug("CVV1=#response.getCVVCode()#, #response.getCVVMessage()#") />
|
||||
<cfset assertTrue(response.getCVVCode() EQ "", "No CVV was passed so no answer should be provided but was: '#response.getCVVCode()#'") />--->
|
||||
|
||||
<!---<cfset options.orderid++ />
|
||||
<cfset response = gw.authorize(money = money, account = createValidCardWithBadCVV(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset debug("Success3=#response.getSuccess()#") />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed 4") />
|
||||
<cfset debug("CVV2=#response.getCVVCode()#, #response.getCVVMessage()#") />
|
||||
<cfset assertTrue(response.getCVVCode() EQ "N", "Bad CVV was passed so non-matching answer should be provided but was: '#response.getCVVCode()#'") />--->
|
||||
|
||||
<!--- <cfset options.orderid++ />
|
||||
<cfset response = gw.authorize(money = money, account = createValidCardWithoutStreetMatch(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed 5") />
|
||||
<cfset debug("AVS2=#response.getAVSCode()#, #response.getAVSMessage()#") />
|
||||
<cfset assertTrue(response.getAVSCode() EQ "Z", "AVS Zip match only should be found") />
|
||||
|
||||
<cfset options.orderid++ />
|
||||
<cfset response = gw.authorize(money = money, account = createValidCardWithoutZipMatch(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed 6") />
|
||||
<cfset debug("AVS3=#response.getAVSCode()#, #response.getAVSMessage()#") />
|
||||
<cfset assertTrue(response.getAVSCode() EQ "A", "AVS Street match only should be found") />--->
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testAuthorizeThenCapture" access="public" returntype="void" output="false">
|
||||
<cfset var account = createValidCard() />
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var report = "" />
|
||||
<cfset var options = structNew() />
|
||||
<cfset var tid = "" />
|
||||
<cfset options.orderid = getTickCount() />
|
||||
|
||||
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed") />
|
||||
|
||||
<cfset response = gw.capture(money = money, authorization = response.getTransactionId(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The capture did not succeed") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testAuthorizeThenCredit" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var account = createValidCard() />
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var report = "" />
|
||||
<cfset var options = structNew() />
|
||||
<cfset options.orderid = getTickCount() />
|
||||
|
||||
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed") />
|
||||
|
||||
<cfset response = gw.credit(transactionid = response.getTransactionID(), money = money, account = createValidCard(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "You cannot credit a preauth") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testAuthorizeThenVoid" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var account = createValidCard() />
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var report = "" />
|
||||
<cfset var options = structNew() />
|
||||
<cfset options.orderid = getTickCount() />
|
||||
|
||||
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed") />
|
||||
|
||||
<cfset response = gw.void(transactionid = response.getTransactionID(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "You can void a preauth") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseThenCredit" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var account = createValidCard() />
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var report = "" />
|
||||
<cfset var options = structNew() />
|
||||
<cfset options.orderid = getTickCount() />
|
||||
|
||||
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The purchase did not succeed") />
|
||||
|
||||
<cfset response = gw.credit(transactionid = response.getTransactionID(), money = money, account = account, options = options) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "You can not full credit a purchase (should void since it's not settled?)") />
|
||||
|
||||
<cfset response = gw.credit(transactionid = response.getTransactionID(), money = variables.svc.createMoney(4500), account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "You can partial credit a purchase") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseThenVoid" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var account = createValidCard() />
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var report = "" />
|
||||
<cfset var options = structNew() />
|
||||
<cfset options.orderid = getTickCount() />
|
||||
|
||||
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The purchase did not succeed") />
|
||||
|
||||
<cfset response = gw.void(transactionid = response.getTransactionID(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "You can void a purchase") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
|
||||
<cffunction name="createValidCard" access="private" returntype="any" output="false">
|
||||
<!--- these values simulate a valid card with matching avs/cvv --->
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset account.setAccount(4111111111111111) />
|
||||
<cfset account.setMonth(10) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue(999) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("888") />
|
||||
<cfset account.setPostalCode("77777") />
|
||||
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
<cffunction name="createCardForErrorResponse" access="private" returntype="any" output="false">
|
||||
<!--- these values simulate a valid card with matching avs/cvv --->
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset account.setAccount(4222222222222) />
|
||||
<cfset account.setMonth(10) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue(999) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("888") />
|
||||
<cfset account.setPostalCode("77777") />
|
||||
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createInvalidCard" access="private" returntype="any" output="false">
|
||||
<!--- these values simulate a valid card with matching avs/cvv --->
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset account.setAccount(4100000000000000) />
|
||||
<cfset account.setMonth(10) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue(123) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("236 N. Santa Cruz") />
|
||||
<cfset account.setPostalCode("95030") />
|
||||
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCardWithoutCVV" access="private" returntype="any" output="false">
|
||||
<!--- these values simulate a valid card with matching avs/cvv --->
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset account.setAccount(4111111111111111) />
|
||||
<cfset account.setMonth(10) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue() />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("888") />
|
||||
<cfset account.setPostalCode("77777") />
|
||||
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCardWithBadCVV" access="private" returntype="any" output="false">
|
||||
<!--- these values simulate a valid card with matching avs/cvv --->
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset account.setAccount(4111111111111111) />
|
||||
<cfset account.setMonth(10) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue(111) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("888") />
|
||||
<cfset account.setPostalCode("77777") />
|
||||
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCardWithoutStreetMatch" access="private" returntype="any" output="false">
|
||||
<!--- these values simulate a valid card with matching avs/cvv --->
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset account.setAccount(4111111111111111) />
|
||||
<cfset account.setMonth(10) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue() />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("N. Santa Cruz") />
|
||||
<cfset account.setPostalCode("77777") />
|
||||
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCardWithoutZipMatch" access="private" returntype="any" output="false">
|
||||
<!--- these values simulate a valid card with matching avs/cvv --->
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset account.setAccount(4111111111111111) />
|
||||
<cfset account.setMonth(10) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue() />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("888") />
|
||||
<cfset account.setPostalCode("00000") />
|
||||
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<cffunction name="createValidEFT" access="private" returntype="any" output="false">
|
||||
<!--- these values simulate a valid eft with matching avs/cvv --->
|
||||
<cfset var account = variables.svc.createEFT() />
|
||||
<cfset account.setAccount("123123123") />
|
||||
<cfset account.setRoutingNumber("123123123") />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("236 N. Santa Cruz Ave") />
|
||||
<cfset account.setPostalCode("95030") />
|
||||
<cfset account.setPhoneNumber("415-555-1212") />
|
||||
|
||||
<cfset account.setAccountType("checking") />
|
||||
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
|
||||
|
||||
</cfcomponent>
|
||||
52
cfpayment/api/gateway/authorizenet/tests/index.cfm
Normal file
52
cfpayment/api/gateway/authorizenet/tests/index.cfm
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<cfsetting showDebugOutput="false">
|
||||
|
||||
<cfparam name="url.runtests" default="false">
|
||||
<cfparam name="url.reporter" default="simple">
|
||||
<cfparam name="url.directory" default="tests.specs">
|
||||
<cfparam name="url.recurse" default="true" type="boolean">
|
||||
<cfparam name="url.bundles" default="">
|
||||
<cfparam name="url.labels" default="">
|
||||
<cfparam name="url.reportpath" default="#expandPath( "/tests/results" )#">
|
||||
<cfparam name="url.propertiesSummary" default="false" type="boolean">
|
||||
|
||||
|
||||
|
||||
<cfif url.runtests OR url.keyExists("testSuites") OR url.keyExists("testBundles") OR url.reporter EQ "text">
|
||||
|
||||
|
||||
<!--- Executes all tests in the 'specs' folder with simple reporter by default --->
|
||||
<!--- Include the TestBox HTML Runner --->
|
||||
<cfinclude template="/libs/testbox/system/runners/HTMLRunner.cfm" >
|
||||
|
||||
<cfelse>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Run tests</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Run Tests</h1>
|
||||
<ul>
|
||||
<li><a href="index.cfm?runtests=true">Run All Tests</a></li>
|
||||
<li>Run Specific Tests:
|
||||
<cfset specDir = expandPath("/" & Replace(url.directory, ".", "/"))>
|
||||
<cfset Tests = DirectoryList(specDir,false, "query")>
|
||||
<ul>
|
||||
<cfloop query="Tests">
|
||||
<cfoutput>
|
||||
<cfif type IS "Dir">
|
||||
<li><a href="index.cfm?directory=#url.directory#.#Name#&runtests=true">#Name#</a></li>
|
||||
|
||||
<cfelse>
|
||||
<cfset CFCName = "#url.directory#.#Replace(Name, ".cfc", "")#">
|
||||
<li><a href="index.cfm?testSuites=#CFCName#&testBundles=#CFCName#">#Name#</a></li>
|
||||
</cfif>
|
||||
|
||||
</cfoutput>
|
||||
</cfloop>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</cfif>
|
||||
115
cfpayment/api/gateway/authorizenet/transactionResponse.cfc
Normal file
115
cfpayment/api/gateway/authorizenet/transactionResponse.cfc
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is a a response object that is returned from the authorize.net system whenever
|
||||
we have interactions with transaction based actions.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
component
|
||||
accessors="true"
|
||||
extends="cfpayment.api.model.response"
|
||||
{
|
||||
|
||||
property name="resultCode" getter="true" setter="true";
|
||||
property name="messageCode" getter="true" setter="true";
|
||||
property name="messageText" getter="true" setter="true";
|
||||
property name="responseType" type="string" getter="true" setter="true";
|
||||
|
||||
|
||||
function init(){
|
||||
|
||||
super.init(argumentCollection=arguments);
|
||||
|
||||
|
||||
if(!hasError()){
|
||||
var xmlResponse = XMLParse(getResult());
|
||||
setParsedResult(xmlResponse);
|
||||
|
||||
|
||||
var messages = XMLSearch(xmlResponse, "//:messages")[1]; //Should work, always you get a message
|
||||
|
||||
//If this errors is because the service didn't actually respond which means hasError() should be true;
|
||||
setResultCode(messages.resultCode.xmlText);
|
||||
setMessageCode(messages.message.code.xmlText);
|
||||
setMessageText(messages.message.text.xmlText);
|
||||
setMessage(getMessageCode() & ": " & getMessageText());
|
||||
|
||||
if(getResultCode() EQ "OK"){
|
||||
setStatus(getService().getStatusSuccessful());
|
||||
setResponseType(xmlResponse.XmlRoot.xmlName);
|
||||
|
||||
processTransactionResponse(xmlResponse);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
private void function processTransactionResponse(XML xmlResponse){
|
||||
|
||||
var transResponse = xmlResponse.createTransactionResponse.transactionResponse;
|
||||
// handle common response fields
|
||||
if(structKeyExists(transResponse, "responseCode")){
|
||||
setMessage(transResponse.responseCode.XMLText);
|
||||
}
|
||||
if (structKeyExists(transResponse, "transId")){
|
||||
setTransactionID(transResponse.transId.XMLText);
|
||||
}
|
||||
|
||||
if (structKeyExists(transResponse, "authCode")){
|
||||
setAuthorization(transResponse.authCode.XmlText);
|
||||
}
|
||||
// handle common "success" fields
|
||||
if (structKeyExists(transResponse, "avsResultCode")){
|
||||
setAVSCode(transResponse.avsResultCode.XmlText);
|
||||
}
|
||||
|
||||
if (structKeyExists(transResponse, "cvvResultCode")){
|
||||
setCVVCode(transResponse.cvvResultCode.XmlText);
|
||||
}
|
||||
|
||||
|
||||
// see if the response was successful
|
||||
switch (transResponse.responseCode.XmlText) {
|
||||
case "1": {
|
||||
setStatus(getService().getStatusSuccessful());
|
||||
break;
|
||||
}
|
||||
case "2": {
|
||||
setStatus(getService().getStatusDeclined());
|
||||
break;
|
||||
}
|
||||
case "4": {
|
||||
setStatus(5); // On hold (this status value is not currently defined in core.cfc)
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
setStatus(getService().getStatusFailure()); // only other known state is 3 meaning, "error in transaction data or system error"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
509
cfpayment/api/gateway/base.cfc
Normal file
509
cfpayment/api/gateway/base.cfc
Normal file
|
|
@ -0,0 +1,509 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2007 Brian Ghidinelli (http://www.ghidinelli.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 name="base" output="false" hint="Base gateway to be extended by real implementations">
|
||||
|
||||
<!---
|
||||
Building a new gateway is straightforward. Extend this base.cfc and then map your gateway-specific parameters to normalized cfpayment parameters.
|
||||
|
||||
For example, we call our internal tracking ID "orderId". However, Braintree expects "order_id" and Skipjack expects "ordernumber".
|
||||
|
||||
To write a new gateway, you would pass in orderId to a method like purchase() and map it to whatever name your gateway requires. When you parse the response from your gateway,
|
||||
you would map it back to orderId in the common response object. Make sense?
|
||||
|
||||
Check the docs for a complete list of normalized cfpayment parameter names.
|
||||
--->
|
||||
|
||||
<cfset variables.cfpayment = structNew() />
|
||||
<cfset variables.cfpayment.GATEWAYID = "1" />
|
||||
<cfset variables.cfpayment.GATEWAY_NAME = "Base Gateway" />
|
||||
<cfset variables.cfpayment.GATEWAY_VERSION = "1.0" />
|
||||
<cfset variables.cfpayment.GATEWAY_TEST_URL = "http://localhost/" />
|
||||
<cfset variables.cfpayment.GATEWAY_LIVE_URL = "http://localhost/" />
|
||||
<cfset variables.cfpayment.PERIODICITY_MAP = StructNew() />
|
||||
<cfset variables.cfpayment.MerchantAccount = "" />
|
||||
<cfset variables.cfpayment.Username = "" />
|
||||
<cfset variables.cfpayment.Password = "" />
|
||||
<cfset variables.cfpayment.Timeout = 300 />
|
||||
<cfset variables.cfpayment.TestMode = true />
|
||||
|
||||
|
||||
<!--- it's possible access to internal java objects is disabled, so we account for that --->
|
||||
<cftry>
|
||||
<!--- use this java object to get at the current RequestTimeout value for a given request --->
|
||||
<cfset variables.rcMonitor = createObject("java", "coldfusion.runtime.RequestMonitor") />
|
||||
<cfset variables.rcMonitorEnabled = true />
|
||||
<cfcatch type="any">
|
||||
<cfset variables.rcMonitorEnabled = false />
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
|
||||
<cffunction name="init" access="public" output="false" returntype="any">
|
||||
<cfargument name="service" type="any" required="true" />
|
||||
<cfargument name="config" type="struct" required="false" />
|
||||
|
||||
<cfset var argName = "" />
|
||||
|
||||
<cfset variables.cfpayment.service = arguments.service />
|
||||
|
||||
<!--- loop over any configuration and set parameters --->
|
||||
<cfif structKeyExists(arguments, "config")>
|
||||
<cfloop collection="#arguments.config#" item="argName">
|
||||
<cfif structKeyExists(arguments.config, argName) AND structKeyExists(this, "set" & argName)>
|
||||
<cfinvoke component="#this#" method="set#argName#">
|
||||
<cfinvokeargument name="#argName#" value="#arguments.config[argName]#" />
|
||||
</cfinvoke>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
</cfif>
|
||||
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<!--- implemented base functions --->
|
||||
<cffunction name="getGatewayName" access="public" output="false" returntype="any" hint="">
|
||||
<cfif structKeyExists(variables.cfpayment, "GATEWAY_NAME")>
|
||||
<cfreturn variables.cfpayment.GATEWAY_NAME />
|
||||
<cfelse>
|
||||
<cfreturn "" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getGatewayVersion" access="public" output="false" returntype="any" hint="">
|
||||
<cfif structKeyExists(variables.cfpayment, "GATEWAY_VERSION")>
|
||||
<cfreturn variables.cfpayment.GATEWAY_VERSION />
|
||||
<cfelse>
|
||||
<cfreturn "" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getTimeout" access="public" output="false" returntype="numeric">
|
||||
<cfreturn variables.cfpayment.Timeout />
|
||||
</cffunction>
|
||||
<cffunction name="setTimeout" access="public" output="false" returntype="void">
|
||||
<cfargument name="Timeout" type="numeric" required="true" />
|
||||
<cfset variables.cfpayment.Timeout = arguments.Timeout />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getTestMode" access="public" output="false" returntype="any" hint="">
|
||||
<cfreturn variables.cfpayment.TestMode />
|
||||
</cffunction>
|
||||
<cffunction name="setTestMode" access="public" output="false" returntype="any">
|
||||
<cfset variables.cfpayment.TestMode = arguments[1] />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getGatewayURL" access="public" output="false" returntype="any" hint="">
|
||||
<cfif getTestMode()>
|
||||
<cfreturn variables.cfpayment.GATEWAY_TEST_URL />
|
||||
<cfelse>
|
||||
<cfreturn variables.cfpayment.GATEWAY_LIVE_URL />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- Date: 7/6/2008 Usage: get access to the service for generating responses, errors, etc --->
|
||||
<cffunction name="getService" output="false" access="private" returntype="any" hint="get access to the service for generating responses, errors, etc">
|
||||
<cfreturn variables.cfpayment.service />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- getter/setters for common configuration parameters like MID, Username, Password --->
|
||||
<cffunction name="getMerchantAccount" access="package" output="false" returntype="any">
|
||||
<cfreturn variables.cfpayment.MerchantAccount />
|
||||
</cffunction>
|
||||
<cffunction name="setMerchantAccount" access="package" output="false" returntype="void">
|
||||
<cfargument name="MerchantAccount" type="any" required="true" />
|
||||
<cfset variables.cfpayment.MerchantAccount = arguments.MerchantAccount />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getUsername" access="package" output="false" returntype="any">
|
||||
<cfreturn variables.cfpayment.Username />
|
||||
</cffunction>
|
||||
<cffunction name="setUsername" access="package" output="false" returntype="void">
|
||||
<cfargument name="Username" type="any" required="true" />
|
||||
<cfset variables.cfpayment.Username = arguments.Username />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getPassword" access="package" output="false" returntype="any">
|
||||
<cfreturn variables.cfpayment.Password />
|
||||
</cffunction>
|
||||
<cffunction name="setPassword" access="package" output="false" returntype="void">
|
||||
<cfargument name="Password" type="any" required="true" />
|
||||
<cfset variables.cfpayment.Password = arguments.Password />
|
||||
</cffunction>
|
||||
|
||||
<!--- the gatewayid is a value used by the transaction/HA apis to differentiate
|
||||
the gateway used for a given payment. The value is arbitrary and unique to
|
||||
a particular system. --->
|
||||
<cffunction name="getGatewayID" access="public" output="false" returntype="any">
|
||||
<cfreturn variables.cfpayment.GATEWAYID />
|
||||
</cffunction>
|
||||
<cffunction name="setGatewayID" access="public" output="false" returntype="void">
|
||||
<cfargument name="GatewayID" required="true" type="any" />
|
||||
<cfset variables.cfpayment.GatewayID = arguments.GatewayID />
|
||||
</cffunction>
|
||||
|
||||
<!--- the current request timeout allows us to intelligently modify the overall page timeout based
|
||||
upon whatever the current page context or configured timeout dictate. It's possible to have
|
||||
acces to internal Java components disabled so we take that into account here. --->
|
||||
<cffunction name="getCurrentRequestTimeout" output="false" access="private" returntype="numeric">
|
||||
<cfif variables.rcMonitorEnabled>
|
||||
<cfreturn variables.rcMonitor.getRequestTimeout() />
|
||||
<cfelse>
|
||||
<cfreturn 0 />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- manage transport and network/connection error handling; all gateways should send HTTP requests through this method --->
|
||||
<cffunction name="process" output="false" access="package" returntype="struct" hint="Robust HTTP get/post mechanism with error handling">
|
||||
<cfargument name="url" type="string" required="false" hint="URL to get/post" default="#getGatewayURL(argumentCollection = arguments)#" />
|
||||
<cfargument name="method" type="string" required="false" default="post" />
|
||||
<cfargument name="payload" type="any" required="true" /><!--- can be xml (simplevalue) or a struct of key-value pairs --->
|
||||
<cfargument name="headers" type="struct" required="false" default="#structNew()#" />
|
||||
<cfargument name="encoded" type="boolean" required="false" default="true" hint="Some gateways (e.g. PayPal Payflow Pro) require unencoded parameters" />
|
||||
<cfargument name="files" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<!--- prepare response before attempting to send over wire --->
|
||||
<cfset var CFHTTP = "" />
|
||||
<cfset var status = "" />
|
||||
<cfset var paramType = "" />
|
||||
<cfset var ResponseData = { Status = getService().getStatusPending()
|
||||
,StatusCode = ""
|
||||
,Result = ""
|
||||
,Message = ""
|
||||
,RequestData = {}
|
||||
,TestMode = getTestMode()
|
||||
} />
|
||||
|
||||
|
||||
<!--- TODO: NOTE: THIS INTERNAL DATA REFERENCE MAY GO AWAY, DO NOT RELY UPON IT!!! DEVELOPMENT PURPOSES ONLY!!! --->
|
||||
<!--- store payload for reference during development (can be simplevalue OR structure) --->
|
||||
<cfif getTestMode()>
|
||||
<cfset ResponseData.RequestData = { PAYLOAD = duplicate(arguments.payload)
|
||||
,GATEWAY_URL = arguments.url
|
||||
,HTTP_METHOD = arguments.method
|
||||
,HEADERS = arguments.headers
|
||||
} />
|
||||
</cfif>
|
||||
|
||||
<!--- enable a little extra time past the CFHTTP timeout so error handlers can run --->
|
||||
<cfsetting requesttimeout="#max(getCurrentRequestTimeout(), getTimeout() + 10)#" />
|
||||
|
||||
<cftry>
|
||||
<cfset CFHTTP = doHttpCall(url = arguments.url
|
||||
,timeout = getTimeout()
|
||||
,argumentCollection = arguments) />
|
||||
|
||||
<!--- begin result handling --->
|
||||
<cfif isDefined("CFHTTP") AND isStruct(CFHTTP) AND structKeyExists(CFHTTP, "fileContent")>
|
||||
<!--- duplicate the non-struct data from CFHTTP for our response --->
|
||||
<cfset ResponseData.Result = CFHTTP.fileContent />
|
||||
<cfelse>
|
||||
<!--- an unknown failure here where the response doesn't exist somehow or is malformed --->
|
||||
<cfset ResponseData.Status = getService().getStatusUnknown() />
|
||||
</cfif>
|
||||
|
||||
|
||||
<!--- make decisions based on the HTTP status code --->
|
||||
<cfset ResponseData.StatusCode = reReplace(CFHTTP.statusCode, "[^0-9]", "", "ALL") />
|
||||
|
||||
<!--- Errors that are thrown even when CFHTTP throwonerror = no:
|
||||
catch (COM.Allaire.ColdFusion.HTTPFailure postError) - invalid ssl / self-signed ssl / expired ssl
|
||||
catch (coldfusion.runtime.RequestTimedOutException postError) - tag timeout like cfhttp timeout or page timeout
|
||||
See http://www.ghidinelli.com/2012/01/03/cfhttp-error-handling-http-status-codes for all others (handled by HTTP status code below)
|
||||
--->
|
||||
|
||||
<!--- implementation and runtime exceptions --->
|
||||
<cfcatch type="cfpayment">
|
||||
<!--- we rethrow here to break the call as this may happen during development --->
|
||||
<cfrethrow />
|
||||
</cfcatch>
|
||||
<cfcatch type="COM.Allaire.ColdFusion.HTTPFailure">
|
||||
<!--- "Connection Failure" - ColdFusion wasn't able to connect successfully. This can be an expired, not legit, wildcard or self-signed SSL cert. --->
|
||||
<cfset ResponseData.Message = "Gateway was not successfully reached and the transaction was not processed (100)" />
|
||||
<cfset ResponseData.Status = getService().getStatusFailure() />
|
||||
<cfreturn ResponseData />
|
||||
</cfcatch>
|
||||
<cfcatch type="coldfusion.runtime.RequestTimedOutException">
|
||||
<cfset ResponseData.Message = "The bank did not respond to our request. Please wait a few moments and try again. (101)" />
|
||||
<cfset ResponseData.Status = getService().getStatusTimeout() />
|
||||
<cfreturn ResponseData />
|
||||
</cfcatch>
|
||||
<cfcatch type="any">
|
||||
<!--- convert the CFCATCH.message into the HTTP Status Code --->
|
||||
<cfset ResponseData.StatusCode = reReplace(CFCATCH.message, "[^0-9]", "", "ALL") />
|
||||
<cfset ResponseData.Status = getService().getStatusUnknown() />
|
||||
<cfset ResponseData.Message = CFCATCH.Message & " (" & cfcatch.Type & ")" />
|
||||
<!--- let it fall through so we can attempt to handle the status code --->
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfif len(ResponseData.StatusCode) AND ResponseData.StatusCode NEQ "200">
|
||||
<cfswitch expression="#ResponseData.StatusCode#">
|
||||
<cfcase value="404,302,503"><!--- coldfusion doesn't follow 302s, so acts like a 404 --->
|
||||
<cfset ResponseData.Message = "Gateway was not successfully reached and the transaction was not processed" />
|
||||
<cfset ResponseData.Status = getService().getStatusFailure() />
|
||||
<cfif structKeyExists(CFHTTP, "ErrorDetail") AND len(CFHTTP.ErrorDetail)>
|
||||
<cfset ResponseData.Message = ResponseData.Message & " (Original message: #CFHTTP.ErrorDetail#)" />
|
||||
</cfif>
|
||||
</cfcase>
|
||||
<cfcase value="500">
|
||||
<cfset ResponseData.Message = "Gateway did not respond as expected and the transaction may have been processed" />
|
||||
<cfset ResponseData.Status = getService().getStatusUnknown() />
|
||||
<cfif structKeyExists(CFHTTP, "ErrorDetail") AND len(CFHTTP.ErrorDetail)>
|
||||
<cfset ResponseData.Message = ResponseData.Message & " (Original message: #CFHTTP.ErrorDetail#)" />
|
||||
</cfif>
|
||||
</cfcase>
|
||||
</cfswitch>
|
||||
<cfelseif NOT len(ResponseData.StatusCode)>
|
||||
<cfset ResponseData.Status = getService().getStatusUnknown() />
|
||||
</cfif>
|
||||
|
||||
<!--- return raw collection to be handled by gateway-specific code --->
|
||||
<cfreturn ResponseData />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- ------------------------------------------------------------------------------
|
||||
|
||||
PRIVATE HELPER METHODS FOR DEVELOPERS
|
||||
|
||||
------------------------------------------------------------------------- --->
|
||||
<cffunction name="doHttpCall" access="private" hint="wrapper around the http call - improves testing" returntype="struct" output="false">
|
||||
<cfargument name="url" type="string" required="true" hint="URL to get/post" />
|
||||
<cfargument name="method" type="string" required="false" hint="the http request method: GET, POST, PUT or DELETE" default="get" />
|
||||
<cfargument name="timeout" type="numeric" required="true" />
|
||||
<cfargument name="headers" type="struct" required="false" default="#structNew()#" />
|
||||
<cfargument name="payload" type="any" required="false" default="#structNew()#" />
|
||||
<cfargument name="encoded" type="boolean" required="false" default="true" />
|
||||
<cfargument name="files" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var CFHTTP = "" />
|
||||
<cfset var key = "" />
|
||||
<cfset var keylist = "" />
|
||||
<cfset var skey = "" />
|
||||
<cfset var paramType = "" />
|
||||
|
||||
<cfif uCase(arguments.method) EQ "GET">
|
||||
<cfset paramType = "url" />
|
||||
<cfelseif uCase(arguments.method) EQ "POST">
|
||||
<cfset paramType = "formfield" />
|
||||
<cfelseif uCase(arguments.method) EQ "PUT">
|
||||
<cfset paramType = "body" />
|
||||
<cfelseif uCase(arguments.method) EQ "DELETE">
|
||||
<cfset paramType = "body" />
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid Method" type="cfpayment.InvalidParameter.Method" />
|
||||
</cfif>
|
||||
|
||||
<!--- send request --->
|
||||
<cfhttp url="#arguments.url#" method="#arguments.method#" timeout="#arguments.timeout#" throwonerror="no">
|
||||
<!--- pass along any extra headers, like Accept or Authorization or Content-Type --->
|
||||
<cfloop collection="#arguments.headers#" item="key">
|
||||
<cfhttpparam name="#key#" value="#arguments.headers[key]#" type="header" />
|
||||
</cfloop>
|
||||
|
||||
<!--- accept nested structures including ordered structs (required for skipjack) --->
|
||||
<cfif isStruct(arguments.payload)>
|
||||
|
||||
<cfloop collection="#arguments.payload#" item="key">
|
||||
<cfif isSimpleValue(arguments.payload[key])>
|
||||
<!--- most common param is simple value --->
|
||||
<cfhttpparam name="#key#" value="#arguments.payload[key]#" type="#paramType#" encoded="#arguments.encoded#" />
|
||||
<cfelseif isStruct(arguments.payload[key])>
|
||||
<!--- loop over structure (check for _keylist to use a pre-determined output order) --->
|
||||
<cfif structKeyExists(arguments.payload[key], "_keylist")>
|
||||
<cfset keylist = arguments.payload[key]._keylist />
|
||||
<cfelse>
|
||||
<cfset keylist = structKeyList(arguments.payload[key]) />
|
||||
</cfif>
|
||||
<cfloop list="#keylist#" index="skey">
|
||||
<cfif ucase(skey) NEQ "_KEYLIST">
|
||||
<cfhttpparam name="#skey#" value="#arguments.payload[key][skey]#" type="#paramType#" encoded="#arguments.encoded#" />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
<cfelseif isArray(arguments.payload[key])>
|
||||
<cfloop array="#arguments.payload[key]#" index="skey">
|
||||
<cfhttpparam name="#key#" value="#skey#" type="#paramType#" encoded="#arguments.encoded#" />
|
||||
</cfloop>
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid data type for #key#" detail="The payload must be either XML/JSON/string or a struct" type="cfpayment.InvalidParameter.Payload" />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfelseif isSimpleValue(arguments.payload) AND len(arguments.payload)>
|
||||
|
||||
<!--- some services may need a Content-Type header of application/xml, pass it in as part of the headers array instead --->
|
||||
<cfhttpparam value="#arguments.payload#" type="body" />
|
||||
|
||||
<cfelse>
|
||||
|
||||
<cfthrow message="The payload must be either XML/JSON/string or a struct" type="cfpayment.InvalidParameter.Payload" />
|
||||
|
||||
</cfif>
|
||||
|
||||
<!--- Handle file uploads with files that already exist on local drive/network. Note, this must be after the cfhttparam type formfield lines --->
|
||||
<cfloop collection="#arguments.files#" item="key">
|
||||
<cfhttpparam name="#key#" file="#arguments.files[key]#" type="file" />
|
||||
</cfloop>
|
||||
</cfhttp>
|
||||
|
||||
<cfreturn CFHTTP />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getOption" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Options" type="any" required="true" />
|
||||
<cfargument name="Key" type="any" required="true" />
|
||||
<cfargument name="ErrorIfNotFound" type="boolean" default="false" />
|
||||
<cfif isStruct(arguments.Options) and structKeyExists(arguments.Options, arguments.Key)>
|
||||
<cfreturn arguments.Options[arguments.Key] />
|
||||
<cfelse>
|
||||
<cfif arguments.ErrorIfNotFound>
|
||||
<cfthrow message="Missing Option: #encodeForHTML(arguments.key)#" type="cfpayment.MissingParameter.Option" />
|
||||
<cfelse>
|
||||
<cfreturn "" />
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="verifyRequiredOptions" output="false" access="private" returntype="void" hint="I verify that the passed in Options structure exists for each item in the RequiredOptionList argument.">
|
||||
<cfargument name="options" type="struct" required="true"/>
|
||||
<cfargument name="requiredOptionList" type="string" required="true"/>
|
||||
<cfset var option="" />
|
||||
<cfloop list="#arguments.requiredOptionList#" index="option">
|
||||
<cfif not StructKeyExists(arguments.options, option)>
|
||||
<cfthrow message="Missing Required Option - #option#" type="cfpayment.MissingParameter.Option" />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="isValidPeriodicity" output="false" access="private" returntype="any" hint="I validate the the given periodicity is valid for the current gateway.">
|
||||
<cfargument name="periodicity" type="string" required="true"/>
|
||||
<cfif len(getPeriodicityValue(arguments.periodicity))>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getPeriodicityValue" output="false" access="private" returntype="any" hint="I return the gateway-specific value for the given normalized periodicity.">
|
||||
<cfargument name="periodicity" type="string" required="true"/>
|
||||
<cfif structKeyExists(variables.cfpayment.PERIODICITY_MAP, arguments.periodicity)>
|
||||
<cfreturn variables.cfpayment.PERIODICITY_MAP[arguments.periodicity] />
|
||||
<cfelse>
|
||||
<cfreturn "" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- gateways may on RARE occasion need to override the response object; being generated by the base gateway allows an implementation to override this --->
|
||||
<cffunction name="createResponse" access="public" output="false" returntype="any" hint="Create a response object with status set to unprocessed">
|
||||
<cfreturn createObject("component", "cfpayment.api.model.response").init(argumentCollection = arguments, service = getService(), testMode = getTestMode()) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- ------------------------------------------------------------------------------
|
||||
|
||||
PUBLIC API FOR USERS TO CALL AND FOR DEVELOPERS TO EXTEND
|
||||
|
||||
|
||||
------------------------------------------------------------------------- --->
|
||||
<!--- Stub out the public functions (these must be implemented in the gateway folders) --->
|
||||
<cffunction name="purchase" access="public" output="false" returntype="any" hint="Perform an authorization immediately followed by a capture">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="authorize" access="public" output="false" returntype="any" hint="Verifies payment details with merchant bank">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="capture" access="public" output="false" returntype="any" hint="Confirms an authorization with direction to charge the account">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="authorization" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="credit" access="public" output="false" returntype="any" hint="Returns an amount back to the previously charged account. Only for use with captured transactions.">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="transactionid" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="void" access="public" output="false" returntype="any" hint="Cancels a previously captured transaction that has not yet settled">
|
||||
<cfargument name="transactionid" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="search" access="public" output="false" returntype="any" hint="Find transactions using gateway-supported criteria">
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="status" access="public" output="false" returntype="any" hint="Reconstruct a response object for a previously executed transaction">
|
||||
<cfargument name="transactionid" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="recurring" access="public" output="false" returntype="any" hint="">
|
||||
<cfargument name="mode" type="string" required="true" /><!--- must be one of: add, edit, delete, get --->
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="settle" access="public" output="false" returntype="any" hint="Directs the merchant account to close the open batch of transactions (typically run once per day either automatically or manually with this method)">
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="supports" access="public" output="false" returntype="boolean" hint="Determine if gateway supports a specific card or account type">
|
||||
<cfargument name="type" type="any" required="true" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
<!--- determine capability of this gateway --->
|
||||
<cffunction name="getIsCCEnabled" access="public" output="false" returntype="boolean" hint="determine whether or not this gateway can accept credit card transactions">
|
||||
<cfreturn false />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getIsEFTEnabled" access="public" output="false" returntype="boolean" hint="determine whether or not this gateway can accept ACH/EFT transactions">
|
||||
<cfreturn false />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
BIN
cfpayment/api/gateway/basecommerce/BaseCommerceClient-4.2.4.jar
Normal file
BIN
cfpayment/api/gateway/basecommerce/BaseCommerceClient-4.2.4.jar
Normal file
Binary file not shown.
183
cfpayment/api/gateway/basecommerce/basecommerce.cfc
Normal file
183
cfpayment/api/gateway/basecommerce/basecommerce.cfc
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
component
|
||||
displayname='BaseCommerce Interface'
|
||||
output=false
|
||||
extends='cfpayment.api.gateway.base' {
|
||||
|
||||
variables.cfpayment.GATEWAY_NAME = 'BaseCommerce';
|
||||
variables.cfpayment.GATEWAY_VERSION = '1.0';
|
||||
|
||||
public string function getProcessorID() {
|
||||
return variables.cfpayment.ProcessorID;
|
||||
}
|
||||
|
||||
//Implement primary methods
|
||||
public any function purchase(required any money, required any account, struct options=structNew()) {
|
||||
arguments.options.batType = 'XS_BAT_TYPE_DEBIT';
|
||||
arguments.options.tokenId = arguments.account.getID();
|
||||
return populateResponse(transactionData(argumentcollection = arguments));
|
||||
}
|
||||
|
||||
public any function credit(required any money, required any account, struct options=structNew()) {
|
||||
arguments.options.batType = 'XS_BAT_TYPE_CREDIT';
|
||||
arguments.options.tokenId = arguments.account.getID();
|
||||
return populateResponse(transactionData(argumentcollection = arguments));
|
||||
}
|
||||
|
||||
public any function store(required any account, struct options=structNew()) {
|
||||
return populateResponse(accountData(account, options));
|
||||
}
|
||||
|
||||
//Private Functions
|
||||
private any function populateResponse(required struct data) {
|
||||
//Response object populated outside of the gateway connection methods (accountData, transactionData) to allow for mocking of data in offline unit tests
|
||||
local.response = createResponse();
|
||||
if(structKeyExists(arguments.data, 'status')) local.response.setStatus(arguments.data.status);
|
||||
if(structKeyExists(arguments.data, 'message') && isArray(arguments.data.message)) local.response.setMessage(arrayToList(arguments.data.message));
|
||||
if(structKeyExists(arguments.data, 'tokenId')) local.response.setTokenId(arguments.data.tokenId);
|
||||
if(structKeyExists(arguments.data, 'transactionId')) local.response.setTransactionId(arguments.data.transactionId);
|
||||
local.response.setParsedResult(arguments.data);
|
||||
local.response.setResult(serializeJson(arguments.data));
|
||||
return local.response;
|
||||
}
|
||||
|
||||
private struct function accountData(required any account, struct options=structNew()) {
|
||||
local.bankData = structNew();
|
||||
|
||||
if(getService().getAccountType(arguments.account) == 'eft') {
|
||||
local.bankAccountObj = createObject('java', 'com.basecommercepay.client.BankAccount');
|
||||
|
||||
//Populate bank account object data passed in to this object
|
||||
local.bankAccountObj.setName(trim(arguments.account.getFirstName() & ' ' & arguments.account.getLastName()));
|
||||
local.bankAccountObj.setAccountNumber(toString(arguments.account.getAccount()));
|
||||
local.bankAccountObj.setRoutingNumber(toString(arguments.account.getRoutingNumber()));
|
||||
local.bankAccountObj.setType(local.bankAccountObj[translateType(arguments.account.getAccountType())]);
|
||||
|
||||
//Set up connection object
|
||||
local.baseCommerceClientObj = createObject('java', 'com.basecommercepay.client.BaseCommerceClient');
|
||||
local.baseCommerceClientObj.init(variables.cfpayment.Username, variables.cfpayment.Password, variables.cfpayment.MerchantAccount);
|
||||
local.baseCommerceClientObj.setSandbox(variables.cfpayment.TestMode);
|
||||
|
||||
//Send account request to BaseCommerce api and update bank account object with result
|
||||
local.bankAccountObj = baseCommerceClientObj.addBankAccount(bankAccountObj);
|
||||
|
||||
//Get BaseCommerce returned data and insert into intermediate struct for later insertion into cfpayment response object
|
||||
local.bankData.status = translateStatus(local.bankAccountObj);
|
||||
local.bankData.message = local.bankAccountObj.getMessages();
|
||||
local.bankData.tokenId = local.bankAccountObj.getToken();
|
||||
local.bankData.type = translateType(local.bankAccountObj.getType());
|
||||
} else {
|
||||
local.bankData.status = translateStatus(local.bankAccountObj);
|
||||
local.bankData.message = ['Unsupported account type: "#getService().getAccountType(arguments.account)#"'];
|
||||
}
|
||||
|
||||
return local.bankData;
|
||||
}
|
||||
|
||||
private any function transactionData(required any money, any account, struct options=structNew()) {
|
||||
local.transactionData = structNew();
|
||||
local.bankAccountTransactionObj = createObject('java', 'com.basecommercepay.client.BankAccountTransaction');
|
||||
|
||||
//Populate transaction object with data passed into this method
|
||||
local.bankAccountTransactionObj.setType(local.bankAccountTransactionObj[arguments.options.batType]);
|
||||
local.bankAccountTransactionObj.setAmount(arguments.money.getAmount());
|
||||
local.bankAccountTransactionObj.setToken(arguments.options.tokenId);
|
||||
|
||||
//Check that transaction method is valid, otherwise return error
|
||||
try {
|
||||
//local.bankAccountTransactionObj[arguments.options.method] is accessing the java object's field, simmilar to accessing struct values in CF
|
||||
local.bankAccountTransactionObj.setMethod(local.bankAccountTransactionObj[translateSEC(arguments.options.sec)]);
|
||||
} catch(any e) {
|
||||
local.transactionData.status = getService().getStatusFailure();
|
||||
if(!structKeyExists(arguments.options, 'method') || !len(arguments.option.sec)) {
|
||||
local.transactionData.message = ['Missing transaction method in arguments.options'];
|
||||
}
|
||||
return local.transactionData;
|
||||
}
|
||||
|
||||
//Check that effective date (days from now) is a valid integer within range
|
||||
if(structKeyExists(arguments.options, 'effectiveDate') && isDate(arguments.options.effectiveDate)) {
|
||||
local.bankAccountTransactionObj.setEffectiveDate(arguments.options.effectiveDate);
|
||||
}
|
||||
|
||||
//Set up client connection object
|
||||
local.baseCommerceClientObj = createObject('java', 'com.basecommercepay.client.BaseCommerceClient');
|
||||
local.baseCommerceClientObj.init(variables.cfpayment.Username, variables.cfpayment.Password, variables.cfpayment.MerchantAccount);
|
||||
local.baseCommerceClientObj.setSandbox(variables.cfpayment.TestMode);
|
||||
|
||||
//Send transaction request to BaseCommerce api and update transaction object with result
|
||||
local.bankAccountTransactionObj = local.baseCommerceClientObj.processBankAccountTransaction(local.bankAccountTransactionObj);
|
||||
|
||||
//Extract data and handle errors
|
||||
if(local.bankAccountTransactionObj.isStatus(local.bankAccountTransactionObj.XS_BAT_STATUS_FAILED)) {
|
||||
local.transactionData.status = translateStatus(local.bankAccountTransactionObj);
|
||||
local.transactionData.message = local.bankAccountTransactionObj.getMessages();
|
||||
} else if(local.bankAccountTransactionObj.isStatus(local.bankAccountTransactionObj.XS_BAT_STATUS_CREATED)) {
|
||||
//Get BaseCommerce returned data and insert into intermediate struct for later insertion into cfpayment response object
|
||||
local.transactionData.tokenId = arguments.options.tokenId;
|
||||
local.transactionData.transactionId = local.bankAccountTransactionObj.getBankAccountTransactionId();
|
||||
local.transactionData.type = local.bankAccountTransactionObj.getType();
|
||||
local.transactionData.status = translateStatus(local.bankAccountTransactionObj);
|
||||
local.transactionData.effectiveDate = local.bankAccountTransactionObj.getEffectiveDate();
|
||||
local.transactionData.settlementDate = local.bankAccountTransactionObj.getSettlementDate();
|
||||
local.transactionData.accountType = local.bankAccountTransactionObj.getAccountType();
|
||||
local.transactionData.amount = local.bankAccountTransactionObj.getAmount();
|
||||
local.transactionData.merchantTransactionID = local.bankAccountTransactionObj.getMerchantTransactionID();
|
||||
local.transactionData.method = local.bankAccountTransactionObj.getMethod();
|
||||
} else {
|
||||
local.transactionData.status = translateStatus(local.bankAccountTransactionObj);
|
||||
local.transactionData.message = ['Status not expected: "#local.transactionData.getStatus()#"'];
|
||||
}
|
||||
|
||||
return local.transactionData;
|
||||
}
|
||||
|
||||
private any function translateStatus(required any basecommerce) {
|
||||
// the basecommerce object has static fields against which we can check for success/failure and map to cfpayment values
|
||||
if(structKeyExists(arguments.basecommerce,'XS_BAT_STATUS_FAILED') && arguments.basecommerce.isStatus(arguments.basecommerce['XS_BAT_STATUS_FAILED'])) {
|
||||
return getService().getStatusFailure();
|
||||
} else if(structKeyExists(arguments.basecommerce,'XS_BA_STATUS_FAILED') && arguments.basecommerce.isStatus(arguments.basecommerce.XS_BA_STATUS_FAILED)) {
|
||||
return getService().getStatusFailure();
|
||||
} else if(structKeyExists(arguments.basecommerce,'XS_BAT_STATUS_CREATED') && arguments.basecommerce.isStatus(arguments.basecommerce.XS_BAT_STATUS_CREATED)) {
|
||||
return getService().getStatusSuccessful();
|
||||
} else if(structKeyExists(arguments.basecommerce,'XS_BA_STATUS_ACTIVE') && arguments.basecommerce.isStatus(arguments.basecommerce.XS_BA_STATUS_ACTIVE)) {
|
||||
return getService().getStatusSuccessful();
|
||||
} else if(structKeyExists(arguments.basecommerce,'XS_BAT_STATUS_INITIATED') && arguments.basecommerce.isStatus(arguments.basecommerce.XS_BAT_STATUS_INITIATED)) {
|
||||
return getService().getStatusSuccessful();
|
||||
} else if(structKeyExists(arguments.basecommerce,'XS_BAT_STATUS_SETTLED') && arguments.basecommerce.isStatus(arguments.basecommerce.XS_BAT_STATUS_SETTLED)) {
|
||||
return getService().getStatusSuccessful();
|
||||
} else if(structKeyExists(arguments.basecommerce,'XS_BAT_STATUS_RETURNED') && arguments.basecommerce.isStatus(arguments.basecommerce.XS_BAT_STATUS_RETURNED)) {
|
||||
return getService().getStatusSuccessful();
|
||||
} else if(structKeyExists(arguments.basecommerce,'XS_BAT_STATUS_PENDING_SETTLEMENT') && arguments.basecommerce.isStatus(arguments.basecommerce.XS_BAT_STATUS_PENDING_SETTLEMENT)) {
|
||||
return getService().getStatusSuccessful();
|
||||
} else if(structKeyExists(arguments.basecommerce,'XS_BAT_STATUS_CANCELED') && arguments.basecommerce.isStatus(arguments.basecommerce.XS_BAT_STATUS_CANCELED)) {
|
||||
return getService().getStatusSuccessful();
|
||||
}
|
||||
// if we get here, we don't know what the result is
|
||||
throw(type = 'BaseCommerce Status', message = 'Unknown BaseCommerce Status: #arguments.status#');
|
||||
}
|
||||
|
||||
private string function translateSEC(required string sec) {
|
||||
if(arguments.sec == 'CCD') {
|
||||
return 'XS_BAT_METHOD_CCD';
|
||||
} else if(arguments.sec == 'PPD') {
|
||||
return 'XS_BAT_METHOD_PPD';
|
||||
} else if(arguments.sec == 'WEB') {
|
||||
return 'XS_BAT_METHOD_WEB';
|
||||
} else if(arguments.sec == 'TEL') {
|
||||
return 'XS_BAT_METHOD_TEL';
|
||||
}
|
||||
|
||||
// if we get here, we don't know what the result is
|
||||
throw(type = 'BaseCommerce Method', message = 'Unknown Account SEC: #arguments.sec#');
|
||||
}
|
||||
|
||||
private string function translateType(required string accountType) {
|
||||
if(arguments.accountType == 'CHECKING') {
|
||||
return 'XS_BA_TYPE_CHECKING';
|
||||
} else if(arguments.accountType == 'SAVINGS') {
|
||||
return 'XS_BA_TYPE_SAVINGS';
|
||||
}
|
||||
// if we get here, we don't know what the result is
|
||||
throw(type = 'BaseCommerce Type', message = 'Unknown Account Type: #arguments.accountType#');
|
||||
}
|
||||
}
|
||||
380
cfpayment/api/gateway/basecommerce/tests/BaseCommerceTest.cfc
Normal file
380
cfpayment/api/gateway/basecommerce/tests/BaseCommerceTest.cfc
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
component
|
||||
displayname='BaseCommerce Tests'
|
||||
output=false
|
||||
extends='mxunit.framework.TestCase' {
|
||||
|
||||
public void function setUp() {
|
||||
local.gw.path = 'basecommerce.basecommerce';
|
||||
//Test account
|
||||
local.gw.Username = '';
|
||||
local.gw.Password = '';
|
||||
local.gw.MerchantAccount = '';
|
||||
local.gw.TestMode = true;
|
||||
|
||||
// create gw and get reference
|
||||
variables.svc = createObject('component', 'cfpayment.api.core').init(local.gw);
|
||||
variables.gw = variables.svc.getGateway();
|
||||
|
||||
//if set to false, will try to connect to remote service to check these all out
|
||||
variables.localMode = true;
|
||||
variables.debugMode = false;
|
||||
}
|
||||
|
||||
private void function offlineInjector(required any receiver, required any giver, required string functionName, string functionNameInReceiver='') {
|
||||
if(variables.localMode) {
|
||||
injectMethod(arguments.receiver, arguments.giver, arguments.functionName, arguments.functionNameInReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
private void function standardResponseTests(required any response) {
|
||||
if(variables.debugMode) {
|
||||
debug(arguments.response.getParsedResult());
|
||||
debug(arguments.response.getResult());
|
||||
}
|
||||
if(isSimpleValue(arguments.response)) assertTrue(false, 'Response returned a simple value: "#arguments.response#"');
|
||||
assertTrue(isObject(arguments.response), 'Invalid: response is not an object');
|
||||
if(arguments.response.hasError()) {
|
||||
if(arrayLen(arguments.response.getMessage())) {
|
||||
assertTrue(false, 'Message returned from BaseCommerce: <br />#arrayToList(arguments.response.getMessage(), "<br />")#');
|
||||
} else {
|
||||
assertTrue(false, 'Error found but no error message attached');
|
||||
}
|
||||
}
|
||||
if(isSimpleValue(arguments.response.getParsedResult())) assertTrue(false, 'Parsed response is a string, expected a structure. Returned string = "#arguments.response.getParsedResult()#"');
|
||||
assertTrue(isStruct(arguments.response.getParsedResult()), 'Parsed response is not a structure');
|
||||
assertFalse(structIsEmpty(arguments.response.getParsedResult()), 'Parsed response structure is empty');
|
||||
assertTrue(arguments.response.getSuccess(), 'Success flag indicates failure');
|
||||
}
|
||||
|
||||
private void function standardErrorResponseTests(required any response) {
|
||||
if(variables.debugMode) {
|
||||
debug(arguments.response.haserror());
|
||||
debug(arguments.response.getMessage());
|
||||
}
|
||||
if(isSimpleValue(arguments.response)) assertTrue(false, 'Response returned a simple value: "#arguments.response#"');
|
||||
assertTrue(isObject(arguments.response), 'Invalid: response is not an object');
|
||||
assertTrue(arguments.response.hasError(), 'No errors indicated in response');
|
||||
assertTrue(isSimpleValue(arguments.response.getMessage()), 'Error Message response not a string');
|
||||
assertTrue(len(arguments.response.getMessage()), 'No error messages available');
|
||||
assertFalse(arguments.response.getSuccess(), 'Success flag indicates success, but should indicate failure');
|
||||
}
|
||||
|
||||
//TESTS
|
||||
public void function testCreateAccount() {
|
||||
createAccountTest();
|
||||
}
|
||||
|
||||
public void function testCreditAccount() {
|
||||
local.accountToken = createAccountTest();
|
||||
|
||||
//Credit account
|
||||
local.account = variables.svc.createToken(id = local.accountToken.getTokenId());
|
||||
local.options = structNew();
|
||||
local.options.sec = 'CCD'; //XS_BAT_METHOD_CCD, XS_BAT_METHOD_PPD, XS_BAT_METHOD_TEL, XS_BAT_METHOD_WEB
|
||||
local.options.effectiveDate = dateAdd('d', 8, now());
|
||||
offlineInjector(variables.gw, this, 'mockCreditAccountOk', 'transactionData');
|
||||
local.credit = variables.gw.credit(money = variables.svc.createMoney(500, 'USD'), account = local.account, options = local.options);
|
||||
standardResponseTests(local.credit);
|
||||
assertTrue(local.credit.getParsedResult().amount == 5, 'The credit amount requested and the actual credit given is different, should be 5, is: #local.credit.getParsedResult().amount#');
|
||||
assertTrue(local.credit.getTransactionId() > 0, 'Invalid transaction id returned: #local.credit.getTransactionId()#');
|
||||
assertTrue(local.credit.getParsedResult().type == 'CREDIT', 'Incorrect transaction type, should be "CREDIT", is: "#local.credit.getParsedResult().type#"');
|
||||
}
|
||||
|
||||
public void function testDebitAccount() {
|
||||
local.accountToken = createAccountTest();
|
||||
|
||||
//Debit account
|
||||
local.account = variables.svc.createToken(id = local.accountToken.getTokenId());
|
||||
local.options = structNew();
|
||||
local.options.sec = 'CCD'; //XS_BAT_METHOD_CCD, XS_BAT_METHOD_PPD, XS_BAT_METHOD_TEL, XS_BAT_METHOD_WEB
|
||||
offlineInjector(variables.gw, this, 'mockDebitAccountOk', 'transactionData');
|
||||
local.debit = variables.gw.purchase(money = variables.svc.createMoney(400, 'USD'), account = local.account, options = local.options);
|
||||
standardResponseTests(local.debit);
|
||||
assertTrue(local.debit.getParsedResult().amount == 4, 'The credit amount requested and the actual credit given is different, should be 4, is: #local.debit.getParsedResult().amount#');
|
||||
assertTrue(local.debit.getTransactionId() > 0, 'Invalid transaction id returned: #local.debit.getTransactionId()#');
|
||||
assertTrue(local.debit.getParsedResult().type == 'DEBIT', 'Incorrect transaction type, should be "CREDIT", is: "#local.debit.getParsedResult().type#"');
|
||||
}
|
||||
|
||||
public void function testCreateInvalidAccountFails() {
|
||||
local.argumentCollection = structNew();
|
||||
local.accountNumberString = '7';
|
||||
local.argumentCollection.account = createInvalidAccount(local.accountNumberString);
|
||||
offlineInjector(variables.gw, this, 'mockCreateInvalidAccountFails', 'accountData');
|
||||
local.accountToken = variables.gw.store(argumentCollection = local.argumentCollection);
|
||||
standardErrorResponseTests(local.accountToken);
|
||||
assertTrue(local.accountToken.getMessage() == 'Account Number must be at least 5 digits', 'Incorrect error message: "#local.accountToken.getMessage()#", expected: "Account Number must be at least 5 digits"');
|
||||
}
|
||||
|
||||
public void function testCreateAccountWithInvalidRoutingNumberFails() {
|
||||
local.argumentCollection = structNew();
|
||||
local.accountRoutingNumberString = '123';
|
||||
local.argumentCollection.account = createAccountWithInvalidRoutingNumber(local.accountRoutingNumberString);
|
||||
offlineInjector(variables.gw, this, 'mockCreateAccountWithInvalidRoutingNumberFails', 'accountData');
|
||||
local.accountToken = variables.gw.store(argumentCollection = local.argumentCollection);
|
||||
standardErrorResponseTests(local.accountToken);
|
||||
assertTrue(local.accountToken.getMessage() == 'Invalid Routing Number', 'Incorrect error message: "#local.accountToken.getMessage()#", expected: "Invalid Routing Number"');
|
||||
}
|
||||
|
||||
public void function testCreateAccountWithInvalidAccountTypeFails() mxunit:expectedException='BaseCommerce Type' {
|
||||
local.argumentCollection = structNew();
|
||||
local.argumentCollection.account = createAccountWithInvalidAccountType('XS_BA_TYPE_THISWILLFAIL');
|
||||
offlineInjector(variables.gw, this, 'mockCreateAccountWithInvalidAccountTypeFails', 'accountData');
|
||||
variables.gw.store(argumentCollection = local.argumentCollection);
|
||||
}
|
||||
|
||||
public void function testCreateAccountWithMissingAccountTypeFails() mxunit:expectedException='BaseCommerce Type' {
|
||||
local.argumentCollection = structNew();
|
||||
local.argumentCollection.account = createAccountWithMissingAccountType();
|
||||
offlineInjector(variables.gw, this, 'mockCreateAccountWithMissingAccountTypeFails', 'accountData');
|
||||
variables.gw.store(argumentCollection = local.argumentCollection);
|
||||
}
|
||||
|
||||
public void function testCreditAccountWithInvalidAmountFails() {
|
||||
local.accountToken = createAccountTest();
|
||||
|
||||
//Credit account (unsuccessfully)
|
||||
local.account = variables.svc.createToken(id = local.accountToken.getTokenId());
|
||||
local.options = structNew();
|
||||
local.options.sec = 'CCD'; //XS_BAT_METHOD_CCD, XS_BAT_METHOD_PPD, XS_BAT_METHOD_TEL, XS_BAT_METHOD_WEB
|
||||
offlineInjector(variables.gw, this, 'mockCreditDebitAccountWithInvalidAmountFails', 'transactionData');
|
||||
local.credit = variables.gw.credit(money = variables.svc.createMoney(-1000, 'USD'), account = local.account, options = local.options);
|
||||
standardErrorResponseTests(local.credit);
|
||||
assertTrue(local.credit.getMessage() == 'Invalid Amount', 'Incorrect error message: "#local.credit.getMessage()#", expected: "Invalid Amount"');
|
||||
}
|
||||
|
||||
public void function testDebitAccountWithInvalidAmountFails() {
|
||||
local.accountToken = createAccountTest();
|
||||
|
||||
//Credit account (unsuccessfully)
|
||||
local.account = variables.svc.createToken(id = local.accountToken.getTokenId());
|
||||
local.options = structNew();
|
||||
local.options.sec = 'CCD'; //XS_BAT_METHOD_CCD, XS_BAT_METHOD_PPD, XS_BAT_METHOD_TEL, XS_BAT_METHOD_WEB
|
||||
offlineInjector(variables.gw, this, 'mockCreditDebitAccountWithInvalidAmountFails', 'transactionData');
|
||||
local.debit = variables.gw.credit(money = variables.svc.createMoney(-2, 'USD'), account = local.account, options = local.options);
|
||||
standardErrorResponseTests(local.debit);
|
||||
assertTrue(local.debit.getMessage() == 'Invalid Amount', 'Incorrect error message: "#local.debit.getMessage()#", expected: "Invalid Amount"');
|
||||
}
|
||||
|
||||
public void function testCreditAccountWithInvalidAccountTokenFails() {
|
||||
local.account = variables.svc.createToken(id = 'lk1j43k324h32j4h32hk***FAKE***32j4h3k432kh43jkh');
|
||||
local.options = structNew();
|
||||
local.options.sec = 'CCD'; //XS_BAT_METHOD_CCD, XS_BAT_METHOD_PPD, XS_BAT_METHOD_TEL, XS_BAT_METHOD_WEB
|
||||
offlineInjector(variables.gw, this, 'mockCreditAccountWithInvalidAccountTokenFails', 'transactionData');
|
||||
local.credit = variables.gw.credit(money = variables.svc.createMoney(-1000, 'USD'), account = local.account, options = local.options);
|
||||
standardErrorResponseTests(local.credit);
|
||||
assertTrue(local.credit.getMessage() == 'No bank account exists for given token', 'Incorrect error message: "#local.credit.getMessage()#", expected: "No bank account exists for given token"');
|
||||
}
|
||||
|
||||
public void function testCreditAccountWithInvalidMethodFails() {
|
||||
local.accountToken = createAccountTest();
|
||||
|
||||
//Credit account (unsuccessfully)
|
||||
local.account = variables.svc.createToken(id = local.accountToken.getTokenId());
|
||||
local.options = structNew();
|
||||
local.options.sec = 'THISWILLFAIL'; //XS_BAT_METHOD_CCD, XS_BAT_METHOD_PPD, XS_BAT_METHOD_TEL, XS_BAT_METHOD_WEB
|
||||
offlineInjector(variables.gw, this, 'mockCreditAccountWithInvalidMethodFails', 'transactionData');
|
||||
local.credit = variables.gw.credit(money = variables.svc.createMoney(1500, 'USD'), account = local.account, options = local.options);
|
||||
standardErrorResponseTests(local.credit);
|
||||
assertTrue(local.credit.getMessage() == 'Invalid transaction method passed in: XS_BAT_METHOD_#local.options.sec#', 'Incorrect error message: "#local.credit.getMessage()#", expected: "Invalid transaction method passed in: #local.options.sec#"');
|
||||
}
|
||||
|
||||
public void function testCreditAccountFutureEffectiveDate() {
|
||||
local.accountToken = createAccountTest();
|
||||
|
||||
//Credit account
|
||||
local.account = variables.svc.createToken(id = local.accountToken.getTokenId());
|
||||
local.effectiveDate = dateAdd('d', 4, nextSaturday()); // Wednesday of next week
|
||||
local.options = structNew();
|
||||
local.options.sec = 'CCD'; //XS_BAT_METHOD_CCD, XS_BAT_METHOD_PPD, XS_BAT_METHOD_TEL, XS_BAT_METHOD_WEB
|
||||
local.options.effectiveDate = local.effectiveDate;
|
||||
offlineInjector(variables.gw, this, 'mockCreditAccountFutureEffectiveDate', 'transactionData');
|
||||
local.credit = variables.gw.credit(money = variables.svc.createMoney(500, 'USD'), account = local.account, options = local.options);
|
||||
standardResponseTests(local.credit);
|
||||
assertTrue(dateCompare(local.effectiveDate, local.credit.getParsedResult().effectiveDate) == 0, 'Posted effective date (#local.effectiveDate#) and confirmed effective date (#local.credit.getParsedResult().effectiveDate#) don''t match');
|
||||
}
|
||||
|
||||
public void function testCreditAccountPastEffectiveDate() {
|
||||
local.accountToken = createAccountTest();
|
||||
|
||||
//Credit account
|
||||
local.account = variables.svc.createToken(id = local.accountToken.getTokenId());
|
||||
local.effectiveDate = dateAdd('d', -4, removeTimePart(now())); //4 days ago
|
||||
local.options = structNew();
|
||||
local.options.sec = 'CCD'; //XS_BAT_METHOD_CCD, XS_BAT_METHOD_PPD, XS_BAT_METHOD_TEL, XS_BAT_METHOD_WEB
|
||||
local.options.effectiveDate = local.effectiveDate;
|
||||
offlineInjector(variables.gw, this, 'mockCreditAccountPastEffectiveDate', 'transactionData');
|
||||
local.credit = variables.gw.credit(money = variables.svc.createMoney(500, 'USD'), account = local.account, options = local.options);
|
||||
standardResponseTests(local.credit);
|
||||
assertTrue(dateCompare(local.effectiveDate, local.credit.getParsedResult().effectiveDate) < 0, 'Posted date is in the past, returned effective date should be ammended to curtrent date but isn''t');
|
||||
}
|
||||
|
||||
public void function testCreditAccountWeekendEffectiveDateMovedToWeekDay() {
|
||||
local.accountToken = createAccountTest();
|
||||
|
||||
//Credit account
|
||||
local.account = variables.svc.createToken(id = local.accountToken.getTokenId());
|
||||
local.effectiveDate = nextSaturday();
|
||||
local.options = structNew();
|
||||
local.options.sec = 'CCD'; //XS_BAT_METHOD_CCD, XS_BAT_METHOD_PPD, XS_BAT_METHOD_TEL, XS_BAT_METHOD_WEB
|
||||
local.options.effectiveDate = local.effectiveDate;
|
||||
offlineInjector(variables.gw, this, 'mockCreditAccountWeekendEffectiveDateMovedToWeekDay', 'transactionData');
|
||||
local.credit = variables.gw.credit(money = variables.svc.createMoney(500, 'USD'), account = local.account, options = local.options);
|
||||
standardResponseTests(local.credit);
|
||||
assertTrue(dateCompare(local.effectiveDate, local.credit.getParsedResult().effectiveDate) < 0, 'Posted date is on the weekend, returned effective date should be ammended to next working day but isn''t');
|
||||
}
|
||||
|
||||
public void function testCreditAccountSettlementDateIsTheBusinessDayAfterEffectiveDay() {
|
||||
local.accountToken = createAccountTest();
|
||||
|
||||
//Credit account
|
||||
local.account = variables.svc.createToken(id = local.accountToken.getTokenId());
|
||||
local.effectiveDate = dateAdd('d', 4, nextSaturday()); // Wednesday of next week
|
||||
local.options = structNew();
|
||||
local.options.sec = 'CCD'; //XS_BAT_METHOD_CCD, XS_BAT_METHOD_PPD, XS_BAT_METHOD_TEL, XS_BAT_METHOD_WEB
|
||||
local.options.effectiveDate = local.effectiveDate;
|
||||
offlineInjector(variables.gw, this, 'mockCreditAccountSettlementDateIsTheBusinessDayAfterEffectiveDay', 'transactionData');
|
||||
local.credit = variables.gw.credit(money = variables.svc.createMoney(500, 'USD'), account = local.account, options = local.options);
|
||||
standardResponseTests(local.credit);
|
||||
assertTrue(dateDiff('d', local.effectiveDate, local.credit.getParsedResult().settlementdate) == 1, 'The settlement date should be the next working day after the effective day');
|
||||
}
|
||||
|
||||
//HELPERS
|
||||
private any function createAccountTest() {
|
||||
local.argumentCollection = structNew();
|
||||
local.argumentCollection.account = createAccount();
|
||||
offlineInjector(variables.gw, this, 'mockCreateAccountOk', 'accountData');
|
||||
local.accountToken = gw.store(argumentCollection = local.argumentCollection);
|
||||
standardResponseTests(local.accountToken);
|
||||
assertTrue(local.accountToken.getTokenId() != '', 'Token not returned');
|
||||
return local.accountToken;
|
||||
}
|
||||
|
||||
private date function nextSaturday(date day=now()) {
|
||||
//Saturday is day 7, subtract today from that to receive next saturday's date
|
||||
arguments.day = dateAdd('d', 7-dayOfWeek(arguments.day), removeTimePart(arguments.day));
|
||||
return arguments.day;
|
||||
}
|
||||
|
||||
private date function removeTimePart(date day=now()) {
|
||||
return createDate(year(arguments.day), month(arguments.day), day(arguments.day));
|
||||
}
|
||||
|
||||
private any function createAccount() {
|
||||
local.account = variables.svc.createEFT();
|
||||
local.account.setFirstName('John');
|
||||
local.account.setLastName('Doe');
|
||||
local.account.setAddress('123 Comox Street');
|
||||
local.account.setAddress2('West End');
|
||||
local.account.setCity('Vancouver');
|
||||
local.account.setRegion('BC');
|
||||
local.account.setPostalCode('V6G1S2');
|
||||
local.account.setCountry('Canada');
|
||||
local.account.setPhoneNumber('0123456789');
|
||||
local.account.setAccount(123123123123);
|
||||
local.account.setRoutingNumber(021000021);
|
||||
local.account.setCheckNumber();
|
||||
local.account.setAccountType('checking');
|
||||
local.account.setSEC();
|
||||
return local.account;
|
||||
}
|
||||
|
||||
private any function createInvalidAccount(required string accountNumberString) {
|
||||
local.account = createAccount();
|
||||
local.account.setAccount(arguments.accountNumberString);
|
||||
return local.account;
|
||||
}
|
||||
|
||||
private any function createAccountWithInvalidRoutingNumber(required string accountRoutingNumberString) {
|
||||
local.account = createAccount();
|
||||
local.account.setRoutingNumber(arguments.accountRoutingNumberString);
|
||||
return local.account;
|
||||
}
|
||||
|
||||
private any function createAccountWithInvalidAccountType(required string accountTypeString) {
|
||||
local.account = createAccount();
|
||||
local.account.setAccountType(arguments.accountTypeString);
|
||||
return local.account;
|
||||
}
|
||||
|
||||
private any function createAccountWithMissingAccountType() {
|
||||
local.account = createAccount();
|
||||
local.account.setAccountType('');
|
||||
return local.account;
|
||||
}
|
||||
|
||||
//MOCKS
|
||||
private any function mockCreditAccountOk() {
|
||||
return { "MERCHANTTRANSACTIONID":0,"EFFECTIVEDATE":"April, 06 2015 00:00:00","TRANSACTIONID":44067,"ACCOUNTTYPE":"CHECKING","METHOD":"CCD","AMOUNT":5.0,"STATUS":0,"SETTLEMENTDATE":"April, 07 2015 00:00:00","TYPE":"CREDIT" };
|
||||
}
|
||||
|
||||
private any function mockCreateAccountOk() {
|
||||
return { status=0, tokenId = 'a347d5a9bc92015fe68871403775f012d204002f9f8419590d4363088376c20e', type = 'CHECKING'};
|
||||
}
|
||||
|
||||
private any function mockDebitAccountOk() {
|
||||
return { "MERCHANTTRANSACTIONID":0,"EFFECTIVEDATE":"April, 06 2015 00:00:00","TRANSACTIONID":44068,"ACCOUNTTYPE":"CHECKING","METHOD":"CCD","AMOUNT":4.0,"STATUS":0,"SETTLEMENTDATE":"April, 07 2015 00:00:00","TYPE":"DEBIT" };
|
||||
}
|
||||
|
||||
private any function mockCreateInvalidAccountFails() {
|
||||
return { Status = 3, message = ['Account Number must be at least 5 digits'] };
|
||||
}
|
||||
|
||||
private any function mockCreateAccountWithInvalidRoutingNumberFails() {
|
||||
return { Status = 3, message = ['Invalid Routing Number'] };
|
||||
}
|
||||
|
||||
private any function mockCreateAccountWithInvalidAccountTypeFails() {
|
||||
throw(type = 'BaseCommerce Type', message = 'Unknown Account Type: XS_BA_TYPE_THISWILLFAIL');
|
||||
}
|
||||
|
||||
private any function mockCreateAccountWithMissingAccountTypeFails() {
|
||||
throw(type = 'BaseCommerce Type', message = 'Unknown Account Type: ');
|
||||
}
|
||||
|
||||
private any function mockCreateAccountWithMissingAccountType() {
|
||||
return { Status = 3, message = ['Missing account type'] };
|
||||
}
|
||||
|
||||
private any function mockCreditDebitAccountWithInvalidAmountFails() {
|
||||
return { Status = 3, message = ['Invalid Amount'] };
|
||||
}
|
||||
|
||||
private any function mockCreditAccountWithInvalidAccountTokenFails() {
|
||||
return { Status = 3, message = ['No bank account exists for given token'] };
|
||||
}
|
||||
|
||||
private any function mockCreditAccountWithInvalidMethodFails() {
|
||||
return { Status = 3, message = ['Invalid transaction method passed in: XS_BAT_METHOD_THISWILLFAIL'] };
|
||||
}
|
||||
|
||||
private any function mockCreditAccountWithInvalideffectiveDateDaysFromNowFails() {
|
||||
return { Status = 3, message = ['Effective date (days from now) must be 0 or greater'] };
|
||||
}
|
||||
|
||||
private any function mockCreditAccountSettlementDateIsTheBusinessDayAfterEffectiveDay() {
|
||||
local.nextSaturday = dateAdd('d', 7-dayOfWeek(now()), now());
|
||||
local.effectiveDate = dateFormat(dateAdd('d', 4, local.nextSaturday), 'Mmm, dd yyyy') & ' 00:00:00';
|
||||
local.settlementDate = dateFormat(dateAdd('d', 5, local.nextSaturday), 'Mmm, dd yyyy') & ' 00:00:00';
|
||||
return {"MERCHANTTRANSACTIONID":0,"EFFECTIVEDATE":"#local.effectiveDate#","TRANSACTIONID":44102,"ACCOUNTTYPE":"CHECKING","METHOD":"CCD","AMOUNT":5.0,"STATUS":0,"SETTLEMENTDATE":"#local.settlementDate#","TYPE":"CREDIT"};
|
||||
}
|
||||
|
||||
private any function mockCreditAccountWeekendEffectiveDateMovedToWeekDay() {
|
||||
local.nextSaturday = dateAdd('d', 7-dayOfWeek(now()), now());
|
||||
local.effectiveDate = dateFormat(dateAdd('d', 2, local.nextSaturday), 'Mmm, dd yyyy') & ' 00:00:00';
|
||||
local.settlementDate = dateFormat(dateAdd('d', 3, local.nextSaturday), 'Mmm, dd yyyy') & ' 00:00:00';
|
||||
return {"MERCHANTTRANSACTIONID":0,"EFFECTIVEDATE":"#local.effectiveDate#","TRANSACTIONID":44158,"ACCOUNTTYPE":"CHECKING","METHOD":"CCD","AMOUNT":5.0,"STATUS":0,"SETTLEMENTDATE":"#local.settlementDate#","TYPE":"CREDIT"};
|
||||
}
|
||||
|
||||
private any function mockCreditAccountPastEffectiveDate() {
|
||||
local.effectiveDate = dateFormat(now(), 'Mmm, dd yyyy') & ' 00:00:00';
|
||||
local.settlementDate = dateFormat(dateAdd('d', 1, now()), 'Mmm, dd yyyy') & ' 00:00:00';
|
||||
return {"MERCHANTTRANSACTIONID":0,"EFFECTIVEDATE":"#local.effectiveDate#","TRANSACTIONID":44160,"ACCOUNTTYPE":"CHECKING","METHOD":"CCD","AMOUNT":5.0,"STATUS":0,"SETTLEMENTDATE":"#local.settlementDate#","TYPE":"CREDIT"};
|
||||
}
|
||||
|
||||
private any function mockCreditAccountFutureEffectiveDate() {
|
||||
local.nextSaturday = dateAdd('d', 7-dayOfWeek(now()), now());
|
||||
local.effectiveDate = dateFormat(dateAdd('d', 4, local.nextSaturday), 'Mmm, dd yyyy') & ' 00:00:00';
|
||||
local.settlementDate = dateFormat(dateAdd('d', 5, local.nextSaturday), 'Mmm, dd yyyy') & ' 00:00:00';
|
||||
return {"MERCHANTTRANSACTIONID":0,"EFFECTIVEDATE":"#local.effectiveDate#","TRANSACTIONID":44161,"ACCOUNTTYPE":"CHECKING","METHOD":"CCD","AMOUNT":5.0,"STATUS":0,"SETTLEMENTDATE":"#local.settlementDate#","TYPE":"CREDIT"};
|
||||
}
|
||||
}
|
||||
106
cfpayment/api/gateway/bogus/gateway.cfc
Normal file
106
cfpayment/api/gateway/bogus/gateway.cfc
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
<cfcomponent displayname="Gateway" extends="cfpayment.api.gateway.base" output="false" hint="Bogus gateway demonstrates an implementation">
|
||||
|
||||
<!--- gateway specific variables --->
|
||||
<cfset variables.cfpayment.GATEWAYID = "2" />
|
||||
<cfset variables.cfpayment.GATEWAY_NAME = "Bogus Gateway" />
|
||||
<cfset variables.cfpayment.GATEWAY_VERSION = "1.1" />
|
||||
<cfset variables.cfpayment.Authorization = "51515" />
|
||||
<cfset variables.cfpayment.SuccessMessage = "Bogus Gateway: Forced success; use CC number 1 for success, 2 for decline, anything else for error" />
|
||||
<cfset variables.cfpayment.DeclineMessage = "Bogus Gateway: Forced failure; use CC number 1 for success, 2 for decline, anything else for error" />
|
||||
<cfset variables.cfpayment.ErrorMessage = "Bogus Gateway: Forced Error; use CC number 1 for success, 2 for decline, anything else for error" />
|
||||
|
||||
|
||||
<cffunction name="init" access="public" output="false" returntype="any">
|
||||
<cfset super.init(argumentCollection = arguments) />
|
||||
<!--- setup static variables --->
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- implemented functions --->
|
||||
<cffunction name="purchase" output="false" access="public" returntype="any" hint="Perform an authorization immediately followed by a capture">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<!--- first try the authorize --->
|
||||
<cfset var res = authorize(argumentCollection = arguments) />
|
||||
|
||||
<!--- For demonstration purposes, we just roll from Authorization to Capture but most
|
||||
gateways have a separate routine that does both actions at once. This is often called
|
||||
"Sale" or something similar. In that case, your purchase() would be different than authorize()+capture() --->
|
||||
<cfif res.getSuccess()>
|
||||
<cfreturn capture(money = arguments.money, authorization = res.getAuthorization(), options = arguments.options) />
|
||||
<cfelse>
|
||||
<cfreturn res />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="authorize" output="false" access="public" returntype="any" hint="Verifies payment details with merchant bank">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfset var response = createResponse() />
|
||||
|
||||
<!--- Just for demonstration purposes; pass CC# 1 for sucecss, CC# 2 for failure, anything else for exception --->
|
||||
<cfswitch expression="#arguments.account.getAccount()#">
|
||||
<cfcase value="1">
|
||||
<cfset response.setMessage(variables.cfpayment.SuccessMessage) />
|
||||
<cfset response.setAuthorization(123456) />
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
</cfcase>
|
||||
<cfcase value="2">
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
<cfset response.setMessage(variables.cfpayment.DeclineMessage) />
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfset response.setMessage(variables.cfpayment.ErrorMessage) />
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="capture" output="false" access="public" returntype="any" hint="Confirms an authorization with direction to charge the account">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="authorization" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfset var response = createResponse() />
|
||||
|
||||
<cfswitch expression="#arguments.authorization#">
|
||||
<cfcase value="123456">
|
||||
<cfset response.setMessage(variables.cfpayment.SuccessMessage) />
|
||||
<cfset response.setAuthorization(123456) />
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
<cfset response.setMessage(variables.cfpayment.DeclineMessage) />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
<cfreturn response />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="process" output="false" access="public" returntype="any">
|
||||
<cfargument name="method" type="string" required="false" default="post" />
|
||||
<cfargument name="payload" type="any" required="true" /><!--- can be xml (simplevalue) or a struct of key-value pairs --->
|
||||
<cfargument name="headers" type="struct" required="false" />
|
||||
|
||||
<cfreturn createResponse() />
|
||||
|
||||
</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>
|
||||
|
||||
</cfcomponent>
|
||||
37
cfpayment/api/gateway/bogus/unittest.cfc
Normal file
37
cfpayment/api/gateway/bogus/unittest.cfc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<cfcomponent displayname="Gateway" extends="cfpayment.api.gateway.base" output="false" hint="Bogus gateway demonstrates an implementation">
|
||||
|
||||
<!--- THIS GATEWAY IS ONLY FOR UNIT TEST PURPOSES --->
|
||||
|
||||
<!--- gateway specific variables --->
|
||||
<cfset variables.cfpayment.GATEWAYID = "2" />
|
||||
<cfset variables.cfpayment.GATEWAY_NAME = "Bogus Gateway" />
|
||||
<cfset variables.cfpayment.GATEWAY_VERSION = "1.1" />
|
||||
<cfset variables.cfpayment.GATEWAY_TEST_URL = "http://localhost/" />
|
||||
<cfset variables.cfpayment.GATEWAY_LIVE_URL = "http://localhost/" />
|
||||
<cfset variables.cfpayment.Authorization = "51515" />
|
||||
<cfset variables.cfpayment.SuccessMessage = "Bogus Gateway: Forced success; use CC number 1 for success, 2 for decline, anything else for error" />
|
||||
<cfset variables.cfpayment.DeclineMessage = "Bogus Gateway: Forced failure; use CC number 1 for success, 2 for decline, anything else for error" />
|
||||
<cfset variables.cfpayment.ErrorMessage = "Bogus Gateway: Forced Error; use CC number 1 for success, 2 for decline, anything else for error" />
|
||||
|
||||
|
||||
<cffunction name="init" access="public" output="false" returntype="any">
|
||||
<cfset super.init(argumentCollection = arguments) />
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="process" output="false" access="public" returntype="any">
|
||||
<cfargument name="method" type="string" required="false" default="post" />
|
||||
<cfargument name="payload" type="any" required="true" /><!--- can be xml (simplevalue) or a struct of key-value pairs --->
|
||||
<cfargument name="headers" type="struct" required="false" />
|
||||
|
||||
<cfreturn createResponse(argumentCollection = super.process(argumentCollection = arguments)) />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getIsCCEnabled" output="false" access="public" returntype="boolean" hint="determine whether or not this gateway can accept credit card transactions">
|
||||
<cfreturn true />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
927
cfpayment/api/gateway/braintree/braintree.cfc
Normal file
927
cfpayment/api/gateway/braintree/braintree.cfc
Normal file
|
|
@ -0,0 +1,927 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2008 Brian Ghidinelli (http://www.ghidinelli.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="Braintree Interface" extends="cfpayment.api.gateway.base" hint="Braintree Gateway" output="false">
|
||||
|
||||
<cfset variables.cfpayment.GATEWAY_NAME = "Braintree" />
|
||||
<cfset variables.cfpayment.GATEWAY_VERSION = "1.0" />
|
||||
<!--- braintree test mode uses different username/password instead of different urls --->
|
||||
<cfset variables.cfpayment.GATEWAY_LIVE_URL = "https://secure.braintreepaymentgateway.com/api/transact.php" />
|
||||
<cfset variables.cfpayment.GATEWAY_TEST_URL = variables.cfpayment.GATEWAY_LIVE_URL />
|
||||
<cfset variables.cfpayment.GATEWAY_REPORT_URL = "https://secure.braintreepaymentgateway.com/api/query.php" />
|
||||
|
||||
<cfset variables.braintree = structNew() />
|
||||
<cfset variables.braintree["100"] = "Transaction was approved" />
|
||||
<cfset variables.braintree["200"] = "Transaction was declined by Processor" />
|
||||
<cfset variables.braintree["201"] = "Do Not Honor" />
|
||||
<cfset variables.braintree["202"] = "Insufficient Funds" />
|
||||
<cfset variables.braintree["203"] = "Over Limit" />
|
||||
<cfset variables.braintree["204"] = "Transaction not allowed" />
|
||||
<cfset variables.braintree["220"] = "Incorrect Payment Data" />
|
||||
<cfset variables.braintree["221"] = "No such card issuer" />
|
||||
<cfset variables.braintree["222"] = "No card number on file with Issuer" />
|
||||
<cfset variables.braintree["223"] = "Expired card" />
|
||||
<cfset variables.braintree["224"] = "Invalid expiration date" />
|
||||
<cfset variables.braintree["225"] = "Invalid card security code" />
|
||||
<cfset variables.braintree["240"] = "Call Issuer for further information" />
|
||||
<cfset variables.braintree["250"] = "Pick up card" />
|
||||
<cfset variables.braintree["251"] = "Lost card" />
|
||||
<cfset variables.braintree["252"] = "Stolen card" />
|
||||
<cfset variables.braintree["253"] = "Fraudulent card" />
|
||||
<cfset variables.braintree["260"] = "Declined with further instructions available (see response text)" />
|
||||
<cfset variables.braintree["261"] = "Declined - Stop all recurring payments" />
|
||||
<cfset variables.braintree["262"] = "Declined - Stop this recurring program" />
|
||||
<cfset variables.braintree["263"] = "Declined - Updated cardholder data available" />
|
||||
<cfset variables.braintree["264"] = "Declined - Retry in a few days" />
|
||||
<cfset variables.braintree["300"] = "Transaction was rejected by gateway" />
|
||||
<cfset variables.braintree["400"] = "Transaction error returned by processor" />
|
||||
<cfset variables.braintree["410"] = "Invalid merchant configuration" />
|
||||
<cfset variables.braintree["411"] = "Merchant account is inactive" />
|
||||
<cfset variables.braintree["420"] = "Communication error" />
|
||||
<cfset variables.braintree["421"] = "Communication error with issuer" />
|
||||
<cfset variables.braintree["430"] = "Duplicate transaction at processor" />
|
||||
<cfset variables.braintree["440"] = "Processor format error" />
|
||||
<cfset variables.braintree["441"] = "Invalid transaction information" />
|
||||
<cfset variables.braintree["460"] = "Processor feature not available" />
|
||||
<cfset variables.braintree["461"] = "Unsupported card type" />
|
||||
|
||||
|
||||
<!--- make a way of setting the key/key id used in hash calculations --->
|
||||
<cffunction name="getSecurityKey" access="public" output="false" returntype="string">
|
||||
<cfif getTestMode()>
|
||||
<cfreturn "844wfNN5FGuGS7wtKfQsY6k6ZxAv6Ff7" />
|
||||
<cfelse>
|
||||
<cfreturn variables.SecurityKey />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
<cffunction name="setSecurityKey" access="public" output="false" returntype="void">
|
||||
<cfargument name="SecurityKey" type="string" required="true" />
|
||||
<cfset variables.SecurityKey = arguments.SecurityKey />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getSecurityKeyID" access="public" output="false" returntype="numeric">
|
||||
<cfif getTestMode()>
|
||||
<cfreturn 1247307 />
|
||||
<cfelse>
|
||||
<cfreturn variables.SecurityKeyID />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
<cffunction name="setSecurityKeyID" access="public" output="false" returntype="void">
|
||||
<cfargument name="SecurityKeyID" type="numeric" required="true" />
|
||||
<cfset variables.SecurityKeyID = arguments.SecurityKeyID />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- process wrapper with gateway/transaction error handling --->
|
||||
<cffunction name="process" output="false" access="private" returntype="any">
|
||||
<cfargument name="payload" type="struct" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var response = "" />
|
||||
<cfset var results = structNew() />
|
||||
<cfset var pairs = "" />
|
||||
<cfset var ii = "" />
|
||||
<cfset var p = arguments.payload /><!--- shortcut (by reference) --->
|
||||
|
||||
|
||||
<!--- create structure of URL parameters; swap in test parameters if necessary --->
|
||||
<cfif getTestMode()>
|
||||
<cfset p["username"] = "testapi" />
|
||||
<cfset p["password"] = "password1" />
|
||||
<cfelse>
|
||||
<cfset p["username"] = getUsername() />
|
||||
<cfset p["password"] = getPassword() />
|
||||
</cfif>
|
||||
|
||||
<!--- provide optional data --->
|
||||
<cfset structAppend(p, arguments.options, true) />
|
||||
|
||||
<!--- process standard and common CFPAYMENT mappings into Braintree-specific values --->
|
||||
<cfif structKeyExists(arguments.options, "orderId")>
|
||||
<cfset p["order_id"] = arguments.options.orderId />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "tokenId")>
|
||||
<cfset p["customer_vault_id"] = arguments.options.tokenId />
|
||||
</cfif>
|
||||
|
||||
|
||||
<!---
|
||||
state (recommended) Format: CC, 2 Character abbrev.
|
||||
country (recommended) Format: CC (ISO-3166)
|
||||
processor_id (optional)
|
||||
product_sku_# (optional) Format: product_sku_1
|
||||
orderdescription (optional)
|
||||
company (optional)
|
||||
address2 (optional)
|
||||
fax (optional)
|
||||
Billing fax number
|
||||
website (optional)
|
||||
shipping_firstname (optional)
|
||||
shipping_lastname (optional)
|
||||
shipping_company (optional)
|
||||
shipping_address1 (optional)
|
||||
shipping_address2 (optional)
|
||||
shipping_city (optional)
|
||||
shipping_state (optional) 2 character abbreviation.
|
||||
shipping_zip (optional)
|
||||
shipping_country (optional) Format: CC (ISO-3166, ie. US)
|
||||
tracking_number (optional)
|
||||
shipping_carrier (optional) Format: ups / fedex / dhl / usps
|
||||
orderid (optional)
|
||||
sec_code (optional) Format: PPD / WEB / TEL / CCD
|
||||
descriptor (optional)
|
||||
descriptor_phone (optional)
|
||||
--->
|
||||
|
||||
|
||||
<!--- braintree requires lower case parameters (per Katrina in support on 3/25/09), so force case --->
|
||||
<cfloop collection="#p#" item="ii">
|
||||
<cfset p[lcase(ii)] = p[ii] />
|
||||
</cfloop>
|
||||
|
||||
|
||||
<!--- send it over the wire using the base gateway --->
|
||||
<cfset response = createResponse(argumentCollection = super.process(payload = p)) />
|
||||
|
||||
|
||||
<!--- we do some meta-checks for gateway-level errors (as opposed to auth/decline errors) --->
|
||||
<cfif NOT response.hasError()>
|
||||
|
||||
<!--- we need to have a result; otherwise that's an error in itself --->
|
||||
<cfif len(response.getResult())>
|
||||
|
||||
<cfif isXML(response.getResult())>
|
||||
|
||||
<!--- returned from query api, just shoehorn it in and return the result --->
|
||||
<cfset results = xmlParse(response.getResult()) />
|
||||
|
||||
<!--- store parsed result --->
|
||||
<cfset response.setParsedResult(results) />
|
||||
|
||||
<!--- check returned XML for success/failure --->
|
||||
<cfif structKeyExists(results.xmlRoot, "error_response")>
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
<cfelse>
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
</cfif>
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- From: http://developer.getbraintree.com/apis/1-payment-processing
|
||||
The transaction responses are returned in the body of the HTTP response
|
||||
in a query string name/value format delimited by ampersands. For example:
|
||||
variable1=value1&variable2=value2&variable3=value3
|
||||
--->
|
||||
<cfset pairs = listToArray(response.getResult(), "&") />
|
||||
|
||||
<!--- now split the variable=value --->
|
||||
<cfloop from="1" to="#arrayLen(pairs)#" index="ii">
|
||||
<cfif listLen(pairs[ii], "=") GT 1>
|
||||
<cfset results[listFirst(pairs[ii], "=")] = listLast(pairs[ii], "=") />
|
||||
<cfelse>
|
||||
<cfset results[listFirst(pairs[ii], "=")] = "" />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<!--- store parsed result --->
|
||||
<cfset response.setParsedResult(results) />
|
||||
|
||||
<!--- handle common response fields --->
|
||||
<cfif structKeyExists(results, "response_code")>
|
||||
<cfset response.setMessage(variables.braintree[results.response_code]) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(results, "response_text")>
|
||||
<cfset response.setMessage(response.getMessage() & ": " & variables.braintree[results.response_text]) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(results, "transactionid")>
|
||||
<cfset response.setTransactionID(results.transactionid) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(results, "authcode")>
|
||||
<cfset response.setAuthorization(results.authcode) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(results, "customer_vault_id")>
|
||||
<cfset response.setTokenID(results.customer_vault_id) />
|
||||
</cfif>
|
||||
|
||||
<!--- handle common "success" fields --->
|
||||
<cfif structKeyExists(results, "avsresponse") AND len(results.avsresponse)>
|
||||
<cfset response.setAVSCode(results.avsresponse) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(results, "cvvresponse") AND len(results.cvvresponse)>
|
||||
<cfset response.setCVVCode(results.cvvresponse) />
|
||||
</cfif>
|
||||
|
||||
<!--- see if the response was successful --->
|
||||
<cfif results.response EQ "1">
|
||||
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
|
||||
<cfelseif results.response EQ "2">
|
||||
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- only other known state is 3 meaning, "error in transaction data or system error" --->
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- this is bad, because Braintree didn't return a response. Uh oh! --->
|
||||
<cfset response.setStatus(getService().getStatusUnknown()) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- implement primary methods --->
|
||||
<cffunction name="purchase" output="false" access="public" returntype="any" hint="Authorize + Capture in one step">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="false" />
|
||||
<cfargument name="transactionId" type="any" required="false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<!--- set general values --->
|
||||
<cfset post["amount"] = arguments.money.getAmount() />
|
||||
<cfset post["type"] = "sale" />
|
||||
|
||||
<!--- API will allow a new sale using the transactionid from a previous sale/auth/validate transaction --->
|
||||
<cfif structKeyExists(arguments, "transactionId")>
|
||||
|
||||
<cfset post["transactionid"] = arguments.transactionId />
|
||||
|
||||
<cfelseif structKeyExists(arguments, "account")>
|
||||
|
||||
<cfswitch expression="#getService().getAccountType(arguments.account)#">
|
||||
<cfcase value="creditcard">
|
||||
<!--- copy in name and customer details --->
|
||||
<cfset post = addCustomer(post = post, account = arguments.account) />
|
||||
<cfset post = addCreditCard(post = post, account = arguments.account, options = arguments.options) />
|
||||
</cfcase>
|
||||
<cfcase value="eft">
|
||||
<!--- copy in name and customer details --->
|
||||
<cfset post = addCustomer(post = post, account = arguments.account) />
|
||||
<cfset post = addEFT(post = post, account = arguments.account, options = arguments.options) />
|
||||
</cfcase>
|
||||
<cfcase value="token">
|
||||
<!--- tokens don't need customer info --->
|
||||
<cfset post = addToken(post = post, account = arguments.account, options = arguments.options) />
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfthrow type="cfpayment.InvalidAccount" message="The account type #getService().getAccountType(arguments.account)# is not supported by this gateway." />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- either a previous transactionId or account must be provided --->
|
||||
<cfthrow type="cfpayment.Gateway.Error" message="Missing Argument" detail="One of the following arguments are required: account, transactionId" />
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="authorize" output="false" access="public" returntype="any" hint="Authorize (only) a credit card">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="false" />
|
||||
<cfargument name="transactionId" type="any" required="false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<!--- set general values --->
|
||||
<cfset post["amount"] = arguments.money.getAmount() />
|
||||
<cfset post["type"] = "auth" />
|
||||
|
||||
<!--- API will allow a new auth using the transactionid from a previous sale/auth/validate transaction --->
|
||||
<cfif structKeyExists(arguments, "transactionId")>
|
||||
|
||||
<cfset post["transactionid"] = arguments.transactionId />
|
||||
|
||||
<cfelseif structKeyExists(arguments, "account")>
|
||||
|
||||
<cfswitch expression="#getService().getAccountType(arguments.account)#">
|
||||
<cfcase value="creditcard">
|
||||
<!--- copy in name and customer details --->
|
||||
<cfset post = addCustomer(post = post, account = arguments.account) />
|
||||
<cfset post = addCreditCard(post = post, account = arguments.account, options = arguments.options) />
|
||||
</cfcase>
|
||||
<cfcase value="eft">
|
||||
<cfthrow message="Authorize not implemented for E-checks; use purchase instead." type="cfpayment.MethodNotImplemented" />
|
||||
</cfcase>
|
||||
<cfcase value="token">
|
||||
<cfset post = addToken(post = post, account = arguments.account, options = arguments.options) />
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfthrow type="cfpayment.InvalidAccount" message="The account type #getService().getAccountType(arguments.account)# is not supported by this gateway." />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- either a previous transactionId or account must be provided --->
|
||||
<cfthrow type="cfpayment.Gateway.Error" message="Missing Argument" detail="One of the following arguments are required: account, transactionId" />
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="validate" output="false" access="public" returntype="any" hint="Validate (only) a credit card without incurring Visa/MC network abuse fees">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="false" />
|
||||
<cfargument name="transactionId" type="any" required="false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<!--- set general values --->
|
||||
<cfset post["amount"] = "0.00" />
|
||||
<cfset post["type"] = "validate" />
|
||||
|
||||
<!--- API will allow a new validate using the transactionid from a previous sale/auth/validate transaction --->
|
||||
<cfif structKeyExists(arguments, "transactionId")>
|
||||
|
||||
<cfset post["transactionid"] = arguments.transactionId />
|
||||
|
||||
<cfelseif structKeyExists(arguments, "account")>
|
||||
|
||||
<cfswitch expression="#getService().getAccountType(arguments.account)#">
|
||||
<cfcase value="creditcard">
|
||||
<!--- copy in name and customer details --->
|
||||
<cfset post = addCustomer(post = post, account = arguments.account) />
|
||||
<cfset post = addCreditCard(post = post, account = arguments.account, options = arguments.options) />
|
||||
</cfcase>
|
||||
<cfcase value="eft">
|
||||
<cfthrow message="Validate not implemented for E-checks; use purchase instead." type="cfpayment.MethodNotImplemented" />
|
||||
</cfcase>
|
||||
<cfcase value="token">
|
||||
<cfthrow message="Validate not implemented for vault tokens; use authorize instead." type="cfpayment.MethodNotImplemented" />
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfthrow type="cfpayment.InvalidAccount" message="The account type #getService().getAccountType(arguments.account)# is not supported by this gateway." />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- either a previous transactionId or account must be provided --->
|
||||
<cfthrow type="cfpayment.Gateway.Error" message="Missing Argument" detail="One of the following arguments are required: account, transactionId" />
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="capture" output="false" access="public" returntype="any" hint="Add a previous authorization to be settled">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="authorization" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<!--- set general values --->
|
||||
<cfset post["amount"] = arguments.money.getAmount() />
|
||||
<cfset post["type"] = "capture" />
|
||||
<cfset post["transactionid"] = arguments.authorization />
|
||||
|
||||
<!--- capture can also take the following options values:
|
||||
descriptor (optional)
|
||||
descriptor_phone (optional)
|
||||
type (required)
|
||||
amount (required) Format: x.xx
|
||||
transactionid (required)
|
||||
tracking_number (optional)
|
||||
shipping_carrier (optional) Format: ups / fedex / dhl / usps
|
||||
orderid (optional)
|
||||
--->
|
||||
|
||||
<cfreturn process(payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- refund all or part of a previous settled transaction --->
|
||||
<cffunction name="refund" output="false" access="public" returntype="any" hint="Refund all or part of a previous transaction">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="transactionid" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<!--- set general values; note that refunding EFTs requires "payment=check" to be passed --->
|
||||
<cfset post["amount"] = arguments.money.getAmount() />
|
||||
<cfset post["type"] = "refund" />
|
||||
<cfset post["transactionid"] = arguments.transactionid />
|
||||
|
||||
<cfreturn process(payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="credit" output="false" access="public" returntype="any" hint="Credit an account">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="transactionid" type="any" required="false" />
|
||||
<cfargument name="account" type="any" required="false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<!--- set general values --->
|
||||
<cfset post["amount"] = arguments.money.getAmount() />
|
||||
|
||||
<cfif structKeyExists(arguments, "account") AND getService().getAccountType(arguments.account) EQ "eft">
|
||||
<!--- in the direct deposit scenario, we need the account --->
|
||||
<cfset post["type"] = "credit" />
|
||||
<cfset post = addEFT(post = post, account = arguments.account, options = arguments.options) />
|
||||
<cfelseif structKeyExists(arguments, "account") AND getService().getAccountType(arguments.account) EQ "token">
|
||||
<!--- direct deposit using the vault --->
|
||||
<cfset post["type"] = "credit" />
|
||||
<cfset post = addToken(post = post, account = arguments.account) />
|
||||
<cfelseif structKeyExists(arguments.options, "tokenId")>
|
||||
<!--- direct deposit using the vault --->
|
||||
<cfset post["type"] = "credit" />
|
||||
<cfset post["customer_vault_id"] = arguments.options.tokenId /><!--- redundant due to normalized processing in process() --->
|
||||
<cfelseif structKeyExists(arguments, "transactionid")>
|
||||
<cfset post["type"] = "refund" />
|
||||
<cfset post["transactionid"] = arguments.transactionid />
|
||||
<cfelse>
|
||||
<cfthrow type="cfpayment.InvalidAccount" message="An account type of EFT, token or a tokenId or transactionId must be provided" />
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="void" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="transactionid" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<!--- set general values --->
|
||||
<cfset post["type"] = "void" />
|
||||
<cfset post["transactionid"] = arguments.transactionid />
|
||||
|
||||
<cfreturn process(payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- function to get a copy of the actual transaction response
|
||||
|
||||
Only requests that have valid structure and therefore reach the processing modules are available for this.
|
||||
--->
|
||||
<cffunction name="status" output="false" access="public">
|
||||
<cfargument name="transactionid" type="any" required="false" hint="If checking status of a transaction with unknown response, this may not be known and can be blank" />
|
||||
<cfargument name="options" type="any" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
<cfset post["type"] = "query" />
|
||||
|
||||
<cfif structKeyExists(arguments, "transactionid")>
|
||||
<cfset post["transaction_id"] = arguments.transactionid />
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(arguments, "orderid")>
|
||||
<cfset post["order_id"] = arguments.orderid />
|
||||
</cfif>
|
||||
|
||||
<!---
|
||||
email (recommended)
|
||||
orderid (optional)
|
||||
last_name (optional)
|
||||
cc_number (optional, use either the full number or the last 4 digits of the number)
|
||||
start_date (optional)
|
||||
end_date (optional)
|
||||
condition (optional, [pending|pendingsettlement|failed|canceled|complete|unknown], you can send multiple values separated by commas)
|
||||
transaction_type (optional, [cc|ck])
|
||||
action_type (optional, [sale|refund|credit|auth|capture|void], can send multiple separated by commas)
|
||||
transaction_id (optional, Original Payment Gateway Transaction ID. This value was passed in the response of a previous Gateway Transaction. Please note that in the Payment Gateway, this value is called transaction (no underscore))
|
||||
report_type=customer_vault (optional) for running a query against the SecureVault
|
||||
--->
|
||||
|
||||
<cfreturn process(payload = post, options = arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="store" output="false" access="public" returntype="any" hint="Put payment information into the vault">
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
<cfset var res = "" />
|
||||
|
||||
<cfswitch expression="#getService().getAccountType(arguments.account)#">
|
||||
<cfcase value="creditcard">
|
||||
<cfset post = addCreditCard(post = post, account = arguments.account, options = arguments.options) />
|
||||
</cfcase>
|
||||
<cfcase value="eft">
|
||||
<cfset post = addEFT(post = post, account = arguments.account, options = arguments.options) />
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfthrow type="cfpayment.InvalidAccount" message="Account type of token is not supported by this method." />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
<cfset post["customer_vault"] = "add_customer" />
|
||||
<cfset post = addCustomer(post = post, account = arguments.account) />
|
||||
|
||||
<!--- check if we have an optional vault id --->
|
||||
<cfif structKeyExists(arguments.options, "tokenId")>
|
||||
<cfset post["customer_vault_id"] = arguments.options.tokenId />
|
||||
<cfset post["customer_vault"] = "update_customer" /><!--- tell it to update --->
|
||||
</cfif>
|
||||
|
||||
<!--- process transaction --->
|
||||
<cfreturn process(payload = post, options = arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="unstore" output="false" access="public" returntype="any" hint="Delete information from the vault">
|
||||
<cfargument name="account" type="any" required="true" /><!--- must be type of "token"? --->
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
<cfset var res = "" />
|
||||
|
||||
<cfif getService().getAccountType(arguments.account) NEQ "token">
|
||||
<cfthrow type="cfpayment.InvalidAccount" message="Only an account type of token is supported by this method." />
|
||||
</cfif>
|
||||
|
||||
<cfset post["customer_vault"] = "delete_customer" />
|
||||
<cfset post = addToken(post = post, account = arguments.account) />
|
||||
|
||||
<!--- process transaction --->
|
||||
<cfreturn process(payload = post, options = arguments.options) />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- override getGatewayURL to inject the extra URL method per gateway method --->
|
||||
<cffunction name="getGatewayURL" access="public" output="false" returntype="any" hint="">
|
||||
<!--- argumentcollection will include method and payload --->
|
||||
<cfargument name="payload" type="struct" required="true" />
|
||||
|
||||
<cfif structKeyExists(arguments.payload, "type") AND arguments.payload.type EQ "query">
|
||||
<cfreturn variables.cfpayment.GATEWAY_REPORT_URL />
|
||||
<cfelse>
|
||||
<cfreturn variables.cfpayment.GATEWAY_LIVE_URL />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- ------------------------------------------------------------------------------
|
||||
|
||||
PRIVATE HELPER METHODS
|
||||
|
||||
------------------------------------------------------------------------- --->
|
||||
<cffunction name="addCustomer" output="false" access="private" returntype="any" hint="Add customer contact details to the request object">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
|
||||
<cfset arguments.post["firstname"] = arguments.account.getFirstName() />
|
||||
<cfset arguments.post["lastname"] = arguments.account.getLastName() />
|
||||
<cfset arguments.post["address1"] = arguments.account.getAddress() />
|
||||
<cfset arguments.post["city"] = arguments.account.getCity() />
|
||||
<cfset arguments.post["state"] = arguments.account.getRegion() />
|
||||
<cfset arguments.post["zip"] = arguments.account.getPostalCode() />
|
||||
<cfset arguments.post["country"] = arguments.account.getCountry() />
|
||||
|
||||
<cfreturn arguments.post />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="addCreditCard" output="false" access="private" returntype="any" hint="Add payment source fields to the request object">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset post["payment"] = "creditcard" />
|
||||
<cfset post["ccnumber"] = arguments.account.getAccount() />
|
||||
<cfset post["ccexp"] = arguments.account.getMonth() & right(arguments.account.getYear(), 2) />
|
||||
<cfset post["cvv"] = arguments.account.getVerificationValue() />
|
||||
|
||||
<!--- if we want to save the instrument to the vault; check if we have an optional vault id --->
|
||||
<cfif structKeyExists(arguments.options, "tokenize")>
|
||||
<cfset post["customer_vault"] = "add_customer" />
|
||||
<cfif structKeyExists(arguments.options, "tokenId")>
|
||||
<cfset post["customer_vault_id"] = arguments.options.tokenId />
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<cfreturn arguments.post />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="addEFT" output="false" access="private" returntype="any" hint="Add payment source fields to the request object">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset arguments.post["payment"] = "check" />
|
||||
<cfset arguments.post["checkname"] = arguments.account.getName() />
|
||||
<cfset arguments.post["checkaba"] = arguments.account.getRoutingNumber() />
|
||||
<cfset arguments.post["checkaccount"] = arguments.account.getAccount() />
|
||||
<cfset arguments.post["account_type"] = arguments.account.getAccountType() />
|
||||
<cfset arguments.post["phone"] = arguments.account.getPhoneNumber() />
|
||||
<cfset arguments.post["sec_code"] = arguments.account.getSEC() />
|
||||
|
||||
<!--- convert SEC code to braintree values --->
|
||||
<cfif arguments.account.getSEC() EQ "PPD">
|
||||
<cfset arguments.post["account_holder_type"] = "personal" />
|
||||
<cfelseif arguments.account.getSEC() EQ "CCD">
|
||||
<cfset arguments.post["account_holder_type"] = "business" />
|
||||
</cfif>
|
||||
|
||||
<!--- if we want to save the instrument to the vault; check if we have an optional vault id --->
|
||||
<cfif structKeyExists(arguments.options, "tokenize")>
|
||||
<cfset post["customer_vault"] = "add_customer" />
|
||||
<cfif structKeyExists(arguments.options, "tokenId")>
|
||||
<cfset post["customer_vault_id"] = arguments.options.tokenId />
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<cfreturn arguments.post />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="addToken" output="false" access="private" returntype="any" hint="Add payment source fields to the request object">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
|
||||
<!--- required when using as a payment source --->
|
||||
<cfset arguments.post["customer_vault_id"] = arguments.account.getID() />
|
||||
|
||||
<cfreturn arguments.post />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getResponseFromStatus" output="false" access="public" returntype="any" hint="Converts previous transaction statuses into regular response as returned from purchase()">
|
||||
|
||||
<cfset var status = status(argumentCollection = arguments) />
|
||||
<cfset var arrResponse = arrayNew(1) />
|
||||
<cfset var response = createResponse() />
|
||||
<cfset var xml = status.getParsedResult() />
|
||||
<cfset var results = "" />
|
||||
<cfset var ii = "" />
|
||||
<cfset var len = "" />
|
||||
|
||||
<!--- we do some meta-checks for gateway-level errors (as opposed to auth/decline errors) --->
|
||||
<cfif status.hasError()>
|
||||
|
||||
<!--- we don't return the errorneous status response because it might be interpreted as the original
|
||||
transaction we're trying to report on (which may have been successful for all we know at this stage); instead throw an error --->
|
||||
<cfthrow type="cfpayment.Gateway.Error" message="Status Check Failed" detail="Failed to obtain the original transaction details" />
|
||||
|
||||
<!--- now populate response with results of status query --->
|
||||
<cfelseif isXML(xml) AND arrayLen(xml.xmlRoot.xmlChildren) GT 0>
|
||||
|
||||
<!--- 99% of time, this will be just a single transaction record but we support n --->
|
||||
<cfset len = arrayLen(xml.xmlRoot.xmlChildren) />
|
||||
|
||||
<cfloop from="1" to="#len#" index="ii">
|
||||
|
||||
<!--- this gives us a base of the "transaction" node so everything is right below it --->
|
||||
<cfset results = xml.xmlRoot.xmlChildren[ii] />
|
||||
<cfset response = createResponse() />
|
||||
|
||||
<!--- store (complete) parsed result for this transaction --->
|
||||
<cfset response.setResult(toString(results)) />
|
||||
<cfset response.setParsedResult(results) />
|
||||
|
||||
<!--- check returned XML for success/failure --->
|
||||
<cfif structKeyExists(results, "error_response")>
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
<cfelse>
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
</cfif>
|
||||
|
||||
|
||||
<!--- handle common response fields --->
|
||||
<cfif structKeyExists(results, "action")>
|
||||
|
||||
<cfif structKeyExists(results.action, "response_text")>
|
||||
<cfset response.setMessage(results.action.response_text.xmlText) />
|
||||
</cfif>
|
||||
|
||||
<!--- see if the response was successful --->
|
||||
<cfif structKeyExists(results.action, "success")>
|
||||
|
||||
<cfif results.action.success.xmlText EQ "1">
|
||||
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
|
||||
<cfelseif results.action.success.xmlText EQ "0">
|
||||
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- only other known state is 3 meaning, "error in transaction data or system error" --->
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(results, "transaction_id")>
|
||||
<cfset response.setTransactionID(results.transaction_id.xmlText) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(results, "authorization_code")>
|
||||
<cfset response.setAuthorization(results.authorization_code.xmlText) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(results, "customer_vault_id")>
|
||||
<cfset response.setTokenID(results.customer_vault_id.xmlText) />
|
||||
<cfelseif structKeyExists(results, "customerid")>
|
||||
<cfset response.setTokenID(results.customerid.xmlText) />
|
||||
</cfif>
|
||||
|
||||
<!--- handle common "success" fields --->
|
||||
<cfif structKeyExists(results, "avs_response") AND len(results.avs_response.xmlText)>
|
||||
<cfset response.setAVSCode(results.avs_response.xmlText) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(results, "csc_response") AND len(results.csc_response.xmlText)>
|
||||
<cfset response.setCVVCode(results.csc_response.xmlText) />
|
||||
</cfif>
|
||||
|
||||
<!--- append to array --->
|
||||
<cfset arrayAppend(arrResponse, response) />
|
||||
|
||||
</cfloop>
|
||||
|
||||
<cfelseif arrayLen(xml.xmlRoot.xmlChildren) EQ 0>
|
||||
|
||||
<!--- payment not found, return the blank response object set as unprocessed --->
|
||||
<cfset arrayAppend(arrResponse, response) />
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- something bad happened here --->
|
||||
<cfset response.setStatus(getService().getStatusUnknown()) />
|
||||
<cfset arrayAppend(arrResponse, response) />
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn arrResponse />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- braintree createResponse() overrides the AVS/CVV responses --->
|
||||
<cffunction name="createResponse" access="private" output="false" returntype="any" hint="Create a Braintree response object with status set to unprocessed">
|
||||
<cfreturn createObject("component", "cfpayment.api.gateway.braintree.response").init(argumentCollection = arguments, service = getService()) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<!--- HELPER FUNCTIONS TO MAKE LIFE EASIER IN COLDFUSION LAND --->
|
||||
<cffunction name="generateHash" output="false" access="public" returntype="string">
|
||||
<cfargument name="orderId" type="uuid" required="true" />
|
||||
<cfargument name="amount" type="any" required="true" />
|
||||
<cfargument name="date" type="date" required="true" hint="A date/time object that is also passed in the form to Braintree; it must be the same value!" />
|
||||
<cfargument name="tokenId" type="numeric" required="false" />
|
||||
|
||||
<cfset var time = dateToBraintree(arguments.date) />
|
||||
<cfset var key = getSecurityKey() />
|
||||
<cfset var src = "" />
|
||||
<cfset var amt = "" />
|
||||
|
||||
<!--- the amount may be blank in certain hashes like for validate or vault storage --->
|
||||
<cfif len(arguments.amount) AND isNumeric(arguments.amount)>
|
||||
<cfset amt = trim(numberFormat(arguments.amount, '-.__')) />
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(arguments, "tokenId")>
|
||||
<!--- with vault: orderid|amount|customer_vault_id|time|Key --->
|
||||
<cfset src = arguments.orderId & "|" & amt & "|" & arguments.tokenId & "|" & time & "|" & key />
|
||||
<cfelse>
|
||||
<!--- no vault: orderid|amount|time|Key --->
|
||||
<cfset src = arguments.orderId & "|" & amt & "|" & time & "|" & key />
|
||||
</cfif>
|
||||
|
||||
<!--- md5 and return --->
|
||||
<cfreturn lcase(hash(src)) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="verifyHash" output="false" access="public" returntype="boolean" hint="Arguments are all as passed back from Braintree; function verifies they are not tampered with by calculating the hash">
|
||||
<cfargument name="orderid" type="string" required="true" />
|
||||
<cfargument name="amount" type="string" required="true" /><!--- can be blank in case of validate --->
|
||||
<cfargument name="response" type="string" required="true" />
|
||||
<cfargument name="transactionid" type="string" required="true" />
|
||||
<cfargument name="avsresponse" type="string" required="false" default="" />
|
||||
<cfargument name="cvvresponse" type="string" required="false" default="" />
|
||||
<cfargument name="customer_vault_id" type="string" required="false" default="" />
|
||||
<cfargument name="time" type="string" required="true" />
|
||||
<cfargument name="hash" type="string" required="true" />
|
||||
|
||||
<!---
|
||||
// with vault: orderid|amount|response|transactionid|avsresponse|cvvresponse|customer_vault_id|time|key
|
||||
// no vault: orderid|amount|response|transactionid|avsresponse|cvvresponse|time|key
|
||||
res = hash(orderid & "|" & amount & "|" & response & "|" & transactionid & "|" & avsresponse & "|" & cvvresponse & "|" & time & "|" & vchBraintreeKey);
|
||||
--->
|
||||
|
||||
<cfset var key = getSecurityKey() />
|
||||
<cfset var res = "" />
|
||||
|
||||
<cfif len(arguments.customer_vault_id) AND isNumeric(arguments.customer_vault_id)>
|
||||
<cfset res = arguments.orderId & "|" &
|
||||
arguments.amount & "|" &
|
||||
arguments.response & "|" &
|
||||
arguments.transactionid & "|" &
|
||||
arguments.avsresponse & "|" &
|
||||
arguments.cvvresponse & "|" &
|
||||
arguments.customer_vault_id & "|" &
|
||||
arguments.time & "|" &
|
||||
key />
|
||||
<cfelse>
|
||||
<cfset res = arguments.orderId & "|" &
|
||||
arguments.amount & "|" &
|
||||
arguments.response & "|" &
|
||||
arguments.transactionid & "|" &
|
||||
arguments.avsresponse & "|" &
|
||||
arguments.cvvresponse & "|" &
|
||||
arguments.time & "|" &
|
||||
key />
|
||||
</cfif>
|
||||
<cfreturn lcase(hash(res)) EQ lcase(arguments.hash) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="dateToBraintree" output="false" access="public" returntype="date" hint="Take a date/time object and convert it to Braintree format in GMT">
|
||||
<cfargument name="date" type="date" required="true" />
|
||||
<cfargument name="localTZ" type="boolean" required="false" default="true" hint="Convert from local server time?" />
|
||||
|
||||
<cfif arguments.localTZ>
|
||||
<cfset arguments.date = dateConvert("local2utc", arguments.date) />
|
||||
</cfif>
|
||||
|
||||
<cfreturn dateFormat(arguments.date, "yyyymmdd") & timeFormat(arguments.date, "HHmmss") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="braintreeToDate" output="false" access="public" returntype="date" hint="Take a GMT Braintree timestamp and convert it to a ColdFusion date object">
|
||||
<cfargument name="date" type="string" required="true" hint="string looks like 20090602120000 or yyyymmddhhmmss" />
|
||||
<cfargument name="localTZ" type="boolean" required="false" default="true" hint="Convert to local server time?" />
|
||||
|
||||
<!--- string format is yyyymmddhhmmss --->
|
||||
<cfset var dteGMT = createDateTime(left(arguments.date, 4), mid(arguments.date, 5, 2), mid(arguments.date, 7, 2), mid(arguments.date, 9, 2), mid(arguments.date, 11, 2), mid(arguments.date, 13, 2)) />
|
||||
|
||||
<cfif arguments.localTZ>
|
||||
<cfset dteGMT = dateConvert("utc2local", dteGMT) />
|
||||
</cfif>
|
||||
|
||||
<cfreturn dteGMT />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="hasTransaction" output="false" access="public" returntype="boolean" hint="Pass in the results of a status() call and see if a transaction was returned">
|
||||
<cfargument name="status" type="any" required="true" />
|
||||
|
||||
<cfif NOT isXML(arguments.status)>
|
||||
<cfset arguments.status = xmlParse(arguments.status) />
|
||||
</cfif>
|
||||
|
||||
<!--- XML looks like <nm_response><transaction>...</transaction><transaction>...</transaction></nm_response> --->
|
||||
<cfreturn arrayLen(arguments.status.xmlRoot.xmlChildren) GT 0 />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getIsCCEnabled" access="public" output="false" returntype="boolean" hint="determine whether or not this gateway can accept credit card transactions">
|
||||
<cfreturn true />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getIsEFTEnabled" access="public" output="false" returntype="boolean" hint="determine whether or not this gateway can accept ACH/EFT transactions">
|
||||
<cfreturn true />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
88
cfpayment/api/gateway/braintree/response.cfc
Normal file
88
cfpayment/api/gateway/braintree/response.cfc
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2007 Brian Ghidinelli (http://www.ghidinelli.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 name="response" displayname="Braintree Gateway Response" output="false" hint="Normalized result for gateway response" extends="cfpayment.api.model.response">
|
||||
|
||||
<!--- CONSTANTS in psuedo-constructor --->
|
||||
<cfscript>
|
||||
// list the possible AVS responses
|
||||
variables.cfpayment.ResponseAVS = structNew();
|
||||
structInsert(variables.cfpayment.ResponseAVS, "0", "AVS Not Available", true); // seen in wild
|
||||
structInsert(variables.cfpayment.ResponseAVS, "A", "Billing street address matches, but 5-digit or 9-digit postal code do not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "B", "Billing street address matches, but postal code not verified.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "C", "Billing street address and postal code do not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "D", "Billing street address and postal code match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "E", "Not a mail/phone order.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "F", "Address and Postal Code match (UK only).", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "G", "Non-U.S. issuing bank does not support AVS.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "I", "Non-U.S. issuing bank does not support AVS.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "L", "Card member's name and 5-digit billing postal code match, but billing address does not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "M", "Card member's name and 5-digit billing postal code match, but billing address does not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "N", "Street address and postal code do not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "O", "Address Verification System (AVS) not available.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "P", "Card member's name and 5-digit billing postal code match, but billing address does not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "R", "Issuing bank Address Verificaiton System (AVS) unavailable.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "S", "U.S.-issuing bank does not support AVS.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "U", "Address information unavailable.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "W", "Card member's name and 9-digit billing postal code match, but billing address does not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "X", "Cardholder's 9-digit billing postal code and billing address match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "Y", "Cardholder's 5-digit billing postal code and billing address match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "Z", "Card member's name and 5-digit billing postal code match, but billing address does not match.", true);
|
||||
|
||||
// list the CVC or CVV2 response options per Braintree docs
|
||||
variables.cfpayment.ResponseCVV = structNew();
|
||||
structInsert(variables.cfpayment.ResponseCVV, "M", "Match", true); // seen in wild
|
||||
structInsert(variables.cfpayment.ResponseCVV, "N", "No Match", true); // seen in wild
|
||||
structInsert(variables.cfpayment.ResponseCVV, "P", "Not Processed", true); // seen in wild
|
||||
structInsert(variables.cfpayment.ResponseCVV, "S", "Merchant has indicated that CVV2/CVC2 is not present on card", true);
|
||||
structInsert(variables.cfpayment.ResponseCVV, "U", "Credit card issuing bank unable to process request, is not certified and/or has not provided Visa encryption keys", true);// seen in wild
|
||||
structInsert(variables.cfpayment.ResponseCVV, "X", "Card does not support verification", true); // seen in wild, it actually says "No such issuer" but it's a decline
|
||||
|
||||
</cfscript>
|
||||
|
||||
|
||||
<cffunction name="getAVSPostalMatch" output="false" access="private" returntype="string" hint="Normalize the AVS postal match code">
|
||||
<cfset var res = uCase(getAVSCode()) />
|
||||
|
||||
<!--- Y = yes, N = no, X = not relevant, U = unknown --->
|
||||
<cfif listFind("D,F,L,M,P,W,X,Y,Z", res)><!--- it does match --->
|
||||
<cfreturn 'Y' />
|
||||
<cfelseif listFind("A,B,C,N", res)><!--- it does not match --->
|
||||
<cfreturn 'N' />
|
||||
<cfelseif listFind("0,E,G,I,O,R,S,U", res)><!--- bank does not support/verify AVS --->
|
||||
<cfreturn 'X' />
|
||||
</cfif>
|
||||
|
||||
<cfreturn 'U' />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getAVSStreetMatch" output="false" access="private" returntype="string" hint="Normalize the AVS street match code">
|
||||
<cfset var res = uCase(getAVSCode()) />
|
||||
|
||||
<cfif listFind("A,B,D,F,X,Y", res)><!--- it does match --->
|
||||
<cfreturn 'Y' />
|
||||
<cfelseif listFind("C,L,M,N,P,W,Z", res)><!--- it does not match --->
|
||||
<cfreturn 'N' />
|
||||
<cfelseif listFind("0,E,G,I,O,R,S,U", res)><!--- bank does not support/verify AVS --->
|
||||
<cfreturn 'X' />
|
||||
</cfif>
|
||||
|
||||
<cfreturn 'U' /><!--- unknown - AVS invalid or could not be verified --->
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
1025
cfpayment/api/gateway/braintree/tests/BraintreeTest.cfc
Normal file
1025
cfpayment/api/gateway/braintree/tests/BraintreeTest.cfc
Normal file
File diff suppressed because it is too large
Load diff
333
cfpayment/api/gateway/dwolla/dwolla-rest.cfc
Normal file
333
cfpayment/api/gateway/dwolla/dwolla-rest.cfc
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Dwolla OAuth + REST Payments API
|
||||
Copyright 2013 Brian Ghidinelli (http://www.ghidinelli.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="Dwolla OAuth + REST Gateway" extends="cfpayment.api.gateway.base" hint="Dwolla OAuth+REST Gateway" output="false">
|
||||
|
||||
<cfset variables.cfpayment.GATEWAY_NAME = "Dwolla" />
|
||||
<cfset variables.cfpayment.GATEWAY_VERSION = "1.0" />
|
||||
<!--- stripe test mode uses different credentials instead of different urls --->
|
||||
<cfset variables.cfpayment.GATEWAY_URL = "https://www.dwolla.com/oauth/rest" />
|
||||
|
||||
<cfset variables.cfpayment.ConsumerKey = "" />
|
||||
<cfset variables.cfpayment.ConsumerSecret = "" />
|
||||
|
||||
<cffunction name="getConsumerKey" access="public" output="false" returntype="string">
|
||||
<cfreturn variables.cfpayment.ConsumerKey />
|
||||
</cffunction>
|
||||
<cffunction name="setConsumerKey" access="public" output="false" returntype="void">
|
||||
<cfargument name="ConsumerKey" type="string" required="true" />
|
||||
<cfset variables.cfpayment.ConsumerKey = arguments.ConsumerKey />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getConsumerSecret" output="false" access="public" returntype="any">
|
||||
<cfreturn variables.cfpayment.ConsumerSecret />
|
||||
</cffunction>
|
||||
<cffunction name="setConsumerSecret" access="public" output="false" returntype="void">
|
||||
<cfargument name="ConsumerSecret" type="string" required="true" />
|
||||
<cfset variables.cfpayment.ConsumerSecret = arguments.ConsumerSecret />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="purchase" output="false" access="public" returntype="any" hint="Request money from an account">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfthrow message="Not Implemented" />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="credit" output="false" access="public" returntype="any" hint="Send money to an account">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="false" />
|
||||
<cfargument name="destinationId" type="string" required="true" hint="Identification of the user to send funds to. Must be the Dwolla identifier, Facebook identifier, Twitter identifier, phone number, or email address." />
|
||||
<!--- optional --->
|
||||
<cfargument name="destinationType" type="string" required="false" default="Dwolla" hint="Possible values: 'Dwolla', 'Facebook', 'Twitter', 'Email', 'Phone'" />
|
||||
<cfargument name="facilitatorAmount" type="numeric" required="false" default="0" />
|
||||
<cfargument name="assumeCosts" type="boolean" required="false" />
|
||||
<cfargument name="notes" type="string" required="false" />
|
||||
<cfargument name="fundsSource" type="string" required="false" hint="Defaults to Balance" />
|
||||
<cfargument name="additionalFees" type="array" required="false" hint="Array of additional facilitator fees each like: { destinationId = '', amount = ''}" default="#arrayNew(1)#" />
|
||||
<cfargument name="assumeAdditionalFees" type="boolean" required="false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var response = "" />
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<!--- case case-sensitive struct to serialize --->
|
||||
<cfset post["amount"] = arguments.money.getAmount() />
|
||||
<cfset post["pin"] = arguments.account.getSecret() />
|
||||
<cfset post["destinationId"] = arguments.destinationId />
|
||||
<cfif structKeyExists(arguments, "destinationType")><cfset post["destinationType"] = arguments.destinationType /></cfif>
|
||||
<cfif structKeyExists(arguments, "facilitatorAmount")><cfset post["facilitatorAmount"] = arguments.facilitatorAmount /></cfif>
|
||||
<cfif structKeyExists(arguments, "assumeCosts")><cfset post["assumeCosts"] = arguments.assumeCosts /></cfif>
|
||||
<cfif structKeyExists(arguments, "notes")><cfset post["notes"] = arguments.notes /></cfif>
|
||||
<cfif structKeyExists(arguments, "fundsSource")><cfset post["fundsSource"] = arguments.fundsSource /></cfif>
|
||||
<cfif structKeyExists(arguments, "additionalFees")><cfset post["additionalFees"] = arguments.additionalFees /></cfif>
|
||||
<cfif structKeyExists(arguments, "assumeAdditionalFees")><cfset post["assumeAdditionalFees"] = arguments.assumeAdditionalFees /></cfif>
|
||||
|
||||
<cfset response = process(gatewayUrl = getGatewayUrl("/transactions/send", arguments.account.getAccessToken()), payload = serializeJson(post), headers = {"Content-Type" = "application/json"}, options = options) />
|
||||
|
||||
<cfif response.getSuccess()>
|
||||
<!--- parse fields --->
|
||||
<cfset response.setTransactionId(response.getParsedResult().Response) />
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="withdraw" output="false" access="public" returntype="any">
|
||||
<cfthrow message="Not Implemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="deposit" output="false" access="public" returntype="any">
|
||||
<cfthrow message="Not Implemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="fundingsources" output="false" access="public" returntype="any">
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/fundingsources/", arguments.account.getAccessToken()), payload = {}, method = "get") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="fundingsource" output="false" access="public" returntype="any">
|
||||
<cfargument name="sourceId" type="string" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/fundingsources/#arguments.sourceId#", arguments.account.getAccessToken()), payload = {}, method = "get") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="contacts" output="false" access="public" returntype="any">
|
||||
<cfthrow message="Not Implemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="balance" output="false" access="public" returntype="any">
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/balance/", arguments.account.getAccessToken()), payload = {}, method = "get") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="request" output="false" access="public" returntype="any">
|
||||
<cfthrow message="Not Implemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="register" output="false" access="public" returntype="any">
|
||||
<cfthrow message="Not Implemented" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="basicinfo" output="false" access="public" returntype="any">
|
||||
<cfargument name="tokenId" type="string" required="true" hint="Dwolla account ID or Email address" />
|
||||
|
||||
<cfset var payload = {"client_id" = getConsumerKey(), "client_secret" = getConsumerSecret()} />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/users/#arguments.tokenId#"), payload = payload, method="get") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="fullinfo" output="false" access="public" returntype="any">
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/users/", arguments.account.getAccessToken()), payload = {}, method = "get") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<cffunction name="refund" access="public" output="false" returntype="any" hint="Returns an amount back to the previously charged account. Default is to refund the full amount.">
|
||||
<cfargument name="money" type="any" required="false" />
|
||||
<cfargument name="transactionId" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<!--- default is to refund full amount --->
|
||||
<cfif structKeyExists(arguments, "money")>
|
||||
<cfset post["amount"] = abs(arguments.money.getCents()) />
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/charges/#trim(arguments.transactionId)#/refund"), payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="search" access="public" output="false" returntype="any" hint="Find transactions using gateway-supported criteria">
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="groupId" type="string" required="false" />
|
||||
<cfargument name="types" type="string" required="false" hint="Possible values: 'money_sent', 'money_received', 'deposit', 'withdrawal', 'fee'. Defaults to: 'money_sent,money_received,deposit,withdrawal,fee'" />
|
||||
<cfargument name="sinceDate" type="date" required="false" />
|
||||
<cfargument name="endDate" type="date" required="false" />
|
||||
<cfargument name="limit" type="numeric" required="false" />
|
||||
<cfargument name="skip" type="numeric" required="false" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/transactions", arguments.account.getAccessToken()), method = "get", options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="status" access="public" output="false" returntype="any" hint="Reconstruct a response object for a previously executed transaction">
|
||||
<cfargument name="transactionId" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
|
||||
<!--- needs clientkey/clientsecret OR oauth --->
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/transactions/#arguments.transactionId#", arguments.account.getAccessToken()), payload = {}, method = "get") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="validate" output="false" access="public" returntype="any" hint="Convert credit card details to a one-time token for charging later. To store payment details for use later, use a customer object with store().">
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="money" type="any" required="false" />
|
||||
|
||||
<cfset var post = addCreditCard(post = structNew(), account = arguments.account) />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/tokens"), payload = post) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="store" output="false" access="public" returntype="any" hint="Convert a one-time token (from validate() or Stripe.js) into a Customer object for charging one or more times in the future">
|
||||
<cfargument name="account" type="any" required="true" /><!--- must be type of "token"? --->
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = {} />
|
||||
|
||||
<cfif getService().getAccountType(account) EQ "creditcard">
|
||||
<cfset post = addCreditCard(post = post, account = account) />
|
||||
<cfelse>
|
||||
<cfset post["card"] = arguments.account.getID() />
|
||||
</cfif>
|
||||
|
||||
<!--- optional things to add --->
|
||||
<cfif structKeyExists(arguments.options, "coupon")>
|
||||
<cfset post["coupon"] = arguments.options.coupon />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "account_balance")>
|
||||
<cfset post["account_balance"] = arguments.options.account_balance />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "plan")>
|
||||
<cfset post["plan"] = arguments.options.plan />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "trial_end")>
|
||||
<cfset post["trial_end"] = dateToUTC(arguments.options.trial_end) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "quantity")>
|
||||
<cfset post["quantity"] = arguments.options.quantity />
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/customers"), payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="unstore" output="false" access="public" returntype="any">
|
||||
<cfargument name="tokenId" type="string" required="true" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/customers/#arguments.tokenId#"), method = "delete") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="listCharges" output="false" access="public" returntype="any">
|
||||
<cfargument name="count" type="numeric" required="false" />
|
||||
<cfargument name="offset" type="numeric" required="false" />
|
||||
<cfargument name="tokenId" type="string" required="false" />
|
||||
|
||||
<cfset var payload = {} />
|
||||
|
||||
<cfloop collection="#arguments#" item="key">
|
||||
<cfif structKeyExists(arguments, key)>
|
||||
<cfset payload[lcase(key)] = arguments[key] />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayUrl("/charges"), method = "get", payload = payload) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<!--- process wrapper with gateway/transaction error handling --->
|
||||
<cffunction name="process" output="false" access="private" returntype="any">
|
||||
<cfargument name="gatewayUrl" type="string" required="true" />
|
||||
<cfargument name="payload" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
<cfargument name="headers" type="struct" required="false" default="#structNew()#" />
|
||||
<cfargument name="method" type="string" required="false" default="post" />
|
||||
|
||||
<cfset var results = "" />
|
||||
<cfset var response = "" />
|
||||
<cfset var p = arguments.payload /><!--- shortcut (by reference) --->
|
||||
|
||||
<!--- add authentication --->
|
||||
<cfset headers["authorization"] = "Bearer #getConsumerKey()#" />
|
||||
|
||||
<!--- process standard and common CFPAYMENT mappings into Braintree-specific values --->
|
||||
<cfif structKeyExists(arguments.options, "description")>
|
||||
<cfset p["description"] = arguments.options.description />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "tokenId")>
|
||||
<cfset p["customer"] = arguments.options.tokenId />
|
||||
</cfif>
|
||||
|
||||
|
||||
<cfset response = createResponse(argumentCollection = super.process(url = arguments.gatewayUrl, payload = payload, headers = headers, method = arguments.method)) />
|
||||
|
||||
|
||||
<!--- dwolla responds 200 OK to everything but doesn't guarantee request succeeded --->
|
||||
<cfif response.getStatusCode() NEQ 200>
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
</cfif>
|
||||
|
||||
<!--- Dwolla returns errors with JSON object with a "success" true/false key --->
|
||||
<cfif isJSON(response.getResult())>
|
||||
|
||||
<cfset results = deserializeJSON(response.getResult()) />
|
||||
<cfset response.setParsedResult(results) />
|
||||
|
||||
<!--- check for success/failure --->
|
||||
<cfif structKeyExists(results, "success") AND results.success EQ true>
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
<cfelse>
|
||||
<cfset response.setMessage(results.message) />
|
||||
|
||||
<cfif findNoCase("insufficient funds", results.message)>
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
<cfelse>
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
|
||||
<!--- dwolla bundles everything in the Response key on a per-response basis, no commonality here unfortunately
|
||||
<cfif structKeyExists(results, "response") AND isStruct(results.response)>
|
||||
|
||||
<cfif structKeyExists(results.response, "id")>
|
||||
<cfset response.setTokenID(results.response.id) />
|
||||
</cfif>
|
||||
|
||||
</cfif>--->
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- HELPER FUNCTIONS --->
|
||||
<cffunction name="getGatewayURL" access="public" output="false" returntype="any" hint="Append to Gateway URL to return the appropriate url for the API endpoint">
|
||||
<cfargument name="endpoint" type="string" required="false" default="" />
|
||||
<cfargument name="oauth_token" type="string" required="false" />
|
||||
|
||||
<cfif reFind("https?://", arguments.endpoint, 1, false)>
|
||||
<cfreturn arguments.endpoint />
|
||||
<cfelseif structKeyExists(arguments, "oauth_token")>
|
||||
<cfreturn variables.cfpayment.GATEWAY_URL & arguments.endpoint & "?oauth_token=#URLEncodedFormat(arguments.oauth_token)#" />
|
||||
<cfelse>
|
||||
<cfreturn variables.cfpayment.GATEWAY_URL & arguments.endpoint />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
</cfcomponent>
|
||||
380
cfpayment/api/gateway/goemerchant/goemerchant.cfc
Normal file
380
cfpayment/api/gateway/goemerchant/goemerchant.cfc
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
<!---
|
||||
$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>
|
||||
7
cfpayment/api/gateway/goemerchant/readme.txt
Normal file
7
cfpayment/api/gateway/goemerchant/readme.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
The GoEMerchant interface under, certain circumstances returns a blank (" ")
|
||||
CVV and/or AVS value. In that case the value is left "un-set" or empty ("")
|
||||
in the response structure.
|
||||
|
||||
The most common case is if no CVV code is sent in, say for a recurring
|
||||
transaction, no CVV response is created. Empty AVS responses tend to be
|
||||
related to testing only.
|
||||
182
cfpayment/api/gateway/goemerchant/tests/gemTest.cfm
Normal file
182
cfpayment/api/gateway/goemerchant/tests/gemTest.cfm
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
<cfscript>
|
||||
gwParams = {};
|
||||
gwParams.Path = "goemerchant.goemerchant";
|
||||
|
||||
// except for password values must be entered here
|
||||
gwParams.MerchantAccount = "";
|
||||
gwParams.userName = ""; // GEM transcenter ID
|
||||
gwParams.password = ""; // not used
|
||||
|
||||
gwParams.mid = ""; //found in test mode virtual terminal - unique to your account
|
||||
gwParams.tid = ""; //found in test mode virtual terminal - unique to your account
|
||||
|
||||
svc = createObject("cfpayment.api.core");
|
||||
svc.init(gwParams);
|
||||
|
||||
account = svc.createCreditCard();
|
||||
account.setAccount(4111111111111111);
|
||||
account.setMonth(10);
|
||||
account.setYear(21);
|
||||
account.setVerificationValue();
|
||||
account.setFirstName("John");
|
||||
account.setLastName("Doe");
|
||||
account.setAddress("888");
|
||||
account.setPostalCode("77777");
|
||||
gw = svc.getGateway();
|
||||
money = svc.createMoney();
|
||||
errors=ArrayNew(1);
|
||||
money.init(100); //in cents
|
||||
options = {};
|
||||
options.order_id = "1234ORDER#dateFormat(now(), 'yyyymmdd')##timeformat(now(), 'HHmmssL')#";
|
||||
|
||||
//Authorize - Test AVS
|
||||
|
||||
for(variables.cents = 100; variables.cents <= 190; variables.cents += 5)
|
||||
{
|
||||
options.order_id = "1234ORDER#dateFormat(now(), 'yyyymmdd')##timeformat(now(), 'HHmmssL')#";
|
||||
money.setCents(variables.cents); // goEMerchant uses specific dollar amounts for test cases
|
||||
gemResponse = gw.authorize(money, account, options);
|
||||
|
||||
writeOutput("Authorize - Test AVS<br />");
|
||||
writeOutput('<div style="font-family:Courier;">');
|
||||
writeOutput('Amount : #money.getAmount()#<br />');
|
||||
writeOutput('Status : #gemResponse.getStatus()#<br />');
|
||||
writeOutput('TransID : #gemResponse.getTransactionID()#<br />');
|
||||
writeOutput('TokenID : #gemResponse.getTokenID()#<br />');
|
||||
writeOutput('CVV Rsp : (#account.getVerificationValue()#) - #gemResponse.getCVVCode()# - #gemResponse.getCVVMessage()#<br />');
|
||||
writeOutput('AVS Rsp : #gemResponse.getAVSCode()# - #gemResponse.getAVSMessage()#<br />');
|
||||
writeOutput('Auth Rsp : #gemResponse.getMessage()#<p />');
|
||||
getPageContext().getOut().flush();
|
||||
}
|
||||
|
||||
// Void - Success expected
|
||||
|
||||
gemResponse = gw.void(gemResponse.getTransactionID(), options);
|
||||
|
||||
writeOutput("Void - Success expected<br />");
|
||||
writeOutput('<div style="font-family:Courier;">');
|
||||
writeOutput('Amount : #money.getAmount()#<br />');
|
||||
writeOutput('Status : #gemResponse.getStatus()#<br />');
|
||||
writeOutput('TransID : #gemResponse.getTransactionID()#<br />');
|
||||
writeOutput('TokenID : #gemResponse.getTokenID()#<br />');
|
||||
writeOutput('Auth Rsp : #gemResponse.getMessage()#<p />');
|
||||
|
||||
// Purchase
|
||||
|
||||
options.order_id = "1234ORDER#dateFormat(now(), 'yyyymmdd')##timeformat(now(), 'HHmmssL')#";
|
||||
money.setCents(100); // goEMerchant uses specific dollar amounts for test cases
|
||||
gemResponse = gw.purchase(money, account, options);
|
||||
account.setVerificationValue();
|
||||
|
||||
writeOutput("Purchase<br />");
|
||||
writeOutput('<div style="font-family:Courier;">');
|
||||
writeOutput('Amount : #money.getAmount()#<br />');
|
||||
writeOutput('Status : #gemResponse.getStatus()#<br />');
|
||||
writeOutput('TransID : #gemResponse.getTransactionID()#<br />');
|
||||
writeOutput('TokenID : #gemResponse.getTokenID()#<br />');
|
||||
writeOutput('CVV Rsp : (#account.getVerificationValue()#) - #gemResponse.getCVVCode()# - #gemResponse.getCVVMessage()#<br />');
|
||||
writeOutput('AVS Rsp : #gemResponse.getAVSCode()# - #gemResponse.getAVSMessage()#<br />');
|
||||
writeOutput('Auth Rsp : #gemResponse.getMessage()#<p />');
|
||||
|
||||
// Credit - Failure expected
|
||||
|
||||
gemResponse = gw.credit(money, gemResponse.getTransactionID(), options);
|
||||
|
||||
writeOutput("Credit - Failure expected - you can only credit a transaction that has been through the nightly batch settlement.<br />");
|
||||
writeOutput('<div style="font-family:Courier;">');
|
||||
writeOutput('Amount : #money.getAmount()#<br />');
|
||||
writeOutput('Status : #gemResponse.getStatus()#<br />');
|
||||
writeOutput('TransID : #gemResponse.getTransactionID()#<br />');
|
||||
writeOutput('TokenID : #gemResponse.getTokenID()#<br />');
|
||||
writeOutput('Auth Rsp : #gemResponse.getMessage()#<p />');
|
||||
|
||||
//Authorize - Test CVV
|
||||
|
||||
variables.cvvList = "123,456,789,012,345";
|
||||
money.setCents(195); // goEMerchant uses specific dollar amounts for test cases
|
||||
|
||||
for(variables.cvv = 1; variables.cvv < 6; variables.cvv++)
|
||||
{
|
||||
account.setVerificationValue(listGetAt(variables.cvvList, variables.cvv));
|
||||
options.order_id = "1234ORDER#dateFormat(now(), 'yyyymmdd')##timeformat(now(), 'HHmmssL')#";
|
||||
gemResponse = gw.authorize(money, account, options);
|
||||
|
||||
writeOutput("Authorize - Test CVV<br />");
|
||||
writeOutput('<div style="font-family:Courier;">');
|
||||
writeOutput('Amount : #money.getAmount()#<br />');
|
||||
writeOutput('Status : #gemResponse.getStatus()#<br />');
|
||||
writeOutput('TransID : #gemResponse.getTransactionID()#<br />');
|
||||
writeOutput('TokenID : #gemResponse.getTokenID()#<br />');
|
||||
writeOutput('CVV Rsp : (#account.getVerificationValue()#) - #gemResponse.getCVVCode()# - #gemResponse.getCVVMessage()#<br />');
|
||||
writeOutput('AVS Rsp : #gemResponse.getAVSCode()# - #gemResponse.getAVSMessage()#<br />');
|
||||
writeOutput('Auth Rsp : #gemResponse.getMessage()#<p />');
|
||||
getPageContext().getOut().flush();
|
||||
}
|
||||
|
||||
// Settle (capture) - Success expected
|
||||
|
||||
account.setVerificationValue();
|
||||
gemResponse = gw.capture(money, gemResponse.getTransactionID(), options);
|
||||
|
||||
writeOutput("Settle (capture) - Success expected<br />");
|
||||
writeOutput('<div style="font-family:Courier;">');
|
||||
writeOutput('Amount : #money.getAmount()#<br />');
|
||||
writeOutput('Status : #gemResponse.getStatus()#<br />');
|
||||
writeOutput('TransID : #gemResponse.getTransactionID()#<br />');
|
||||
writeOutput('TokenID : #gemResponse.getTokenID()#<br />');
|
||||
writeOutput('CVV Rsp : (#account.getVerificationValue()#) - #gemResponse.getCVVCode()# - #gemResponse.getCVVMessage()#<br />');
|
||||
writeOutput('AVS Rsp : #gemResponse.getAVSCode()# - #gemResponse.getAVSMessage()#<br />');
|
||||
writeOutput('Auth Rsp : #gemResponse.getMessage()#<p />');
|
||||
|
||||
//Authorize - Test Decline
|
||||
|
||||
for(variables.cents = 200; variables.cents <= 454; variables.cents++) // there are some gaps that are not specific errors but you will get a decline
|
||||
{
|
||||
options.order_id = "1234ORDER#dateFormat(now(), 'yyyymmdd')##timeformat(now(), 'HHmmssL')#";
|
||||
money.setCents(variables.cents); // goEMerchant uses specific dollar amounts for test cases
|
||||
gemResponse = gw.authorize(money, account, options);
|
||||
|
||||
writeOutput("Authorize - Test Decline<br />");
|
||||
writeOutput('<div style="font-family:Courier;">');
|
||||
writeOutput('Amount : #money.getAmount()#<br />');
|
||||
writeOutput('Status : #gemResponse.getStatus()#<br />');
|
||||
writeOutput('TransID : #gemResponse.getTransactionID()#<br />');
|
||||
writeOutput('TokenID : #gemResponse.getTokenID()#<br />');
|
||||
writeOutput('CVV Rsp : (#account.getVerificationValue()#) - #gemResponse.getCVVCode()# - #gemResponse.getCVVMessage()#<br />');
|
||||
writeOutput('AVS Rsp : #gemResponse.getAVSCode()# - #gemResponse.getAVSMessage()#<br />');
|
||||
writeOutput('Auth Rsp : #gemResponse.getMessage()#<p />');
|
||||
getPageContext().getOut().flush();
|
||||
}
|
||||
|
||||
options.order_id = "1234ORDER#dateFormat(now(), 'yyyymmdd')##timeformat(now(), 'HHmmssL')#";
|
||||
money.setCents(493); // goEMerchant uses specific dollar amounts for test cases
|
||||
gemResponse = gw.authorize(money, account, options);
|
||||
|
||||
writeOutput("Authorize - Test Decline<br />");
|
||||
writeOutput('<div style="font-family:Courier;">');
|
||||
writeOutput('Amount : #money.getAmount()#<br />');
|
||||
writeOutput('Status : #gemResponse.getStatus()#<br />');
|
||||
writeOutput('TransID : #gemResponse.getTransactionID()#<br />');
|
||||
writeOutput('TokenID : #gemResponse.getTokenID()#<br />');
|
||||
writeOutput('CVV Rsp : (#account.getVerificationValue()#) - #gemResponse.getCVVCode()# - #gemResponse.getCVVMessage()#<br />');
|
||||
writeOutput('AVS Rsp : #gemResponse.getAVSCode()# - #gemResponse.getAVSMessage()#<br />');
|
||||
writeOutput('Auth Rsp : #gemResponse.getMessage()#<p />');
|
||||
|
||||
options.order_id = "1234ORDER#dateFormat(now(), 'yyyymmdd')##timeformat(now(), 'HHmmssL')#";
|
||||
money.setCents(999); // goEMerchant uses specific dollar amounts for test cases
|
||||
gemResponse = gw.authorize(money, account, options);
|
||||
|
||||
writeOutput("Authorize - Test Decline<br />");
|
||||
writeOutput('<div style="font-family:Courier;">');
|
||||
writeOutput('Amount : #money.getAmount()#<br />');
|
||||
writeOutput('Status : #gemResponse.getStatus()#<br />');
|
||||
writeOutput('TransID : #gemResponse.getTransactionID()#<br />');
|
||||
writeOutput('TokenID : #gemResponse.getTokenID()#<br />');
|
||||
writeOutput('CVV Rsp : (#account.getVerificationValue()#) - #gemResponse.getCVVCode()# - #gemResponse.getCVVMessage()#<br />');
|
||||
writeOutput('AVS Rsp : #gemResponse.getAVSCode()# - #gemResponse.getAVSMessage()#<br />');
|
||||
writeOutput('Auth Rsp : #gemResponse.getMessage()#<p />');
|
||||
|
||||
writeOutput('</div>');
|
||||
|
||||
</cfscript>
|
||||
|
||||
31
cfpayment/api/gateway/itransact/README
Normal file
31
cfpayment/api/gateway/itransact/README
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
ABOUT ITRANSACT.COM - $Id$
|
||||
|
||||
iTransact has three products available:
|
||||
|
||||
* "Front-end" HTML - create HTML forms customers post to iTransact.com, no programming required;
|
||||
includes features like customer email receipts, merchant dashboard and reporting.
|
||||
http://www.itransact.com/support/connect_html.html
|
||||
|
||||
* "Front-end" XML - receive customer details and post them to iTransact.com using HTTP; includes
|
||||
features like customer email receipts, merchant dashboard and reporting.
|
||||
http://www.itransact.com/support/connect_xml_fe.html
|
||||
|
||||
* "Back-end" XML - receive customer details and post them to iTransact.com using alternative XML
|
||||
interface - does NOT provide customer email receipts, etc. The private-labeled
|
||||
solution that requires more integration but more flexibility.
|
||||
|
||||
This Gateway implementation is for the third gateway, the "Back-end XML Gateway". For serious
|
||||
e-commerce merchants, this gives you absolute control over all aspects of the payment processing
|
||||
workflow but also requires more integration. Or, it did until we wrote the gateway for you.
|
||||
|
||||
Now you simply need to worry about the order tracking and reporting on your end, which any serious
|
||||
e-commerce shop is already doing. Even simple e-commerce companies will have a few database tables
|
||||
for orders, customers and so forth.
|
||||
|
||||
I've been using this gateway for the last 5 years (and 4 years at a company before that) and it has
|
||||
served me well.
|
||||
|
||||
To obtain service documentation (if desired) or your own test account (recommended), contact iTransact
|
||||
by email at support@itransact.com.
|
||||
|
||||
|
||||
508
cfpayment/api/gateway/itransact/itransact.cfc
Normal file
508
cfpayment/api/gateway/itransact/itransact.cfc
Normal file
|
|
@ -0,0 +1,508 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2008 Brian Ghidinelli (http://www.ghidinelli.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="Base iTransact XML Interface" extends="cfpayment.api.gateway.base" hint="Common functionality for iTransact/PaymentClearing.com Gateways" output="false">
|
||||
|
||||
<cfset variables.cfpayment.GATEWAY_NAME = "iTransact" />
|
||||
<cfset variables.cfpayment.GATEWAY_VERSION = "1.0" />
|
||||
<cfset variables.cfpayment.GATEWAY_LIVE_URL = "https://secure.paymentclearing.com:8180/registered/GatewayServlet" />
|
||||
<cfset variables.cfpayment.GATEWAY_TEST_URL = "https://secure.test.itransact.com/gateway/registered/GatewayServlet" />
|
||||
|
||||
<!--- shared process wrapper with gateway/transaction error handling --->
|
||||
<cffunction name="process" output="false" access="private" returntype="any">
|
||||
<cfargument name="payload" type="string" required="true" />
|
||||
|
||||
<cfset var p = structNew() />
|
||||
<cfset var response = "" />
|
||||
<cfset var xmlResponse = "" />
|
||||
|
||||
<!--- create options array; iTransact expects XML as a string under FORM variable "xml"; not sure if case-sensitive --->
|
||||
<cfset p["xml"] = arguments.payload />
|
||||
<cfset p["username"] = getUsername() />
|
||||
<cfset p["password"] = getPassword() />
|
||||
|
||||
<!--- send it over the wire using the base gateway --->
|
||||
<cfset response = createResponse(argumentCollection = super.process(payload = p)) />
|
||||
|
||||
<!--- we do some meta-checks for gateway-level errors (as opposed to auth/decline errors) --->
|
||||
<cfif NOT response.hasError()>
|
||||
|
||||
<!--- we need to have a result we can parse; otherwise that's an error in itself --->
|
||||
<cfif len(response.getResult()) AND isXML(response.getResult())>
|
||||
|
||||
<cfset xmlResponse = xmlParse(response.getResult()) />
|
||||
|
||||
<!--- store parsed result --->
|
||||
<cfset response.setParsedResult(xmlResponse) />
|
||||
|
||||
<!--- handle common response fields --->
|
||||
<cfif structKeyExists(xmlResponse.xmlRoot, "InternalId")>
|
||||
<cfset response.setTransactionID(xmlResponse.xmlRoot.InternalId.XmlText) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(xmlResponse.xmlRoot, "ErrorMessage")>
|
||||
<cfset response.setMessage(xmlResponse.xmlRoot.ErrorMessage.XmlText) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(xmlResponse.xmlRoot, "ApprovalCode")>
|
||||
<cfset response.setAuthorization(xmlResponse.xmlRoot.ApprovalCode.XmlText) />
|
||||
</cfif>
|
||||
|
||||
<cfif isTransactionResponseError(xmlResponse)>
|
||||
|
||||
<!--- transaction error means somethign bad happened *before* the transaction could be run but that request structure is OK (so an iTransact problem?) --->
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
<cfset response.setMessage(getTransactionResponseError(xmlResponse)) />
|
||||
|
||||
<cfelseif isGatewayFailure(xmlResponse)>
|
||||
|
||||
<!--- gateway failure means something happened *before* transaction was run: doesn't contain authentication fields, can't be mapped to a valid request structure, or has some other fatal initialization issues. --->
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
<cfset response.setMessage(getGatewayFailure(xmlResponse)) />
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- handle common "success" fields --->
|
||||
<cfif structKeyExists(xmlResponse.xmlRoot, "AVSResponse")>
|
||||
<cfset response.setAVSCode(xmlResponse.xmlRoot.AVSResponse.XmlText) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(xmlResponse.xmlRoot, "CVV2Response")>
|
||||
<cfset response.setCVVCode(xmlResponse.xmlRoot.CVV2Response.XmlText) />
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- this is bad, because iTransact didn't return XML. Uh oh! --->
|
||||
<cfset response.setStatus(getService().getStatusUnknown()) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- shared methods between credit card and e-checks --->
|
||||
<cffunction name="credit" output="false" access="public" returntype="any" hint="Credit all or part of a previous transaction">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="transactionid" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfset var xmlRequest = "" />
|
||||
<cfset var xmlResponse = "" />
|
||||
<cfset var response = "" />
|
||||
|
||||
<cfoutput>
|
||||
<cfxml variable="xmlRequest">
|
||||
<IdBasedCreditRequest>
|
||||
<CentAmount>#arguments.money.getCents()#</CentAmount>
|
||||
<InternalId>#arguments.transactionid#</InternalId>
|
||||
<ExternalId>#arguments.options.ExternalId#</ExternalId>
|
||||
<MerchantAccountNumber>#getMerchantAccount()#</MerchantAccountNumber>
|
||||
</IdBasedCreditRequest>
|
||||
</cfxml>
|
||||
</cfoutput>
|
||||
|
||||
<!--- run thru local process routine which normalizes the response --->
|
||||
<cfset response = process(toString(xmlRequest)) />
|
||||
|
||||
<!--- see if the response is already an error --->
|
||||
<cfif NOT response.hasError() AND isXML(response.getResult())>
|
||||
|
||||
<!--- the raw result is XML, parse it --->
|
||||
<cfset xmlResponse = xmlParse(response.getResult()) />
|
||||
|
||||
<!--- normalize status and responses --->
|
||||
<!--- see if the response object has a successful root node: <CardAuthResponseOK> --->
|
||||
<cfif isCardAuthOK(xmlResponse)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
<cfset response.setAuthorization(xmlResponse.xmlRoot.ApprovalCode.XmlText) />
|
||||
<cfset response.setTransactionID(xmlResponse.xmlRoot.InternalId.XmlText) />
|
||||
|
||||
<cfelseif isCardAuthError(xmlResponse)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
<cfset response.setTransactionID(xmlResponse.xmlRoot.InternalId.XmlText) />
|
||||
<cfset response.setMessage(getCardAuthError(xmlResponse)) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="void" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="transactionid" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfset var xmlRequest = "" />
|
||||
<cfset var response = "" />
|
||||
|
||||
<cfoutput>
|
||||
<cfxml variable="xmlRequest">
|
||||
<IdBasedVoidRequest>
|
||||
<ExternalId>#arguments.options.ExternalId#</ExternalId>
|
||||
<InternalId>#arguments.transactionid#</InternalId>
|
||||
<MerchantAccountNumber>#getMerchantAccount()#</MerchantAccountNumber>
|
||||
</IdBasedVoidRequest>
|
||||
</cfxml>
|
||||
</cfoutput>
|
||||
|
||||
<!--- run thru local process routine which normalizes the response --->
|
||||
<cfset response = process(toString(xmlRequest)) />
|
||||
|
||||
<!--- see if the response is already an error --->
|
||||
<cfif NOT response.hasError() AND isXML(response.getResult())>
|
||||
|
||||
<!--- the raw result is XML, parse it --->
|
||||
<cfset xmlResponse = xmlParse(response.getResult()) />
|
||||
|
||||
<!--- normalize status and responses --->
|
||||
<!--- see if the response object has a successful root node: <CardAuthResponseOK> --->
|
||||
<cfif isVoid(xmlResponse) OR isCardAuthOK(xmlResponse)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
<cfset response.setAuthorization(xmlResponse.xmlRoot.ApprovalCode.XmlText) />
|
||||
<cfset response.setTransactionID(xmlResponse.xmlRoot.InternalId.XmlText) />
|
||||
|
||||
<cfelseif isCardAuthError(xmlResponse)>
|
||||
|
||||
<!--- the void failed for some reason; i'm not sure if we'll ever make it here
|
||||
documentation says a CardAuthResponseError can come back but I think we only
|
||||
get Gateway Failures for "transaction not found" --->
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
<cfset response.setTransactionID(xmlResponse.xmlRoot.InternalId.XmlText) />
|
||||
<cfset response.setMessage(getCardAuthError(xmlResponse)) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="settle" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfset var xmlRequest = "" />
|
||||
<cfset var response = "" />
|
||||
|
||||
<cfoutput>
|
||||
<cfxml variable="xmlRequest">
|
||||
<SettlementRequest>
|
||||
<ExternalId>#arguments.options.ExternalId#</ExternalId>
|
||||
<MerchantAccountNumber>#getMerchantAccount()#</MerchantAccountNumber>
|
||||
</SettlementRequest>
|
||||
</cfxml>
|
||||
</cfoutput>
|
||||
|
||||
<!--- return the response which will need to be parsed via response.getResult() --->
|
||||
<cfset response = process(toString(xmlRequest)) />
|
||||
|
||||
<!--- see if the response is already an error --->
|
||||
<cfif NOT response.hasError() AND isXML(response.getResult())>
|
||||
|
||||
<!--- the raw result is XML, parse it --->
|
||||
<cfset xmlResponse = xmlParse(response.getResult()) />
|
||||
|
||||
<!--- if we have a SettlementResponseOk node, it came back ok --->
|
||||
<cfif lcase(xmlResponse.xmlRoot.xmlName) EQ lcase("SettlementResponseOk")>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
<cfset response.setTransactionID(xmlResponse.xmlRoot.InternalId.XmlText) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<!--- function to get a copy of the actual transaction response
|
||||
|
||||
Only requests that have valid structure and therefore reach the processing modules are available for this.
|
||||
This means that any request that would return <GatewayResponseFail> will not be loadable.
|
||||
If a ReportResponseFail is returned from this request, it is most likely that the original request resulted
|
||||
in a GatewayResponseFail response.
|
||||
--->
|
||||
<cffunction name="status" output="false" access="public">
|
||||
<cfargument name="transactionid" type="any" required="false" default="" hint="If checking status of a transaction with unknown response, this may not be known and can be blank" />
|
||||
<cfargument name="options" type="any" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var xmlRequest = "" />
|
||||
<cfset var xmlResponse = "" />
|
||||
<cfset var response = "" />
|
||||
|
||||
<cfif NOT (len(arguments.transactionid) OR (structKeyExists(arguments.options, "ExternalID") AND len(arguments.options.ExternalID)))>
|
||||
<cfthrow type="cfpayment.MissingParameter.Argument" detail="Requires either tranactionid or ExternalID to determine status" />
|
||||
</cfif>
|
||||
|
||||
<cfoutput>
|
||||
<cfxml variable="xmlRequest">
|
||||
<TransactionResponseReportRequest>
|
||||
<cfif structKeyExists(arguments.options, "ExternalId")>
|
||||
<ExternalId>#arguments.options.ExternalID#</ExternalId>
|
||||
<MerchantAccountNumber>#getMerchantAccount()#</MerchantAccountNumber>
|
||||
<cfelse>
|
||||
<InternalId>#arguments.transactionid#</InternalId>
|
||||
</cfif>
|
||||
</TransactionResponseReportRequest>
|
||||
</cfxml>
|
||||
</cfoutput>
|
||||
|
||||
<!--- run thru local process routine which normalizes the response --->
|
||||
<cfset response = process(toString(xmlRequest)) />
|
||||
|
||||
<!--- see if the response is already an error --->
|
||||
<cfif NOT response.hasError() AND isXML(response.getResult())>
|
||||
|
||||
<!--- the raw result is XML, parse it --->
|
||||
<cfset xmlResponse = xmlParse(response.getResult()) />
|
||||
|
||||
<!--- normalize status and responses --->
|
||||
<!--- see if the response object has a successful root node --->
|
||||
<cfif listFindNoCase("CheckAuthResponseOK,CardAuthResponseOK", xmlResponse.xmlRoot.xmlName)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
|
||||
<cfelseif listFindNoCase("CheckAuthResponseError,CardAuthResponseError", xmlResponse.xmlRoot.xmlName)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
|
||||
<cfelse>
|
||||
|
||||
<!--- usually means original transaction resulted in GatewayResponseFail --->
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
<cfset response.setMessage(xmlResponse.xmlRoot.ErrorMessage.XmlText) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<!--- PRIVATE HELPER METHODS FOR PARSING XML ------------------------------
|
||||
|
||||
Based upon iTransact Documentation as of 6/24/2006
|
||||
Used in production through 11/8/2008
|
||||
|
||||
----------------------------------------------------------------------- --->
|
||||
|
||||
<!--- boolean test to see if the check transaction failed --->
|
||||
<cffunction name="isTransactionResponseError" output="false" access="private" returntype="boolean">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
<!--- first format looks like:
|
||||
|
||||
<TransactionResponseFail>
|
||||
<ErrorCategory>text</ErrorCategory>
|
||||
<ErrorCode>text</ErrorCode>
|
||||
<ErrorMessage>text</ErrorMessage>
|
||||
<InternalId>text</InternalId>
|
||||
</TransactionResponseFail>
|
||||
|
||||
<cfswitch expression="#xmlObject.xmlNode.ErrorMessage#">
|
||||
<cftry value="EXPIRED CARD">
|
||||
Expired Card
|
||||
</cftry>
|
||||
...
|
||||
<cfcase value="PROCESSOR_CONNECTION,PROCESSOR_ERROR">
|
||||
<cfset msg = "The transaction was temporarily declined because we could not obtain an answer from your bank. Please resubmit your payment in a few minutes or try an e-check.">
|
||||
</cfcase>
|
||||
<cftry value="REQ. EXCEEDS BALANCE">
|
||||
Request exceeds available balance o ncard
|
||||
</cftry>
|
||||
<cfdefaultcase>
|
||||
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
--->
|
||||
|
||||
<!--- see if the response object has an error root node: <CardAuthResponseError> or <TransactionResponseFail> --->
|
||||
<cfif lcase(xmlObject.xmlRoot.xmlName) EQ lcase("TransactionResponseFail")>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- return a string message for the cause of the error --->
|
||||
<cffunction name="getTransactionResponseError" output="false" access="private" returntype="string">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
|
||||
<cfset var msg = "" />
|
||||
<!--- first format looks like:
|
||||
<TransactionResponseFail>
|
||||
<ErrorCategory>text</ErrorCategory>
|
||||
<ErrorCode>text</ErrorCode>
|
||||
<ErrorMessage>text</ErrorMessage>
|
||||
<InternalId>text</InternalId>
|
||||
</TransactionResponseFail>
|
||||
--->
|
||||
|
||||
<cfif IsDefined("xmlObject.xmlRoot.ErrorMessage.xmlText")>
|
||||
|
||||
<cfswitch expression="#xmlObject.xmlRoot.ErrorMessage#">
|
||||
<cfcase value="PROCESSOR_CONNECTION,PROCESSOR_ERROR">
|
||||
<cfset msg = "The transaction was temporarily declined because we could not obtain an answer from the bank. Please resubmit your payment in a few minutes." />
|
||||
</cfcase>
|
||||
<cfcase value="SYSTEM_ERROR">
|
||||
<cfset msg = "The transaction was temporarily unable to be processed by the bank due to a system error. Please resubmit your payment in a few minutes." />
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfset msg = "There was a transaction error connecting with the bank caused by: " & xmlObject.xmlRoot.ErrorMessage.xmlText />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
<cfelse>
|
||||
<cfset msg = "No error description found. Please contact the administrators for help. The error object is: #htmlEditFormat(toString(xmlObject))#" />
|
||||
</cfif>
|
||||
|
||||
<!--- return msg --->
|
||||
<cfreturn msg />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- boolean test to see if the gateway had a failure --->
|
||||
<cffunction name="isGatewayFailure" output="false" access="private" returntype="boolean">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
<!--- format looks like:
|
||||
<GatewayResponseFail>
|
||||
<ErrorCategory>DATA_VALIDATION</ErrorCategory>
|
||||
<ErrorCode>castor.Unmarshal.unmarshal.2</ErrorCode>
|
||||
<ErrorMessage>unable to add text content to CardAccountNumber due to the following error: java.lang.IllegalStateException: Field access error: account(java.lang.String) access resulted in exception: null</ErrorMessage>
|
||||
</GatewayResponseFail>
|
||||
--->
|
||||
|
||||
<!--- see if the response object has an error root node: <CardAuthResponseError> --->
|
||||
<cfif lcase(xmlObject.xmlRoot.xmlName) EQ lcase("GatewayResponseFail")>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- method to return the gateway failure error --->
|
||||
<cffunction name="getGatewayFailure" output="false" access="private" returntype="string">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
|
||||
<cfset var msg = "" />
|
||||
<!--- format looks like:
|
||||
<GatewayResponseFail>
|
||||
<ErrorCategory>DATA_VALIDATION</ErrorCategory>
|
||||
<ErrorCode>castor.Unmarshal.unmarshal.2</ErrorCode>
|
||||
<ErrorMessage>unable to add text content to CardAccountNumber due to the following error: java.lang.IllegalStateException: Field access error: account(java.lang.String) access resulted in exception: null</ErrorMessage>
|
||||
</GatewayResponseFail>
|
||||
|
||||
ErrorCategory:
|
||||
DATABASE - Database Error
|
||||
<09> DATA_VALIDATION - Error validating data within code. Not request specific.
|
||||
<09> PROCESSOR_CONNECTION - There was an error while connecting to the processing network.
|
||||
<09> PROCESSOR_DENIED - The processor denied the authorization.
|
||||
<09> PROCESSOR_ERROR - The processing network reported an internal problem.
|
||||
<09> REQUEST_VALIDATION - The request could not be processed because of a problem with the
|
||||
request. This could be becouse of formatting, missing data, invalid data, etc.
|
||||
<09> SECURITY - The request could not be processed because it would violate system security constraints.
|
||||
<09> SYSTEM_CONFIG - The iTransact Gateway is not configured correctly, please report.
|
||||
<09> SYSTEM_ERROR - There was a general system error while processing the request, please report.
|
||||
<09> UNSPECIFIED - There was an unexpected error processing the transaction.
|
||||
--->
|
||||
|
||||
<cfif IsDefined("xmlObject.xmlRoot.ErrorMessage.xmlText")>
|
||||
<cfswitch expression="#xmlObject.xmlRoot.ErrorMessage.xmlText#">
|
||||
<!--- cfcase value="DATABASE">
|
||||
<cfset msg = "">
|
||||
</cfcase>
|
||||
<cfcase value="DATA_VALIDATION">
|
||||
<cfset msg = "">
|
||||
</cfcase>
|
||||
<cfcase value="PROCESSOR_CONNECTION">
|
||||
<cfset msg = "">
|
||||
</cfcase --->
|
||||
<cfdefaultcase>
|
||||
<cfset msg = "The transaction was declined by the bank because: #xmlObject.xmlRoot.ErrorMessage.xmlText#" />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
<cfelse>
|
||||
<cfset msg = "No error description found. Please contact the administrators for help. The error object is: #toString(xmlObject)#" />
|
||||
</cfif>
|
||||
|
||||
<!--- see if the response object has an error root node: <CardAuthResponseError> --->
|
||||
<cfreturn msg />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="isTransaction" output="false" access="private" returntype="boolean">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
<!---
|
||||
If a transaction does not exist in the DB, this is the error we'll get:
|
||||
<?xml version="1.0"?>
|
||||
<ReportResponseFail>
|
||||
<ErrorCategory>DATABASE</ErrorCategory>
|
||||
<ErrorCode>trans.RequestResponseMap.DBLoadByExternalTransactionId.1</ErrorCode>
|
||||
<ErrorMessage>No record for externalId 18317065 and merchantAccountNumber 13588</ErrorMessage>
|
||||
<InternalId>21794289</InternalId>
|
||||
</ReportResponseFail>
|
||||
--->
|
||||
|
||||
<!--- see if the response object has an error root node: <ReportResponseFail> --->
|
||||
<cfif lcase(xmlObject.xmlRoot.xmlName) EQ lcase("ReportResponseFail")>
|
||||
<cfreturn false />
|
||||
<cfelse>
|
||||
<cfreturn true />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="isVoid" output="false" access="private" returntype="boolean">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
<!---
|
||||
If a transaction has been voided, its previously successful response will come back as a VOID:
|
||||
|
||||
<CardAuthResponseOk>
|
||||
<ApprovalCode> SALE</ApprovalCode>
|
||||
<BatchNumber>877</BatchNumber>
|
||||
<CVV2Response></CVV2Response>
|
||||
<InternalId>21795510</InternalId>
|
||||
<ProcessorTransactionId>010</ProcessorTransactionId>
|
||||
</CardAuthResponseOk>
|
||||
--->
|
||||
|
||||
<!--- see if the response object has root node: <CardAuthResponseOk> --->
|
||||
<!--- The first character or two in " SALE" is NOT a space, it's some other character --->
|
||||
<cfif lcase(xmlObject.xmlRoot.xmlName) EQ lcase("CardAuthResponseOk") AND lcase(trim(right(xmlObject.xmlRoot.ApprovalCode.XmlText, 4))) EQ "sale">
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
</cfcomponent>
|
||||
272
cfpayment/api/gateway/itransact/itransact_cc.cfc
Normal file
272
cfpayment/api/gateway/itransact/itransact_cc.cfc
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2008 Brian Ghidinelli (http://www.ghidinelli.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="iTransact XML Interface" extends="itransact" hint="Used for processing credit card payments via iTransact.com/PaymentClearing.com" output="false">
|
||||
|
||||
<!--- wrap process with cardauth* processing --->
|
||||
<cffunction name="process" output="false" access="private" returntype="any">
|
||||
<!--- pass up the chain, and do generic result processing --->
|
||||
<cfset var response = super.process(argumentCollection = arguments) />
|
||||
<cfset var xmlResponse = "" />
|
||||
|
||||
<!--- see if the response is already an error --->
|
||||
<cfif NOT response.hasError() AND isXML(response.getResult())>
|
||||
|
||||
<!--- the raw result is XML, load it --->
|
||||
<cfset xmlResponse = response.getParsedResult() />
|
||||
|
||||
<!--- see if the response object has a successful root node: <CardAuthResponseOK> --->
|
||||
<cfif isCardAuthOK(xmlResponse)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
|
||||
<cfelseif isCardAuthError(xmlResponse)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
<cfset response.setMessage(getCardAuthError(xmlResponse)) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- implement primary methods --->
|
||||
<cffunction name="purchase" output="false" access="public" returntype="any" hint="Authorize + Capture in one step">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfset var xmlRequest = "" />
|
||||
|
||||
<cfoutput>
|
||||
<cfxml variable="xmlRequest">
|
||||
<CardSaleRequest>
|
||||
<CentAmount>#arguments.money.getCents()#</CentAmount>
|
||||
<CardAccountNumber>#arguments.account.getAccount()#</CardAccountNumber>
|
||||
<CardExpirationDate month="#arguments.account.getMonth()#" year="#arguments.account.getYear()#" />
|
||||
<ExternalId>#arguments.options.ExternalId#</ExternalId>
|
||||
<MerchantAccountNumber>#getMerchantAccount()#</MerchantAccountNumber>
|
||||
<cfif len(arguments.account.getPostalCode())><PostalCode>#xmlFormat(arguments.account.getPostalCode())#</PostalCode></cfif>
|
||||
<cfif len(arguments.account.getAddress())><StreetAddress>#xmlFormat(arguments.account.getAddress())#</StreetAddress></cfif>
|
||||
<cfif len(arguments.account.getVerificationValue())>
|
||||
<CardCVV2Data number="#arguments.account.getVerificationValue()#" indicator="1"/>
|
||||
<cfelse>
|
||||
<CardCVV2Data number="" indicator="0"/>
|
||||
</cfif>
|
||||
</CardSaleRequest>
|
||||
</cfxml>
|
||||
</cfoutput>
|
||||
|
||||
<cfreturn process(toString(xmlRequest)) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="authorize" output="false" access="public" returntype="any" hint="Authorize (only) a credit card">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfset var xmlRequest = "" />
|
||||
|
||||
<cfoutput>
|
||||
<cfxml variable="xmlRequest">
|
||||
<CardPreAuthRequest>
|
||||
<CentAmount>#arguments.money.getCents()#</CentAmount>
|
||||
<CardAccountNumber>#arguments.account.getAccount()#</CardAccountNumber>
|
||||
<CardExpirationDate month="#arguments.account.getMonth()#" year="#arguments.account.getYear()#" />
|
||||
<ExternalId>#arguments.options.ExternalId#</ExternalId>
|
||||
<MerchantAccountNumber>#getMerchantAccount()#</MerchantAccountNumber>
|
||||
<cfif len(arguments.account.getPostalCode())><PostalCode>#xmlFormat(arguments.account.getPostalCode())#</PostalCode></cfif>
|
||||
<cfif len(arguments.account.getAddress())><StreetAddress>#xmlFormat(arguments.account.getAddress())#</StreetAddress></cfif>
|
||||
</CardPreAuthRequest>
|
||||
</cfxml>
|
||||
</cfoutput>
|
||||
|
||||
<cfreturn process(toString(xmlRequest)) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="capture" output="false" access="public" returntype="any" hint="Add a previous authorization to be settled">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="authorization" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfset var xmlRequest = "" />
|
||||
|
||||
<cfoutput>
|
||||
<cfxml variable="xmlRequest">
|
||||
<CardPostAuthRequest>
|
||||
<CentAmount>#arguments.money.getCents()#</CentAmount>
|
||||
<ExternalId>#arguments.options.ExternalId#</ExternalId>
|
||||
<InternalId>#arguments.options.InternalId#</InternalId>
|
||||
<MerchantAccountNumber>#getMerchantAccount()#</MerchantAccountNumber>
|
||||
</CardPostAuthRequest>
|
||||
</cfxml>
|
||||
</cfoutput>
|
||||
|
||||
<!--- run thru local process routine which normalizes the response --->
|
||||
<cfreturn process(toString(xmlRequest)) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- additional gateway specific requests --->
|
||||
<cffunction name="checkAVS" output="false" access="public" returntype="any" hint="Verify (but not process) the AVS for the credit card">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfset var xmlRequest = "" />
|
||||
|
||||
<cfoutput>
|
||||
<cfxml variable="xmlRequest">
|
||||
<CardAVSOnlyRequest>
|
||||
<CentAmount>#arguments.money.getCents()#</CentAmount>
|
||||
<CardAccountNumber>#arguments.account.getAccount()#</CardAccountNumber>
|
||||
<CardExpirationDate month="#arguments.account.getMonth()#" year="#arguments.account.getYear()#" />
|
||||
<ExternalId>#arguments.options.ExternalId#</ExternalId>
|
||||
<MerchantAccountNumber>#getMerchantAccount()#</MerchantAccountNumber>
|
||||
<cfif len(arguments.account.getPostalCode())><PostalCode>#xmlFormat(arguments.account.getPostalCode())#</PostalCode></cfif>
|
||||
<cfif len(arguments.account.getAddress())><StreetAddress>#xmlFormat(arguments.account.getAddress())#</StreetAddress></cfif>
|
||||
</CardAVSOnlyRequest>
|
||||
</cfxml>
|
||||
</cfoutput>
|
||||
|
||||
<cfreturn process(toString(xmlRequest)) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getIsCCEnabled" access="public" output="false" returntype="boolean">
|
||||
<cfreturn true />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- PRIVATE HELPER METHODS FOR PARSING XML ------------------------------
|
||||
|
||||
Based upon iTransact Documentation as of 6/24/2006
|
||||
Used in production through 11/8/2008
|
||||
|
||||
----------------------------------------------------------------------- --->
|
||||
|
||||
<!--- boolean test to see if the transaction was successful --->
|
||||
<cffunction name="isCardAuthOK" output="false" access="private" returntype="boolean">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
<!--- format looks like:
|
||||
<CardAuthResponseOk>
|
||||
<ApprovalCode>text</ApprovalCode>
|
||||
<AVSCategory>text</AVSCategory>
|
||||
<AVSResponse>text</AVSResponse>
|
||||
<CVV2Response>text</CVV2Response>
|
||||
<InternalId>text</InternalId>
|
||||
</CardAuthResponseOk>
|
||||
--->
|
||||
|
||||
<!--- see if the response object has a successful root node: <CardAuthResponseOK> --->
|
||||
<cfif lcase(xmlObject.xmlRoot.xmlName) EQ lcase("CardAuthResponseOK")>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- boolean test to see if the transaction failed --->
|
||||
<cffunction name="isCardAuthError" output="false" access="private" returntype="boolean">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
|
||||
<!--- see if the response object has an error root node: <CardAuthResponseError> --->
|
||||
<cfif lcase(xmlObject.xmlRoot.xmlName) EQ lcase("CardAuthResponseError")>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- return a string message for the cause of the error --->
|
||||
<cffunction name="getCardAuthError" output="false" access="private" returntype="string">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
|
||||
<cfset var msg = "" />
|
||||
<!--- first format looks like:
|
||||
<CardAuthResponseError>
|
||||
<AVSCategory>text</AVSCategory>
|
||||
<AVSResponse>text</AVSResponse>
|
||||
<CVV2Response>text</CVV2Response>
|
||||
<ErrorMessage>text</ErrorMessage>
|
||||
<InternalId>text</InternalId>
|
||||
</CardAuthResponseError>
|
||||
|
||||
second:
|
||||
<TransactionResponseFail>
|
||||
...
|
||||
</TransactionResponseFail>
|
||||
--->
|
||||
<cfif IsDefined("xmlObject.xmlRoot.ErrorMessage.xmlText")>
|
||||
<cfswitch expression="#xmlObject.xmlRoot.ErrorMessage.xmlText#">
|
||||
<cfcase value="EXPIRED CARD">
|
||||
<cfset msg = "The transaction was declined because the credit card has expired. Please try another credit card or e-check.">
|
||||
</cfcase>
|
||||
<cfcase value="NOT ON FILE">
|
||||
<cfset msg = "Your bank has declined the transaction indicating you are not on file. You should call your bank to verify your account is working properly.">
|
||||
</cfcase>
|
||||
<cfcase value="INVALID CARD">
|
||||
<cfset msg = "The transaction was declined because the card number was invalid. Please double-check the number matches the digits on your card.">
|
||||
</cfcase>
|
||||
<cfcase value="DECLINED">
|
||||
<!--- check the reason why --->
|
||||
<cfif listFindNoCase("C,N,R", ucase(xmlObject.xmlRoot.AVSResponse.xmlText))>
|
||||
<cfset msg = "The transaction was declined because the address or zip code provided does not match the information on file at your bank. Are you sure the address supplied matches your billing address?">
|
||||
<cfelse>
|
||||
<cfset msg = "The transaction was declined by your bank. Please try another credit card or e-check.">
|
||||
</cfif>
|
||||
</cfcase>
|
||||
<cfcase value="CALL AUTH CENTER">
|
||||
<cfset msg = "Your bank is asking me to call for a voice authorization but I am just a computer! Would you please call them and ask why they declined your card? Then you can return and I will happily accept your payment.">
|
||||
</cfcase>
|
||||
<cfcase value="CALL REF.; 999999,PICK UP CARD">
|
||||
<cfset msg = "Your bank has instructed us to decline your card at this time. Please try another credit card or e-check.">
|
||||
</cfcase>
|
||||
<cfcase value="DECLINE CVV2,DECLINED CVV2,CVV2 MISMATCH">
|
||||
<cfset msg = "The transaction was declined because the security code on the back of your card does not match the code on file at your bank. Please verify the 3-digit code is correct.">
|
||||
</cfcase>
|
||||
<cfcase value="PLEASE RETRY">
|
||||
<cfset msg = "There was a temporary error processing your card with the bank. Please retry the transaction.">
|
||||
</cfcase>
|
||||
<cfcase value="MAX MONTHLY $VOL">
|
||||
<cfset msg = "There has been a temporary error with the bank that requires our attention. Please try again later.">
|
||||
</cfcase>
|
||||
<cfcase value="REQ. EXCEEDS BALANCE">
|
||||
<cfset msg = "The transaction was declined because this charge would exceed the credit limit of the card. Please try another credit card or e-check.">
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfset msg = "The transaction was declined by the bank because: #xmlObject.xmlRoot.ErrorMessage.xmlText#" />
|
||||
<!--- should notify admins here so we can better message this in the future --->
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
<cfelse>
|
||||
<cfset msg = "No error description found. Please contact the administrators for help. The error object is: #toString(xmlObject)#" />
|
||||
</cfif>
|
||||
|
||||
<!--- return msg --->
|
||||
<cfreturn msg />
|
||||
</cffunction>
|
||||
|
||||
|
||||
</cfcomponent>
|
||||
264
cfpayment/api/gateway/itransact/itransact_eft.cfc
Normal file
264
cfpayment/api/gateway/itransact/itransact_eft.cfc
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2008 Brian Ghidinelli (http://www.ghidinelli.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="iTransact XML Interface" extends="itransact" hint="Used for processing e-checks payments via iTransact.com/PaymentClearing.com" output="false">
|
||||
|
||||
<!--- wrap process with checkauth* processing --->
|
||||
<cffunction name="process" output="false" access="private" returntype="any">
|
||||
<!--- pass up the chain, and do generic result processing --->
|
||||
<cfset var response = super.process(argumentCollection = arguments) />
|
||||
<cfset var xmlResponse = "" />
|
||||
|
||||
<!--- see if the response is already an error --->
|
||||
<cfif NOT response.hasError() AND isXML(response.getResult())>
|
||||
|
||||
<!--- the raw result is XML, load it --->
|
||||
<cfset xmlResponse = response.getParsedResult() />
|
||||
|
||||
<!--- see if the response object has a successful root node: <CheckAuthResponseOK> --->
|
||||
<cfif isCheckAuthOK(xmlResponse)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
|
||||
<cfelseif isCheckAuthError(xmlResponse)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
<cfset response.setMessage(getCheckAuthError(xmlResponse)) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- override the primary methods --->
|
||||
<cffunction name="authorize" output="false" access="public" returntype="any" hint="">
|
||||
<cfthrow message="Authorize not implemented for E-checks; use purchase instead." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- e-check doesn't have separate auth vs. purchase --->
|
||||
<cffunction name="purchase" output="false" access="public" returntype="any" hint="Debit a checking account">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfset var xmlRequest = "" />
|
||||
<cfset var xmlResponse = "" />
|
||||
<cfset var response = "" />
|
||||
|
||||
<cfoutput>
|
||||
<cfxml variable="xmlRequest">
|
||||
<CheckAuthRequest>
|
||||
<FirstName>#arguments.account.getFirstName()#</FirstName>
|
||||
<LastName>#arguments.account.getLastName()#</LastName>
|
||||
<PhoneNumber>#xmlFormat(arguments.account.getPhoneNumber())#</PhoneNumber>
|
||||
<CentAmount>#arguments.money.getCents()#</CentAmount>
|
||||
<BankRouteNumber>#arguments.account.getRoutingNumber()#</BankRouteNumber>
|
||||
<BankAccountNumber>#arguments.account.getAccount()#</BankAccountNumber>
|
||||
<ExternalId>#arguments.options.ExternalId#</ExternalId>
|
||||
<MerchantAccountNumber>#getMerchantAccount()#</MerchantAccountNumber>
|
||||
<cfif len(arguments.account.getAddress())><Address1>#xmlFormat(arguments.account.getAddress())#</Address1></cfif>
|
||||
<cfif len(arguments.account.getAddress2())><Address2>#xmlFormat(arguments.account.getAddress2())#</Address2></cfif>
|
||||
<cfif len(arguments.account.getPostalCode())><PostalCode>#xmlFormat(arguments.account.getPostalCode())#</PostalCode></cfif>
|
||||
<cfif len(arguments.account.getCheckNumber())><CheckNumber>#arguments.account.getCheckNumber()#</CheckNumber></cfif>
|
||||
</CheckAuthRequest>
|
||||
</cfxml>
|
||||
</cfoutput>
|
||||
|
||||
<cfreturn process(toString(xmlRequest)) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- can idbasedcredit work?
|
||||
<cffunction name="credit" output="false" access="public" returntype="any" hint="Credit all or part of a previous transaction">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="transactionid" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
|
||||
<cfset var xmlRequest = "" />
|
||||
<cfset var xmlResponse = "" />
|
||||
<cfset var response = "" />
|
||||
|
||||
<cfoutput>
|
||||
<cfxml variable="xmlRequest">
|
||||
<CheckCreditRequest>
|
||||
<CentAmount>#arguments.money.getCents()#</CentAmount>
|
||||
<BankAccountNumber>number</BankAccountNumber>
|
||||
<BankRouteNumber>number</BankRouteNumber>
|
||||
<ExternalId>number</ExternalId>
|
||||
<FirstName>string</FirstName>
|
||||
<LastName>string</LastName>
|
||||
<MerchantAccountNumber>number</MerchantAccountNumber>
|
||||
</CheckCreditRequest>
|
||||
|
||||
<IdBasedCreditRequest>
|
||||
<CentsAmount>#arguments.money.getCents()#</CentsAmount>
|
||||
<InternalId>#arguments.transactionid#</InternalId>
|
||||
<ExternalId>#arguments.options.ExternalId#</ExternalId>
|
||||
<MerchantAccountNumber>#getMerchantAccount()#</MerchantAccountNumber>
|
||||
</IdBasedCreditRequest>
|
||||
</cfxml>
|
||||
</cfoutput>
|
||||
|
||||
<!--- run thru local process routine which normalizes the response --->
|
||||
<cfset response = process(toString(xmlRequest)) />
|
||||
|
||||
<!--- see if the response is already an error --->
|
||||
<cfif NOT response.hasError() AND isXML(response.getResult())>
|
||||
|
||||
<!--- the raw result is XML, load it --->
|
||||
<cfset xmlResponse = response.getParsedResult() />
|
||||
|
||||
<!--- normalize status and responses --->
|
||||
<!--- see if the response object has a successful root node: <CardAuthResponseOK> --->
|
||||
<cfif isCardAuthOK(xmlResponse)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
<cfset response.setAuthorization(xmlResponse.xmlRoot.ApprovalCode.XmlText) />
|
||||
<cfset response.setTransactionID(xmlResponse.xmlRoot.InternalId.XmlText) />
|
||||
|
||||
<cfelseif isCardAuthError(xmlResponse)>
|
||||
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
<cfset response.setTransactionID(xmlResponse.xmlRoot.InternalId.XmlText) />
|
||||
<cfset response.setMessage(getCardAuthError(xmlResponse)) />
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
--->
|
||||
|
||||
<cffunction name="getIsEFTEnabled" access="public" output="false" returntype="boolean">
|
||||
<cfreturn true />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- PRIVATE HELPER METHODS FOR PARSING XML ------------------------------
|
||||
|
||||
Based upon iTransact Documentation as of 6/24/2006
|
||||
Used in production through 11/8/2008
|
||||
|
||||
----------------------------------------------------------------------- --->
|
||||
|
||||
<!--- boolean test to see if the transaction was successful --->
|
||||
<cffunction name="isCheckAuthOK" output="false" access="private" returntype="boolean">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
<!--- format looks like:
|
||||
<CheckAuthResponseOk>
|
||||
<InternalId>number</InternalId>
|
||||
<ProcessorTransactionId>string</ProcessorTransactionId>
|
||||
</CheckAuthResponseOk>
|
||||
--->
|
||||
|
||||
<!--- see if the response object has a successful root node: <CardAuthResponseOK> --->
|
||||
<cfif lcase(xmlObject.xmlRoot.xmlName) EQ lcase("CheckAuthResponseOK")>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- boolean test to see if the check transaction failed --->
|
||||
<cffunction name="isCheckAuthError" output="false" access="private" returntype="boolean">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
<!--- first format looks like:
|
||||
<CheckAuthResponseError>
|
||||
<AVSResponse>string</AVSResponse>
|
||||
<ErrorMessage>string</ErrorMessage>
|
||||
<EquifaxResponse>string</EquifaxResponse>
|
||||
<InternalId>number</InternalId>
|
||||
<PreviousPayment>string</PreviousPayment>
|
||||
<ProcessorTransactionId>string</ProcessorTransactionId>
|
||||
<RequiredText>string</RequiredText>
|
||||
<Score>number</Score>
|
||||
</CheckAuthResponseError>
|
||||
|
||||
or
|
||||
|
||||
<TransactionResponseFail>
|
||||
<ErrorCategory>text</ErrorCategory>
|
||||
<ErrorCode>text</ErrorCode>
|
||||
<ErrorMessage>text</ErrorMessage>
|
||||
<InternalId>text</InternalId>
|
||||
</TransactionResponseFail>
|
||||
|
||||
<cfswitch expression="#xmlObject.xmlNode.ErrorMessage#">
|
||||
<cftry value="EXPIRED CARD">
|
||||
Expired Card
|
||||
</cftry>
|
||||
...
|
||||
<cftry value="REQ. EXCEEDS BALANCE">
|
||||
Request exceeds available balance o ncard
|
||||
</cftry>
|
||||
<cfdefaultcase>
|
||||
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
--->
|
||||
|
||||
<!--- see if the response object has an error root node: <CardAuthResponseError> --->
|
||||
<cfif lcase(xmlObject.xmlRoot.xmlName) EQ lcase("CheckAuthResponseError")>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- return a string message for the cause of the error --->
|
||||
<cffunction name="getCheckAuthError" output="false" access="private" returntype="string">
|
||||
<cfargument name="xmlObject" type="any" required="true" />
|
||||
|
||||
<cfset var msg = "" />
|
||||
<!--- first format looks like:
|
||||
<CheckAuthResponseError>
|
||||
<AVSResponse>string</AVSResponse>
|
||||
<ErrorMessage>string</ErrorMessage>
|
||||
<EquifaxResponse>string</EquifaxResponse>
|
||||
<InternalId>number</InternalId>
|
||||
<PreviousPayment>string</PreviousPayment>
|
||||
<ProcessorTransactionId>string</ProcessorTransactionId>
|
||||
<RequiredText>string</RequiredText>
|
||||
<Score>number</Score>
|
||||
</CheckAuthResponseError>
|
||||
--->
|
||||
<cfif IsDefined("xmlObject.xmlRoot.ErrorMessage.xmlText")>
|
||||
<cfswitch expression="#xmlObject.xmlRoot.ErrorMessage.xmlText#">
|
||||
<cfcase value="PLEASE RETRY">
|
||||
<!--- if this occurs, we should retry the transaction ourselves and not harass the user --->
|
||||
<cfset msg = "There was a temporary error processing your card with the bank. Please retry the transaction." />
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfset msg = "Your check was declined by the bank because: #xmlObject.xmlRoot.ErrorMessage.xmlText#. Please try again or try using a credit card." />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
<cfelse>
|
||||
<cfset msg = "No error description found. Please contact the administrators for help. The error object is: #toString(xmlObject)#" />
|
||||
</cfif>
|
||||
|
||||
<!--- return msg --->
|
||||
<cfreturn msg />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
287
cfpayment/api/gateway/itransact/tests/ItransactTest.cfc
Normal file
287
cfpayment/api/gateway/itransact/tests/ItransactTest.cfc
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
<cfcomponent name="ItransactTest" extends="mxunit.framework.TestCase" output="false">
|
||||
|
||||
<cffunction name="setUp" returntype="void" access="public" output="false">
|
||||
|
||||
<cfset var gw = structNew() />
|
||||
|
||||
<cfscript>
|
||||
variables.svc = createObject("component", "cfpayment.api.core");
|
||||
|
||||
gw.path = "itransact.itransact_cc";
|
||||
// THESE TEST CREDENTIALS ARE PROVIDED AS A COURTESY BY ITRANSACT TO THE CFPAYMENT PROJECT
|
||||
// THERE IS NO GUARANTEE THEY WILL REMAIN ACTIVE
|
||||
// CONTACT SUPPORT@ITRANSACT.COM FOR YOUR OWN TEST ACCOUNT
|
||||
gw.MerchantAccount = 375;
|
||||
gw.Username = 'externalTest';
|
||||
gw.Password = 'externalTest123';
|
||||
gw.TestMode = true; // defaults to true anyways
|
||||
|
||||
// create gw and get reference
|
||||
variables.svc.init(gw);
|
||||
variables.gw = variables.svc.getGateway();
|
||||
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testAuthorizeOnly" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset account.setAccount(5454545454545454) />
|
||||
<cfset account.setMonth(12) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue(123) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("236 N. Santa Cruz Ave") />
|
||||
<cfset account.setPostalCode("95030") />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<!--- do some debugging --->
|
||||
<cfset debug("Endpoint: " & gw.getGatewayURL()) />
|
||||
|
||||
<!--- 5454 card will result in an error for bogus gateway --->
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testAuthorizeThenCaptureThenReport" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var report = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset account.setAccount(5454545454545454) />
|
||||
<cfset account.setMonth(12) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue(123) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("236 N. Santa Cruz Ave") />
|
||||
<cfset account.setPostalCode("95030") />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<!--- do some debugging --->
|
||||
<cfset debug("Endpoint: " & gw.getGatewayURL()) />
|
||||
|
||||
<!--- 5454 card will result in an error for bogus gateway --->
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<!--- cfset debug(response.getMemento()) / --->
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed") />
|
||||
|
||||
<!--- now try to settle it --->
|
||||
<cfset options.InternalId = response.getTransactionId() />
|
||||
|
||||
<!--- itransact doesn't actually use the authorization value, which I think is an anomaly --->
|
||||
<cfset response = gw.capture(money = money, authorization = response.getAuthorization(), options = options) />
|
||||
<!--- cfset debug(response.getMemento()) / --->
|
||||
<cfset assertTrue(response.getSuccess(), "The capture did not succeed") />
|
||||
|
||||
<!--- now run a detail report on this transaction --->
|
||||
<cfset report = gw.status(transactionid = response.getTransactionID()) />
|
||||
<cfset assertTrue(report.getSuccess() AND NOT report.hasError(), "Successful transactionid should have success = true") />
|
||||
|
||||
<!--- try getting detail with externalid --->
|
||||
<cfset report = gw.status(options = options) />
|
||||
<cfset assertTrue(report.getSuccess() AND NOT report.hasError(), "Successful externalid should have success = true") />
|
||||
|
||||
<!--- pass an invalid id to see how error is handled --->
|
||||
<cfset report = gw.status(transactionid = "123456") />
|
||||
<cfset assertTrue(report.hasError(), "Invalid transactionid should result in ReportResponseFail") />
|
||||
<cfset debug(report.getMemento()) />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testAuthorizeThenVoid" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset account.setAccount(5454545454545454) />
|
||||
<cfset account.setMonth(12) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue(123) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("236 N. Santa Cruz Ave") />
|
||||
<cfset account.setPostalCode("95030") />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<!--- do some debugging --->
|
||||
<cfset debug("Endpoint: " & gw.getGatewayURL()) />
|
||||
|
||||
<!--- 5454 card will result in an error for bogus gateway --->
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed") />
|
||||
|
||||
<!--- now try to void it --->
|
||||
<!--- itransact doesn't actually use the authorization value, which I think is an anomaly --->
|
||||
<cfset response = gw.void(transactionid = response.getTransactionID(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "You cannot void a preauth") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseThenVoidThenReport" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset var money = variables.svc.createMoney(10000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var id = "" />
|
||||
<cfset var report = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset account.setAccount(5454545454545454) />
|
||||
<cfset account.setMonth(12) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue(123) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("236 N. Santa Cruz Ave") />
|
||||
<cfset account.setPostalCode("95030") />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<!--- do some debugging --->
|
||||
<cfset debug("Endpoint: " & gw.getGatewayURL()) />
|
||||
|
||||
<!--- 5454 card will result in an error for bogus gateway --->
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset id = response.getTransactionID() />
|
||||
<cfset assertTrue(response.getSuccess(), "The purchase did not succeed") />
|
||||
|
||||
<!--- now try to void transaction --->
|
||||
<cfset response = gw.void(transactionid = response.getTransactionID(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The void did not succeed") />
|
||||
|
||||
<!--- now run a detail report on original transaction and void --->
|
||||
<cfset report = gw.status(transactionid = id) />
|
||||
<cfset debug(report.getMemento()) />
|
||||
<cfset assertTrue(report.getSuccess() AND NOT report.hasError(), "Being the original response, this should be successful even if since voided") />
|
||||
|
||||
<cfset report = gw.status(transactionid = response.getTransactionID()) />
|
||||
<cfset debug(report.getMemento()) />
|
||||
<cfset assertTrue(report.getSuccess() AND NOT report.hasError(), "A successful response means the void was successfully applied") />
|
||||
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseThenCredit" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset var money = variables.svc.createMoney(10000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset account.setAccount(5454545454545454) />
|
||||
<cfset account.setMonth(12) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue(123) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("236 N. Santa Cruz Ave") />
|
||||
<cfset account.setPostalCode("95030") />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<!--- do some debugging --->
|
||||
<cfset debug("Endpoint: " & gw.getGatewayURL()) />
|
||||
|
||||
<!--- 5454 card will result in an error for bogus gateway --->
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The purchase did not succeed") />
|
||||
|
||||
<!--- now try to credit more than we charged
|
||||
this apparently varies based upon the merchant bank so in test mode, itransact does not validate this and returns OK
|
||||
<cfset money.setCents(15000) />
|
||||
<cfset response = gw.credit(money = money, transactionid = response.getTransactionID(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "Credits can't exceed original charge value") />
|
||||
--->
|
||||
|
||||
<!--- now perform partial credit --->
|
||||
<cfset money.setCents(5000) />
|
||||
<cfset response = gw.credit(money = money, transactionid = response.getTransactionID(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "Partial credit did not succeed") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testSettle" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<cfset response = gw.settle(options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The settlement did not succeed") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testInvalidPurchases" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var account = variables.svc.createCreditCard() />
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset account.setAccount(5454545454545451) />
|
||||
<cfset account.setMonth(12) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setVerificationValue(123) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("236 N. Santa Cruz Ave") />
|
||||
<cfset account.setPostalCode("95030") />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<!--- 5451 card will result in an error --->
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "The purchase did not fail with invalid CC") />
|
||||
|
||||
<cfset account.setAccount(5454545454545454) />
|
||||
|
||||
<!--- try invalid expiration --->
|
||||
<cfset account.setMonth(13) />
|
||||
<cfset account.setYear(year(now()) + 1) />
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "The purchase did not fail with invalid expiration date") />
|
||||
|
||||
<!--- try expired card --->
|
||||
<cfset account.setMonth(5) />
|
||||
<cfset account.setYear(year(now()) - 1) />
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "iTransact gateway does not validate the expiration date so test gateway won't throw error; it is the acquiring bank's responsibility to validate/enforce it") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
167
cfpayment/api/gateway/itransact/tests/ItransactTestEFT.cfc
Normal file
167
cfpayment/api/gateway/itransact/tests/ItransactTestEFT.cfc
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
<cfcomponent name="ItransactTest" extends="mxunit.framework.TestCase" output="false">
|
||||
|
||||
<cffunction name="setUp" returntype="void" access="public" output="false">
|
||||
|
||||
<cfset var gw = structNew() />
|
||||
|
||||
<cfscript>
|
||||
variables.svc = createObject("component", "cfpayment.api.core");
|
||||
|
||||
gw.path = "itransact.itransact_eft";
|
||||
// THESE TEST CREDENTIALS ARE PROVIDED AS A COURTESY BY ITRANSACT TO THE CFPAYMENT PROJECT
|
||||
// THERE IS NO GUARANTEE THEY WILL REMAIN ACTIVE
|
||||
// CONTACT SUPPORT@ITRANSACT.COM FOR YOUR OWN TEST ACCOUNT
|
||||
gw.MerchantAccount = 376;
|
||||
gw.Username = 'externalTest';
|
||||
gw.Password = 'externalTest123';
|
||||
gw.TestMode = true; // defaults to true anyways
|
||||
|
||||
// create gw and get reference
|
||||
variables.svc.init(gw);
|
||||
variables.gw = variables.svc.getGateway();
|
||||
|
||||
// create eft to use
|
||||
account = variables.svc.createEFT();
|
||||
account.setAccount("12345-12345");
|
||||
account.setRoutingNumber("222371863");
|
||||
account.setFirstName("John");
|
||||
account.setLastName("Doe");
|
||||
account.setAddress("236 N. Santa Cruz Ave");
|
||||
account.setPostalCode("95030");
|
||||
account.setPhoneNumber("415-555-1212");
|
||||
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- confirm authorize throws error --->
|
||||
<cffunction name="testAuthorizeThrowsException" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<!--- authorize will throw an error for e-check --->
|
||||
<cftry>
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset assertTrue(false, "EFT authorize() should fail but did not") />
|
||||
<cfcatch type="cfpayment.MethodNotImplemented">
|
||||
<cfset assertTrue(true, "EFT authorize() threw cfpayment.MethodNotImplemented") />
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseThenVoid" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var money = variables.svc.createMoney(10000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<!--- validate object --->
|
||||
<cfset assertTrue(account.getIsValid(), "EFT is not valid") />
|
||||
|
||||
<!--- first try to purchase --->
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The purchase did not succeed") />
|
||||
|
||||
<!--- then try to void transaction --->
|
||||
<cfset response = gw.void(transactionid = response.getTransactionID(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The void did not succeed") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseThenCredit" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<!--- first try to purchase --->
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The purchase did not succeed") />
|
||||
|
||||
<!--- now try to credit more than we charged --->
|
||||
<cfset money.setCents(15000) />
|
||||
<cfset response = gw.credit(money = money, transactionid = response.getTransactionID(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "Credits can't exceed original charge value") />
|
||||
|
||||
<!--- now perform partial credit --->
|
||||
<cfset money.setCents(5000) />
|
||||
<cfset response = gw.credit(money = money, transactionid = response.getTransactionID(), options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "Partial credit did not succeed") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testSettle" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<cfset response = gw.settle(options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "EFTs do not accept a direct settlement request; it is implicit") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!---
|
||||
<cffunction name="testInvalidPurchases" access="public" returntype="void" output="false">
|
||||
|
||||
<cfset var cc = variables.svc.createCreditCard() />
|
||||
<cfset var money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset var response = "" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset cc.setAccount(5454545454545451) />
|
||||
<cfset cc.setMonth(12) />
|
||||
<cfset cc.setYear(year(now())+1) />
|
||||
<cfset cc.setVerificationValue(123) />
|
||||
<cfset cc.setFirstName("John") />
|
||||
<cfset cc.setLastName("Doe") />
|
||||
<cfset cc.setAddress("236 N. Santa Cruz Ave") />
|
||||
<cfset cc.setPostalCode("95030") />
|
||||
|
||||
<cfset options.ExternalID = createUUID() />
|
||||
|
||||
<!--- 5451 card will result in an error --->
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "The purchase did not fail with invalid CC") />
|
||||
|
||||
<cfset cc.setAccount(5454545454545454) />
|
||||
|
||||
<!--- try invalid expiration --->
|
||||
<cfset cc.setMonth(13) />
|
||||
<cfset cc.setYear(year(now()) + 1) />
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "The purchase did not fail with invalid expiration date") />
|
||||
|
||||
<!--- try expired card --->
|
||||
<cfset cc.setMonth(5) />
|
||||
<cfset cc.setYear(year(now()) - 1) />
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "The purchase did not fail with expired card") />
|
||||
|
||||
</cffunction>
|
||||
--->
|
||||
|
||||
</cfcomponent>
|
||||
144
cfpayment/api/gateway/merchantware/MerchantWareRequest.cfc
Normal file
144
cfpayment/api/gateway/merchantware/MerchantWareRequest.cfc
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is an implementation of Cayan MerchantWare API.
|
||||
See:
|
||||
https://ps1.merchantware.net/Merchantware/ws/RetailTransaction/v4/Credit.asmx
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
component {
|
||||
|
||||
variables.validTransactions = "SaleKeyed,Sale";
|
||||
|
||||
public Array function createPayload(String required requestType, Any required merchantAuthentication, Any required money, Any account, Any transactionId, Any customer, Struct options={}){
|
||||
|
||||
var ret = [];
|
||||
if(!isValidTransactionType(requestType)){
|
||||
throw(type="cfpayment.UnknownTransactionType", message="transactionType, #requestType# is not known");
|
||||
}
|
||||
|
||||
// if(!structKeyExists(options, "ipaddress")){
|
||||
// options["ipaddress"]=CGI.remote_addr;
|
||||
// }
|
||||
|
||||
var ret = [];
|
||||
|
||||
|
||||
|
||||
|
||||
addKey(ret, "merchantName", merchantAuthentication.merchantName);
|
||||
addKey(ret, "merchantSiteId", merchantAuthentication.merchantSiteId);
|
||||
addKey(ret, "merchantKey", merchantAuthentication.merchantKey);
|
||||
addKey(ret, "invoiceNumber", options.invoiceNumber?:"");
|
||||
if(!isNull(transactionid)){
|
||||
addKey(ret, "transactionid", transactionId);
|
||||
}
|
||||
if(!isNull(money)){
|
||||
addKey(ret, "amount",Trim(money.getAmount()));
|
||||
//addKey(ret, "currency",money.getCurrency());
|
||||
}
|
||||
|
||||
|
||||
if(!isNull(account)){
|
||||
addKey(ret, "cardNumber",account.getAccount());
|
||||
addKey(ret, "expirationDate",DateFormat(account.getExpirationDate(), "MMYY"));
|
||||
|
||||
addKey(ret, "cardholder", account.getFirstName() & " " & account.getLastName());
|
||||
|
||||
//addKey(ret, "company", account.getcompany());
|
||||
addKey(ret, "avsStreetAddress", account.getaddress());
|
||||
// //addKey(ret, "address2", account.getaddress2());
|
||||
// addKey(ret, "city", account.getcity());
|
||||
// addKey(ret, "state", account.getRegion());
|
||||
|
||||
addKey(ret, "avsStreetZipCode", account.getPostalCode());
|
||||
// addKey(ret, "country", account.getcountry());
|
||||
|
||||
addKey(ret, "cardSecurityCode",account.getVerificationValue());
|
||||
}
|
||||
|
||||
addKey(ret, "forceDuplicate", options.forceDuplicate?:true);
|
||||
addKey(ret, "registerNumber", options.registerNumber?:"");
|
||||
addKey(ret, "merchantTransactionId", options.merchantTransactionId?:"");
|
||||
|
||||
// if(!isNull(customer)){
|
||||
// var customer = customer.getMemento();
|
||||
|
||||
|
||||
|
||||
// for(var k in customer){
|
||||
|
||||
// if(k EQ "address" && !isNull(customer[k])){
|
||||
// var address = customer[k];
|
||||
|
||||
// addKey(ret, "firs_tname", address.getFirstName());
|
||||
// addKey(ret, "last_name", address.getLastName());
|
||||
// addKey(ret, "company", address.getcompany());
|
||||
// addKey(ret, "address1", address.getaddress());
|
||||
// addKey(ret, "address2", address.getAddress2());
|
||||
// addKey(ret, "city", address.getCity());
|
||||
// addKey(ret, "state", address.getState());
|
||||
// addKey(ret, "zip", address.getZip());
|
||||
// addKey(ret, "country", address.getcountry());
|
||||
// addKey(ret, "phone", address.getphoneNumber());
|
||||
// addKey(ret, "fax", address.getphoneNumber());
|
||||
// addKey(ret, "email", address.getEmail());
|
||||
// }
|
||||
// else if(k EQ "shippingaddress" && !isNull(customer[k])){
|
||||
// var address = customer[k];
|
||||
// addKey(ret, "shipping_firstname", address.getFirstName());
|
||||
// addKey(ret, "shipping_lastname", address.getLastName());
|
||||
// addKey(ret, "shipping_company", address.getcompany());
|
||||
// addKey(ret, "shipping_address1", address.getaddress());
|
||||
// addKey(ret, "shipping_address2", address.getAddress2());
|
||||
// addKey(ret, "shipping_city", address.getCity());
|
||||
// addKey(ret, "shipping_state", address.getState());
|
||||
// addKey(ret, "shipping_zip", address.getZip());
|
||||
// addKey(ret, "shipping_country", address.getcountry());
|
||||
// addKey(ret, "shipping_phone", address.getphoneNumber());
|
||||
// addKey(ret, "shipping_fax", address.getphoneNumber());
|
||||
// addKey(ret, "shipping_email", address.getEmail());
|
||||
// }
|
||||
|
||||
// //Dont add fields we don't have
|
||||
// else if(!isNull(customer[k])){
|
||||
// addKey(ret, k, customer[k]);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
for(var o in options){
|
||||
addKey(ret, o, options[o]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private boolean function isValidTransactionType(String type){
|
||||
return trueFalseFormat(listFindNoCase(variables.validTransactions, arguments.type));
|
||||
}
|
||||
|
||||
private function addKey(arrayItem, name, value){
|
||||
if(!isNull(value)){
|
||||
arrayItem.append({"name":name, "value":value});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
141
cfpayment/api/gateway/merchantware/MerchantWareResponse.cfc
Normal file
141
cfpayment/api/gateway/merchantware/MerchantWareResponse.cfc
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is an implementation of Cayan MerchantWare API.
|
||||
See:
|
||||
https://ps1.merchantware.net/Merchantware/ws/RetailTransaction/v4/Credit.asmx
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
component accessors=true extends="cfpayment.api.model.response"
|
||||
{
|
||||
|
||||
property name="creditresponse4" setter="true" getter="true";
|
||||
property name="VaultBoardingResponse" setter="true" getter="true";
|
||||
property name="responseType" setter="true" getter="true";
|
||||
property name="requestType" setter="true" getter="true";
|
||||
property name="account" setter="true" getter="true";
|
||||
|
||||
function init(){
|
||||
super.init(argumentCollection=arguments);
|
||||
|
||||
|
||||
|
||||
var res = getParsedResult();
|
||||
var responseType = ListLast(res.getClass().getName(), ".");
|
||||
setResponseType(responseType);
|
||||
|
||||
if(responseType EQ "CreditResponse4"){
|
||||
|
||||
|
||||
setCreditresponse4(res); //Set the main object we get back for any other info.
|
||||
setTokenId(res.getToken());
|
||||
setAuthorization(res.getAuthorizationCode());
|
||||
setAVSCode(res.getAvsResponse());
|
||||
setCVVCode(res.getCvResponse());
|
||||
setMessage(res.getApprovalStatus());
|
||||
setTokenId(res.getToken());
|
||||
setTransactionID(res.getToken());
|
||||
|
||||
if(res.getApprovalStatus() EQ "APPROVED"){
|
||||
setStatus(getService().getStatusSuccessful());
|
||||
}
|
||||
else {
|
||||
setStatus(getService().getStatusFailure());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(responseType EQ "VaultBoardingResponse"){
|
||||
setVaultBoardingResponse(res);
|
||||
setTokenId(res.getVaultToken());
|
||||
setMessage(res.getErrorMessage());
|
||||
|
||||
|
||||
if(Len(res.getErrorCode())){
|
||||
setStatus(getService().getStatusFailure());
|
||||
}
|
||||
else {
|
||||
setStatus(getService().getStatusSuccessful());
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
if(responseType EQ "VaultPaymentInfoResponse"){
|
||||
//create an account if it is correct.
|
||||
|
||||
setMessage(res.getErrorMessage());
|
||||
|
||||
if(Len(res.getErrorCode())){
|
||||
setStatus(getService().getStatusFailure());
|
||||
}
|
||||
else {
|
||||
|
||||
var card = super.getService().createCreditCard();
|
||||
|
||||
|
||||
card.setMonth(Left(res.getExpirationDate(), 2));
|
||||
card.setYear(Right(res.getExpirationDate(), 2));
|
||||
card.setAddress(res.getAvsStreetAddress());
|
||||
card.setPostalCode(res.getAvsZipCode());
|
||||
card.setAccount( res.getCardNumber());
|
||||
|
||||
card.setLastName(ListLast(res.getCardHolder(), " "));
|
||||
var nameLen = ListLen(res.getCardHolder(), " ");
|
||||
var fname = ListDeleteAt(res.getCardHolder(), nameLen, " ");
|
||||
card.setFirstName(fname);
|
||||
setAccount(card)
|
||||
setStatus(getService().getStatusSuccessful());
|
||||
|
||||
}
|
||||
return this;
|
||||
|
||||
|
||||
}
|
||||
|
||||
throw("ResponseType #responseType# doens't have a handler");
|
||||
abort;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
function asString(){
|
||||
|
||||
var resp = getcreditresponse4();
|
||||
var ret = "";
|
||||
ret &= "Token: #resp.getToken()# #Chr(10) & Chr(13)#";
|
||||
ret &= "ErrorMessage: #resp.getErrorMessage()# #Chr(10) & Chr(13)#";
|
||||
ret &= "AvsResponse: #resp.getAvsResponse()# #Chr(10) & Chr(13)#";
|
||||
ret &= "CvResponse: #resp.getCvResponse()# #Chr(10) & Chr(13)#";
|
||||
ret &= "EntryMode: #resp.getEntryMode()# #Chr(10) & Chr(13)#";
|
||||
ret &= "Amount: #resp.getAmount()# #Chr(10) & Chr(13)#";
|
||||
//ret &= "string: #resp.getstring()# #Chr(10) & Chr(13)#";
|
||||
ret &= "TransactionDate: #resp.getTransactionDate()# #Chr(10) & Chr(13)#";
|
||||
ret &= "AuthorizationCode: #resp.getAuthorizationCode()# #Chr(10) & Chr(13)#";
|
||||
ret &= "TransactionType: #resp.getTransactionType()# #Chr(10) & Chr(13)#";
|
||||
ret &= "ExtraData: #resp.getExtraData()# #Chr(10) & Chr(13)#";
|
||||
ret &= "InvoiceNumber: #resp.getInvoiceNumber()# #Chr(10) & Chr(13)#";
|
||||
ret &= "Cardholder: #resp.getCardholder()# #Chr(10) & Chr(13)#";
|
||||
ret &= "CardNumber: #resp.getCardNumber()# #Chr(10) & Chr(13)#";
|
||||
ret &= "CardType: #resp.getCardType()# #Chr(10) & Chr(13)#";
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
553
cfpayment/api/gateway/merchantware/merchantware.cfc
Normal file
553
cfpayment/api/gateway/merchantware/merchantware.cfc
Normal file
|
|
@ -0,0 +1,553 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is an implementation of Cayan MerchantWare API.
|
||||
See:
|
||||
https://ps1.merchantware.net/Merchantware/ws/RetailTransaction/v4/Credit.asmx
|
||||
|
||||
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.
|
||||
*/
|
||||
component
|
||||
extends="cfpayment.api.gateway.base"
|
||||
displayname="Merchantware API Interface"
|
||||
|
||||
{
|
||||
|
||||
variables.cfpayment.GATEWAY_LIVE_URL = "https://ps1.merchantware.net/Merchantware/ws/RetailTransaction/v4/Credit.asmx";
|
||||
|
||||
variables.MerchantWareService = ""; //Needs to be configured at startup
|
||||
|
||||
|
||||
function init(){
|
||||
super.init(argumentCollection=arguments);
|
||||
|
||||
//Create the webservice
|
||||
|
||||
//we require
|
||||
if(!structKeyExists(config, "merchantName")){
|
||||
throw("merchantName is required")
|
||||
}
|
||||
if(!structKeyExists(config, "merchantSiteId")){
|
||||
throw("merchantSiteId is required")
|
||||
}
|
||||
if(!structKeyExists(config, "merchantKey")){
|
||||
throw("merchantKey is required")
|
||||
}
|
||||
|
||||
variables.cfpayment.merchantName = config.merchantName;
|
||||
variables.cfpayment.merchantSiteId = config.merchantSiteId;
|
||||
variables.cfpayment.merchantKey = config.merchantKey;
|
||||
variables.MerchantWareService = createObject("webservice", "#variables.cfpayment.GATEWAY_LIVE_URL#?wsdl");
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
public boolean function hasValidCredentials(){
|
||||
|
||||
//Do the minimum that is required.
|
||||
//Should do a purchase with a test card
|
||||
var expDate = dateAdd("m", randRange(1, 20), Now());
|
||||
var money = getService().createMoney(5000);
|
||||
var account = getService().createCreditCard();
|
||||
account.setAccount("4111111111111111");
|
||||
account.setMonth(Month(expDate));
|
||||
account.setYear(Year(expDate));
|
||||
account.setVerificationValue(900);
|
||||
|
||||
var options = {
|
||||
"refId": getTickCount() //Authorize.net requires a unique order id for each transaction.
|
||||
};
|
||||
|
||||
|
||||
var requestType = "SaleKeyed";
|
||||
var creds = getMerchantAuthentication();
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
invoiceNumber:"",
|
||||
amount:money.getCents(),
|
||||
cardNumber:account.getAccount(),
|
||||
expirationDate:DateFormat(account.getExpirationDate(), "MMYY"),
|
||||
cardholder:account.getName(),
|
||||
avsStreetAddress:account.getAddress(),
|
||||
avsStreetZipCode:account.getPostalCode(),
|
||||
cardSecurityCode:account.getVerificationValue(),
|
||||
forceDuplicate:false,
|
||||
registerNumber:"",
|
||||
merchantTransactionId="",
|
||||
}
|
||||
|
||||
var resp = variables.MerchantWareService.SaleKeyed(argumentCollection=args );
|
||||
|
||||
if(resp.ErrorMessage EQ "Invalid Credentials."){
|
||||
return false;
|
||||
}
|
||||
//There could be other errors but we are ignoring it
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function purchase(required Any money, Any account, Struct options={}){
|
||||
|
||||
//Need to append /SaleKeyed to url
|
||||
var requestType = "SaleKeyed";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
invoiceNumber:"",
|
||||
amount:money.getCents(),
|
||||
cardNumber:account.getAccount(),
|
||||
expirationDate=DateFormat(account.getExpirationDate(), "MMYY"),
|
||||
cardholder=account.getName(),
|
||||
avsStreetAddress=account.getAddress(),
|
||||
avsStreetZipCode=account.getPostalCode(),
|
||||
cardSecurityCode=account.getVerificationValue(),
|
||||
forceDuplicate=getTestMode(),
|
||||
registerNumber=options.registerNumber?:"",
|
||||
merchantTransactionId=options.merchantTransactionId?:""
|
||||
}
|
||||
|
||||
if(StructKeyExists(options,"invoiceNumber")){
|
||||
args["invoiceNumber"]=options.invoiceNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"registerNumber")){
|
||||
args["registerNumber"]=options.registerNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"merchantTransactionId")){
|
||||
args["merchantTransactionId"]=options.merchantTransactionId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var resp = variables.MerchantWareService.SaleKeyed(argumentCollection=args );
|
||||
|
||||
//Raw result
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType": "SaleKeyed"
|
||||
};
|
||||
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
}
|
||||
|
||||
|
||||
function canSwipe(){
|
||||
return true;
|
||||
}
|
||||
function purchaseSwiped(required Any money, required String trackdata, Struct options={}){
|
||||
|
||||
//Need to append /SaleKeyed to url
|
||||
var requestType = "Sale";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
invoiceNumber:"",
|
||||
amount:money.getCents(),
|
||||
trackData:trackData,
|
||||
forceDuplicate:getTestMode(),
|
||||
registerNumber:"",
|
||||
merchantTransactionId:"",
|
||||
entryMode:"MAGNETICSTRIPE"
|
||||
}
|
||||
|
||||
if(StructKeyExists(options,"invoiceNumber")){
|
||||
args["invoiceNumber"]=options.invoiceNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"registerNumber")){
|
||||
args["registerNumber"]=options.registerNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"merchantTransactionId")){
|
||||
args["merchantTransactionId"]=options.merchantTransactionId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var resp = variables.MerchantWareService.Sale(argumentCollection=args );
|
||||
|
||||
//Raw result
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType": "SaleKeyed"
|
||||
};
|
||||
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
}
|
||||
|
||||
function purchaseVault(required money, Any vaultToken, Struct options={}){
|
||||
|
||||
var requestType = "SaleVault";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
invoiceNumber:"",
|
||||
amount:money.getCents(),
|
||||
vaultToken: vaultToken,
|
||||
forceDuplicate=getTestMode(),
|
||||
registerNumber="",
|
||||
merchantTransactionId="",
|
||||
}
|
||||
|
||||
if(StructKeyExists(options,"invoiceNumber")){
|
||||
args["invoiceNumber"]=options.invoiceNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"registerNumber")){
|
||||
args["registerNumber"]=options.registerNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"merchantTransactionId")){
|
||||
args["merchantTransactionId"]=options.merchantTransactionId;
|
||||
}
|
||||
|
||||
|
||||
var resp = variables.MerchantWareService.SaleVault(argumentCollection=args );
|
||||
|
||||
|
||||
//Raw result
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType": "SaleVault"
|
||||
};
|
||||
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
}
|
||||
|
||||
function authorize(Any required money, Any requred account, Struct options={}){
|
||||
|
||||
var requestType = "PreAuthorizationKeyed";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
invoiceNumber:"",
|
||||
amount:money.getCents(),
|
||||
cardNumber:account.getAccount(),
|
||||
expirationDate=DateFormat(account.getExpirationDate(), "MMYY"),
|
||||
cardholder=account.getName(),
|
||||
avsStreetAddress=account.getAddress(),
|
||||
avsStreetZipCode=account.getPostalCode(),
|
||||
cardSecurityCode=account.getVerificationValue(),
|
||||
registerNumber="",
|
||||
merchantTransactionId="",
|
||||
}
|
||||
|
||||
if(StructKeyExists(options,"invoiceNumber")){
|
||||
args["invoiceNumber"]=options.invoiceNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"registerNumber")){
|
||||
args["registerNumber"]=options.registerNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"merchantTransactionId")){
|
||||
args["merchantTransactionId"]=options.merchantTransactionId;
|
||||
}
|
||||
|
||||
var resp = variables.MerchantWareService.PreAuthorizationKeyed(argumentCollection=args );
|
||||
//Raw result
|
||||
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType": "PreAuthorizationKeyed"
|
||||
};
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
}
|
||||
|
||||
function capture(Any required money, String required authorization, Struct options={}){
|
||||
|
||||
var requestType = "PostAuthorization";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
invoiceNumber:"",
|
||||
amount:money.getCents(),
|
||||
token:authorization,
|
||||
registerNumber="",
|
||||
merchantTransactionId="",
|
||||
}
|
||||
|
||||
if(StructKeyExists(options,"invoiceNumber")){
|
||||
args["invoiceNumber"]=options.invoiceNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"registerNumber")){
|
||||
args["registerNumber"]=options.registerNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"merchantTransactionId")){
|
||||
args["merchantTransactionId"]=options.merchantTransactionId;
|
||||
}
|
||||
|
||||
var resp = variables.MerchantWareService.PostAuthorization(argumentCollection=args );
|
||||
//Raw result
|
||||
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType": "PostAuthorization"
|
||||
};
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
}
|
||||
|
||||
public Any function refund(required Any transactionID, required Any money, Struct options={}){
|
||||
|
||||
var requestType = "Refund";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
invoiceNumber:"",
|
||||
overrideAmount:money.getCents(),
|
||||
token:transactionID,
|
||||
registerNumber="",
|
||||
merchantTransactionId="",
|
||||
}
|
||||
|
||||
if(StructKeyExists(options,"invoiceNumber")){
|
||||
args["invoiceNumber"]=options.invoiceNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"registerNumber")){
|
||||
args["registerNumber"]=options.registerNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"merchantTransactionId")){
|
||||
args["merchantTransactionId"]=options.merchantTransactionId;
|
||||
}
|
||||
|
||||
var resp = variables.MerchantWareService.Refund(argumentCollection=args );
|
||||
//Raw result
|
||||
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType": "Refund"
|
||||
};
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
}
|
||||
|
||||
|
||||
function credit(Any required transactionID, Any required money, Struct options={}) {
|
||||
|
||||
throw("Method Not Implemented");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function void(required Any transactionID, Struct options={}) {
|
||||
|
||||
var requestType = "Void";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
|
||||
token:transactionID,
|
||||
registerNumber="",
|
||||
merchantTransactionId="",
|
||||
}
|
||||
|
||||
|
||||
if(StructKeyExists(options,"registerNumber")){
|
||||
args["registerNumber"]=options.registerNumber;
|
||||
}
|
||||
if(StructKeyExists(options,"merchantTransactionId")){
|
||||
args["merchantTransactionId"]=options.merchantTransactionId;
|
||||
}
|
||||
|
||||
var resp = variables.MerchantWareService.Void(argumentCollection=args );
|
||||
//Raw result
|
||||
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType": "Void"
|
||||
};
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
|
||||
}
|
||||
|
||||
function store(String merchantDefinedToken="", required account) {
|
||||
|
||||
var requestType = "VaultBoardCreditKeyed";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
merchantDefinedToken=merchantDefinedToken,
|
||||
cardNumber:account.getAccount(),
|
||||
expirationDate=DateFormat(account.getExpirationDate(), "MMYY"),
|
||||
cardholder=account.getName(),
|
||||
avsStreetAddress=account.getAddress(),
|
||||
avsStreetZipCode=account.getPostalCode(),
|
||||
}
|
||||
|
||||
|
||||
var resp = variables.MerchantWareService.VaultBoardCreditKeyed(argumentCollection=args );
|
||||
//Raw result
|
||||
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType": "Void"
|
||||
};
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
|
||||
}
|
||||
function storeByTransaction(String merchantDefinedToken="", required String referenceNumber) {
|
||||
|
||||
var requestType = "VaultBoardCreditByReference";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
merchantDefinedToken=merchantDefinedToken,
|
||||
referenceNumber:referenceNumber
|
||||
}
|
||||
|
||||
|
||||
var resp = variables.MerchantWareService.VaultBoardCreditByReference(argumentCollection=args );
|
||||
//Raw result
|
||||
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType": "VaultBoardCreditByReference"
|
||||
};
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
|
||||
}
|
||||
|
||||
function unstore(String vaultToken="") {
|
||||
|
||||
var requestType = "VaultDeleteToken";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
vaultToken=vaultToken,
|
||||
}
|
||||
|
||||
|
||||
var resp = variables.MerchantWareService.VaultDeleteToken(argumentCollection=args );
|
||||
//Raw result
|
||||
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType": "VaultDeleteToken"
|
||||
};
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function getCustomer(String merchantDefinedToken="") {
|
||||
|
||||
var requestType = "VaultFindPaymentInfo";
|
||||
var creds = getMerchantAuthentication();
|
||||
|
||||
var args = {
|
||||
merchantName:creds.merchantName,
|
||||
merchantSiteId:creds.merchantSiteId,
|
||||
merchantKey:creds.merchantKey,
|
||||
vaultToken=merchantDefinedToken,
|
||||
}
|
||||
|
||||
|
||||
var resp = variables.MerchantWareService.VaultFindPaymentInfo(argumentCollection=args );
|
||||
//Raw result
|
||||
|
||||
var result = {
|
||||
"parsedResult": resp,
|
||||
"service" : super.getService(),
|
||||
"testmode" : super.getTestMode(),
|
||||
"requestType":requestType
|
||||
};
|
||||
var formattedresponse = new MerchantWareResponse(argumentCollection=result);
|
||||
|
||||
return formattedresponse;
|
||||
|
||||
}
|
||||
|
||||
function getMerchantAuthentication(){
|
||||
|
||||
return {
|
||||
"merchantName" : variables.cfpayment.merchantName,
|
||||
"merchantSiteId" : variables.cfpayment.merchantSiteID,
|
||||
"merchantKey" : variables.cfpayment.merchantKey
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
122
cfpayment/api/gateway/paylinedata/PaylineRequest.cfc
Normal file
122
cfpayment/api/gateway/paylinedata/PaylineRequest.cfc
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
Helper class to genrate all the XML that is required to send to the of the authorize.net API.
|
||||
|
||||
http://developer.authorize.net/api/reference/index.html
|
||||
|
||||
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.
|
||||
*/
|
||||
component
|
||||
accessors="true"
|
||||
|
||||
{
|
||||
|
||||
variables.validTransactions = "sale,auth,capture,refund,void,validate,update,credit,add_customer,update_customer";
|
||||
|
||||
variables.validFields = {
|
||||
"update": "tracking_number,shipping,shipping_postal,ship_from_postal,shipping_country,shipping_carrier,shipping_date,order_description,order_date,customer_receipt,ponumber,summary_commodity_code,duty_amount,discount_amount,tax,national_tax_amount,alternate_tax_amount,alternate_tax_id,vat_tax_amount,vat_tax_rate,vat_invoice_reference_number,customer_vat_registration,merchant_vat_registration"
|
||||
}
|
||||
|
||||
public Array function createPayload(String required requestType, Any required merchantAuthentication, Any required money, Any account, String customer_vault_id, Any transactionId, Any customer, Struct options={}){
|
||||
|
||||
if(!isValidTransactionType(requestType)){
|
||||
throw(type="cfpayment.UnknownTransactionType", message="transactionType, #requestType# is not known");
|
||||
}
|
||||
|
||||
if(!structKeyExists(options, "ipaddress")){
|
||||
options["ipaddress"]=CGI.remote_addr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var ret = [];
|
||||
|
||||
if(ListFindNocase("update_customer,add_customer", requestType)){
|
||||
addKey(ret, "customer_vault", requestType);
|
||||
}
|
||||
else{
|
||||
addKey(ret, "type", requestType);
|
||||
}
|
||||
|
||||
addKey(ret, "username", merchantAuthentication.username);
|
||||
addKey(ret, "password", merchantAuthentication.password);
|
||||
|
||||
if(!isNull(transactionid)){
|
||||
addKey(ret, "transactionid", transactionId);
|
||||
}
|
||||
if(!isNull(money)){
|
||||
addKey(ret, "amount",money.getAmount());
|
||||
addKey(ret, "currency",money.getCurrency());
|
||||
}
|
||||
|
||||
if(!isNull(customer_vault_id)){
|
||||
addKey(ret, "customer_vault_id",customer_vault_id);
|
||||
}
|
||||
|
||||
if(!isNull(account)){
|
||||
addKey(ret, "ccnumber",account.getAccount());
|
||||
addKey(ret, "ccexp",DateFormat(account.getExpirationDate(), "MMYY"));
|
||||
addKey(ret, "cvv",account.getVerificationValue());
|
||||
addKey(ret, "ipaddress",options.ipaddress);
|
||||
addKey(ret, "first_name", account.getFirstName());
|
||||
addKey(ret, "last_name", account.getLastName());
|
||||
addKey(ret, "company", account.getcompany());
|
||||
addKey(ret, "address1", account.getaddress());
|
||||
//addKey(ret, "address2", account.getaddress2());
|
||||
addKey(ret, "city", account.getcity());
|
||||
addKey(ret, "state", account.getRegion());
|
||||
|
||||
addKey(ret, "zip", account.getPostalCode());
|
||||
addKey(ret, "country", account.getcountry());
|
||||
}
|
||||
|
||||
if(!isNull(customer)){
|
||||
var customer = customer.getMemento();
|
||||
|
||||
for(var k in customer){
|
||||
if(!isNull(customer[k])){
|
||||
addKey(ret, k, customer[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(var o in options){
|
||||
addKey(ret, o, options[o]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
private boolean function isValidTransactionType(String type){
|
||||
return trueFalseFormat(listFindNoCase(variables.validTransactions, arguments.type));
|
||||
}
|
||||
|
||||
private function addKey(arrayItem, name, value){
|
||||
if(!isNull(value)){
|
||||
arrayItem.append({"name":name, "value":value});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean function isValidField(string requestType, string field){
|
||||
|
||||
|
||||
//These are also valid
|
||||
//merchant_defined_field_#
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
199
cfpayment/api/gateway/paylinedata/PaylineResponse.cfc
Normal file
199
cfpayment/api/gateway/paylinedata/PaylineResponse.cfc
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is a response from calls to the Payline API
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
component
|
||||
accessors="true"
|
||||
extends="cfpayment.api.model.response"
|
||||
{
|
||||
|
||||
|
||||
property name="orderID" getter="true" setter="true";
|
||||
property name="responseType" type="string" getter="true" setter="true";
|
||||
property name="responseCode" type="numeric" getter="true" setter="true";
|
||||
property name="response" type="numeric" getter="true" setter="true";
|
||||
property name="customerVaultId" type="string" getter="true" setter="true";
|
||||
property name="customer" getter="true" setter="true";
|
||||
|
||||
|
||||
|
||||
function init(){
|
||||
super.init(argumentCollection=arguments);
|
||||
|
||||
|
||||
|
||||
//ResultCodes:
|
||||
// 100 Transaction was approved.
|
||||
// 200 Transaction was declined by processor.
|
||||
// 201 Do not honor.
|
||||
// 202 Insufficient funds.
|
||||
// 203 Over limit.
|
||||
// 204 Transaction not allowed.
|
||||
// 220 Incorrect payment information.
|
||||
// 221 No such card issuer.
|
||||
// 222 No card number on file with issuer.
|
||||
// 223 Expired card.
|
||||
// 224 Invalid expiration date.
|
||||
// 225 Invalid card security code.
|
||||
// 240 Call issuer for further information.
|
||||
// 250 Pick up card.
|
||||
// 251 Lost card.
|
||||
// 252 Stolen card.
|
||||
// 253 Fraudulent card.
|
||||
// 260 Declined with further instructions available. (See response text)
|
||||
// 261 Declined-Stop all recurring payments.
|
||||
// 262 Declined-Stop this recurring program.
|
||||
// 263 Declined-Update cardholder data available.
|
||||
// 264 Declined-Retry in a few days.
|
||||
// 300 Transaction was rejected by gateway.
|
||||
// 400 Transaction error returned by processor.
|
||||
// 410 Invalid merchant configuration.
|
||||
// 411 Merchant account is inactive.
|
||||
// 420 Communication error.
|
||||
// 421 Communication error with issuer.
|
||||
// 430 Duplicate transaction at processor.
|
||||
// 440 Processor format error.
|
||||
// 441 Invalid transaction information.
|
||||
// 460 Processor feature not available.
|
||||
// 461 Unsupported card type.
|
||||
|
||||
if(!hasError()){
|
||||
|
||||
var parsedResult = getResult();
|
||||
|
||||
if(isXML(getResult())){
|
||||
//We have to process this differently
|
||||
parseXMLResponse(getResult());
|
||||
setParsedResult(parsedResult);
|
||||
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
parsedResult = parseResponse(getResult());
|
||||
setParsedResult(parsedResult);
|
||||
setResponseType(parsedResult.type);
|
||||
|
||||
setAuthorization(parsedResult.authcode);
|
||||
setAVSCode(parsedResult.avsresponse);
|
||||
setCVVCode(parsedResult.cvvresponse);
|
||||
setOrderID(parsedResult.orderid);
|
||||
setTransactionID(parsedResult.transactionid);
|
||||
|
||||
setResponseCode(parsedResult.response_code)
|
||||
setResponse(parsedResult.response);
|
||||
setMessage(parsedResult.responsetext);
|
||||
|
||||
if(structKeyExists(parsedResult, "customer_vault_id")){
|
||||
setCustomerVaultId(parsedResult.customer_vault_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(getResponseCode() EQ 100){
|
||||
setStatus(getService().getStatusSuccessful());
|
||||
}
|
||||
else{
|
||||
|
||||
setStatus(getService().getStatusFailure());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private struct function parseResponse(String response){
|
||||
var ret = {};
|
||||
var tuples=listToArray(response, "&", true);
|
||||
for(var t in tuples){
|
||||
var tup = listToArray(t, "=", true);
|
||||
ret[URLDecode(tup[1])] = arrayLen(tup) ==2 ? URLDecode(tup[2]) : "";
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private any function parseXMLResponse(XML response){
|
||||
var resp = XMLParse(response);
|
||||
var ret = {};
|
||||
|
||||
|
||||
|
||||
//This is a customer_vault lookup
|
||||
if(isDefined("resp.nm_response.customer_vault.customer")){
|
||||
var custXML = resp.nm_response.customer_vault.customer;
|
||||
|
||||
//we are getting a customer from the vault, so let's create him,
|
||||
|
||||
setCustomerVaultId(custXML.xmlAttributes.id)
|
||||
setResponseType("customer_vault");
|
||||
setResponseCode(100)
|
||||
setResponse(1);
|
||||
setMessage("Returned customer from customer_vault");
|
||||
|
||||
|
||||
|
||||
|
||||
var inputStruct = {};
|
||||
for(var field in custXML.XMLChildren){
|
||||
|
||||
inputStruct[field.xmlName] = field.XMLText;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
var card = getService().createCreditCard();
|
||||
card.setAccount(custXML.cc_number.XMLText);
|
||||
card.setMonth(Left(custXML.cc_exp.XMLText, 2));
|
||||
card.setYear(Right(custXML.cc_exp.XMLText, 2));
|
||||
card.setIssueNumber(custXML.cc_issue_number.XMLText);
|
||||
|
||||
card.setStartMonth(Left(custXML.cc_start_date.XMLText, 2));
|
||||
card.setStartYear(Right(custXML.cc_start_date.XMLText, 2));
|
||||
|
||||
|
||||
inputStruct.card = card;
|
||||
|
||||
|
||||
var customer = new customer().populate(inputStruct);
|
||||
|
||||
setCustomer(customer);
|
||||
return this;
|
||||
}
|
||||
|
||||
//get the root
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
50
cfpayment/api/gateway/paylinedata/address.cfc
Normal file
50
cfpayment/api/gateway/paylinedata/address.cfc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is an address object that can be used to store billTo addresses etc.
|
||||
|
||||
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.
|
||||
*/
|
||||
component
|
||||
accessors="true"
|
||||
{
|
||||
property name="firstName" type="string" getter="true" setter="true";
|
||||
property name="lastName" type="string" getter="true" setter="true";
|
||||
property name="company" type="string" getter="true" setter="true";
|
||||
property name="address" type="string" getter="true" setter="true";
|
||||
property name="address2" type="string" getter="true" setter="true";
|
||||
property name="city" type="string" getter="true" setter="true";
|
||||
property name="state" type="string" getter="true" setter="true";
|
||||
property name="zip" type="string" getter="true" setter="true";
|
||||
property name="country" type="string" getter="true" setter="true";
|
||||
property name="phoneNumber" type="string" getter="true" setter="true";
|
||||
property name="email" type="string" getter="true" setter="true";
|
||||
property name="faxNumber" type="string" getter="true" setter="true";
|
||||
property name="cellPhoneNumber" type="string" getter="true" setter="true";
|
||||
property name="website" type="string" getter="true" setter="true";
|
||||
|
||||
|
||||
public Struct function getMemento(){
|
||||
|
||||
var ret = {};
|
||||
var proparr = getMetadata(this).properties;
|
||||
|
||||
for(var prop in proparr){
|
||||
|
||||
ret[prop.name] = prop.getter? this["get#prop.name#"]() : variables[prop.name];
|
||||
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
260
cfpayment/api/gateway/paylinedata/customer.cfc
Normal file
260
cfpayment/api/gateway/paylinedata/customer.cfc
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is a customer that can be loaded and saved to the authorize.net system
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
component accessors="true"
|
||||
{
|
||||
|
||||
|
||||
//These properties are named in the same format so we can use the getMemento to create our sending packet
|
||||
|
||||
property name="customerVaultId" getter="true" setter="true";
|
||||
|
||||
property name="card" getter="true" setter="true";
|
||||
|
||||
//Billing Info
|
||||
property name="billingId" type="string" getter="true" setter="true";
|
||||
property name="firstName" type="string" getter="true" setter="true";
|
||||
property name="lastName" type="string" getter="true" setter="true";
|
||||
property name="company" type="string" getter="true" setter="true";
|
||||
property name="address" type="string" getter="true" setter="true";
|
||||
property name="address2" type="string" getter="true" setter="true";
|
||||
property name="city" type="string" getter="true" setter="true";
|
||||
property name="state" type="string" getter="true" setter="true";
|
||||
property name="zip" type="string" getter="true" setter="true";
|
||||
property name="country" type="string" getter="true" setter="true";
|
||||
property name="phoneNumber" type="string" getter="true" setter="true";
|
||||
property name="faxNumber" type="string" getter="true" setter="true";
|
||||
property name="email" type="string" getter="true" setter="true";
|
||||
|
||||
|
||||
//Shipping Info
|
||||
property name="shippingId" type="string" getter="true" setter="true";
|
||||
property name="shippingFirstname" type="string" getter="true" setter="true";
|
||||
property name="shippingLastname" type="string" getter="true" setter="true";
|
||||
property name="shippingCompany" type="string" getter="true" setter="true";
|
||||
property name="shippingAddress" type="string" getter="true" setter="true";
|
||||
property name="shippingAddress2" type="string" getter="true" setter="true";
|
||||
property name="shippingCity" type="string" getter="true" setter="true";
|
||||
property name="shippingState" type="string" getter="true" setter="true";
|
||||
property name="shippingZip" type="string" getter="true" setter="true";
|
||||
property name="shippingCountry" type="string" getter="true" setter="true";
|
||||
property name="shippingPhoneNumber" type="string" getter="true" setter="true";
|
||||
property name="shippingFaxNumber" type="string" getter="true" setter="true";
|
||||
property name="shippingEmail" type="string" getter="true" setter="true";
|
||||
//property name="processor_id" getter="true" setter="true";
|
||||
|
||||
|
||||
property name="payment" getter="true" setter="true" default="creditcard";
|
||||
property name="orderid" getter="true" setter="true";
|
||||
property name="orderDescription" getter="true" setter="true";
|
||||
|
||||
|
||||
//Should be an array
|
||||
property name="merchantDefinedField1" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField2" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField3" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField4" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField5" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField6" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField7" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField8" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField9" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField10" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField11" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField12" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField13" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField14" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField15" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField16" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField17" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField18" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField19" type="string" getter="true" setter="true";
|
||||
property name="merchantDefinedField20" type="string" getter="true" setter="true";
|
||||
|
||||
//returned fields?
|
||||
property name="shippingCarrier" getter="true" setter="true";
|
||||
property name="shipping" getter="true" setter="true";
|
||||
property name="trackingNumber" getter="true" setter="true";
|
||||
property name="shippingDate" getter="true" setter="true";
|
||||
property name="cc_hash" getter="true" setter="true";
|
||||
property name="cc_bin" getter="true" setter="true";
|
||||
// ponumber****
|
||||
// tax****
|
||||
// tax_exempt****
|
||||
// shipping****
|
||||
|
||||
//Takes a struct of data that comes in and populates the properties
|
||||
public any function populate(struct indata){
|
||||
var funcMapping ={
|
||||
"customer_vault_id" : setCustomerVaultId,
|
||||
"billing_id" : setBillingId,
|
||||
"first_name" : setFirstName,
|
||||
"last_name" : setLastName,
|
||||
"company" : setCompany,
|
||||
"address" : setAddress,
|
||||
"address_1" : setAddress,
|
||||
"address2" : setAddress2,
|
||||
"address_2" : setAddress2,
|
||||
"city" : setCity,
|
||||
"state" : setState,
|
||||
"zip" : setZip,
|
||||
"postal_code" : setZip,
|
||||
"country" : setCountry,
|
||||
"phone_number" : setPhoneNumber,
|
||||
"phone" : setPhoneNumber,
|
||||
"fax_number" : setFaxNumber,
|
||||
"fax" : setFaxNumber,
|
||||
"email" : setEmail,
|
||||
"shipping_id" : setShippingId,
|
||||
"shipping_firstname" : setShippingFirstname,
|
||||
"shipping_first_name" : setShippingFirstname,
|
||||
"shipping_lastname" : setShippingLastname,
|
||||
"shipping_last_name" : setShippingLastname,
|
||||
"shipping_company" : setShippingCompany,
|
||||
"shipping_address" : setShippingAddress,
|
||||
"shipping_address_1" : setShippingAddress,
|
||||
"shipping_address2" : setShippingAddress2,
|
||||
"shipping_address_2" : setShippingAddress2,
|
||||
"shipping_city" : setShippingCity,
|
||||
"shipping_state" : setShippingState,
|
||||
"shipping_zip" : setShippingZip,
|
||||
"shipping_postal_code" : setShippingZip,
|
||||
"shipping_country" : setShippingCountry,
|
||||
"shipping_phone_number" : setShippingPhoneNumber,
|
||||
"shipping_fax_number" : setShippingFaxNumber,
|
||||
"shipping_email" : setShippingEmail,
|
||||
//"processor_id" : setProcessorId,
|
||||
"payment" : setPayment,
|
||||
"orderid" : setOrderid,
|
||||
"order_description" : setOrderDescription,
|
||||
"merchant_defined_field1" : setMerchantDefinedField1,
|
||||
"merchant_defined_field2" : setMerchantDefinedField2,
|
||||
"merchant_defined_field3" : setMerchantDefinedField3,
|
||||
"merchant_defined_field4" : setMerchantDefinedField4,
|
||||
"merchant_defined_field5" : setMerchantDefinedField5,
|
||||
"merchant_defined_field6" : setMerchantDefinedField6,
|
||||
"merchant_defined_field7" : setMerchantDefinedField7,
|
||||
"merchant_defined_field8" : setMerchantDefinedField8,
|
||||
"merchant_defined_field9" : setMerchantDefinedField9,
|
||||
"merchant_defined_field10" : setMerchantDefinedField10,
|
||||
"merchant_defined_field11" : setMerchantDefinedField11,
|
||||
"merchant_defined_field12" : setMerchantDefinedField12,
|
||||
"merchant_defined_field13" : setMerchantDefinedField13,
|
||||
"merchant_defined_field14" : setMerchantDefinedField14,
|
||||
"merchant_defined_field15" : setMerchantDefinedField15,
|
||||
"merchant_defined_field16" : setMerchantDefinedField16,
|
||||
"merchant_defined_field17" : setMerchantDefinedField17,
|
||||
"merchant_defined_field18" : setMerchantDefinedField18,
|
||||
"merchant_defined_field19" : setMerchantDefinedField19,
|
||||
"merchant_defined_field20" : setMerchantDefinedField20,
|
||||
"shipping_carrier" : setShippingCarrier,
|
||||
"shipping" : setShipping,
|
||||
"tracking_number" : setTrackingNumber,
|
||||
"shipping_date" : setShippingDate,
|
||||
"cc_hash" : setCC_hash,
|
||||
"cc_bin" : setCC_bin,
|
||||
};
|
||||
|
||||
|
||||
//These are the keys that are ignored. We can ignore them generally
|
||||
//var ignoredfields = "sec_code,check_name,account_holder_type,customertaxid,check_hash,processor_id,account_type,cc_issue_number,check_aba,check_account,cc_exp,website,cc_start_date,cc_number,cell_phone";
|
||||
for(var st in indata){
|
||||
if(st EQ "card"){
|
||||
//deal with cards differently?
|
||||
setCard(indata[st]);
|
||||
}
|
||||
else if (structKeyExists(funcMapping, st)){
|
||||
funcMapping[st](indata[st]); //Called the mapped function
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
public Struct function getMemento(){
|
||||
var ret = {
|
||||
"customer_vault_id" : getCustomerVaultId(),
|
||||
"billing_id" : getBillingId(),
|
||||
"first_name" : getFirstName(),
|
||||
"last_name" : getLastName(),
|
||||
"company" : getCompany(),
|
||||
"address" : getAddress(),
|
||||
"address2" : getAddress2(),
|
||||
"city" : getCity(),
|
||||
"state" : getState(),
|
||||
"zip" : getZip(),
|
||||
"country" : getCountry(),
|
||||
"phone_number" : getPhoneNumber(),
|
||||
"fax_number" : getFaxNumber(),
|
||||
"email" : getEmail(),
|
||||
"shipping_id" : getShippingId(),
|
||||
"shipping_firstname" : getShippingFirstname(),
|
||||
"shipping_lastname" : getShippingLastname(),
|
||||
"shipping_company" : getShippingCompany(),
|
||||
"shipping_address" : getShippingAddress(),
|
||||
"shipping_address2" : getShippingAddress2(),
|
||||
"shipping_city" : getShippingCity(),
|
||||
"shipping_state" : getShippingState(),
|
||||
"shipping_zip" : getShippingZip(),
|
||||
"shipping_country" : getShippingCountry(),
|
||||
"shipping_phone_number" : getShippingPhoneNumber(),
|
||||
"shipping_fax_number" : getShippingFaxNumber(),
|
||||
"shipping_email" : getShippingEmail(),
|
||||
//"processor_id" : getProcessorId(),
|
||||
"payment" : getPayment(),
|
||||
"orderid" : getOrderid(),
|
||||
"order_description" : getOrderDescription(),
|
||||
"merchant_defined_field1" : getMerchantDefinedField1(),
|
||||
"merchant_defined_field2" : getMerchantDefinedField2(),
|
||||
"merchant_defined_field3" : getMerchantDefinedField3(),
|
||||
"merchant_defined_field4" : getMerchantDefinedField4(),
|
||||
"merchant_defined_field5" : getMerchantDefinedField5(),
|
||||
"merchant_defined_field6" : getMerchantDefinedField6(),
|
||||
"merchant_defined_field7" : getMerchantDefinedField7(),
|
||||
"merchant_defined_field8" : getMerchantDefinedField8(),
|
||||
"merchant_defined_field9" : getMerchantDefinedField9(),
|
||||
"merchant_defined_field10" : getMerchantDefinedField10(),
|
||||
"merchant_defined_field11" : getMerchantDefinedField11(),
|
||||
"merchant_defined_field12" : getMerchantDefinedField12(),
|
||||
"merchant_defined_field13" : getMerchantDefinedField13(),
|
||||
"merchant_defined_field14" : getMerchantDefinedField14(),
|
||||
"merchant_defined_field15" : getMerchantDefinedField15(),
|
||||
"merchant_defined_field16" : getMerchantDefinedField16(),
|
||||
"merchant_defined_field17" : getMerchantDefinedField17(),
|
||||
"merchant_defined_field18" : getMerchantDefinedField18(),
|
||||
"merchant_defined_field19" : getMerchantDefinedField19(),
|
||||
"merchant_defined_field20" : getMerchantDefinedField20(),
|
||||
"shipping_carrier" : getShippingCarrier(),
|
||||
"shipping" : getShipping(),
|
||||
"tracking_number" : getTrackingNumber(),
|
||||
"shipping_date" : getShippingDate(),
|
||||
"cc_hash" : getCC_hash(),
|
||||
"cc_bin" : getCC_bin(),
|
||||
};
|
||||
|
||||
if(!isNull(getCard())) {
|
||||
ret["ccnumber"] = getCard().getAccount();
|
||||
ret["ccexp"] = DateFormat(getCard().getExpirationDate(), "MMYY");
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
483
cfpayment/api/gateway/paylinedata/paylinedata.cfc
Normal file
483
cfpayment/api/gateway/paylinedata/paylinedata.cfc
Normal file
|
|
@ -0,0 +1,483 @@
|
|||
/*
|
||||
Copyright 2016 Mark Drew (http://markdrew.io)
|
||||
|
||||
This is an implementation of paylinedata API.
|
||||
See:
|
||||
https://secure.paylinedatagateway.com/gw/merchants/resources/integration/integration_portal.php#transaction_types
|
||||
|
||||
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.
|
||||
*/
|
||||
component
|
||||
extends="cfpayment.api.gateway.base"
|
||||
displayname="PaylineData API Interface"
|
||||
hint="https://secure.paylinedatagateway.com/gw/merchants/resources/integration/integration_portal.php"
|
||||
{
|
||||
|
||||
variables.cfpayment.GATEWAY_NAME = "PaylineData";
|
||||
variables.cfpayment.GATEWAY_VERSION = "1.0";
|
||||
|
||||
|
||||
//Same endpoint, but different credentials
|
||||
variables.cfpayment.GATEWAY_TEST_URL = "https://secure.paylinedatagateway.com/api/transact.php";
|
||||
variables.cfpayment.GATEWAY_LIVE_URL = "https://secure.paylinedatagateway.com/api/transact.php";
|
||||
|
||||
variables.cfpayment.QUERY_URL = "https://secure.paylinedatagateway.com/api/query.php"
|
||||
|
||||
/**
|
||||
Check that the credentials are correct
|
||||
*/
|
||||
public boolean function hasValidCredentials(){
|
||||
var requestPayload = {
|
||||
requestType="sale",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
}
|
||||
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
var payload = PaylineRequest.createPayload(
|
||||
argumentCollection=requestPayload
|
||||
);
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
|
||||
//If we actually got some kind of result
|
||||
if(result.statuscode NEQ "200"){
|
||||
return false;
|
||||
}
|
||||
var mem = resp.getMemento();
|
||||
if(resp.getMessage() EQ "Authentication Failed"){
|
||||
return false;
|
||||
}
|
||||
//Most other answers could be a "pass?"
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function purchase(required Any money, Any account, String customer_vault_id, Struct options={}){
|
||||
|
||||
var requestPayload = {
|
||||
requestType="sale",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
money=money,
|
||||
options=options
|
||||
}
|
||||
|
||||
if(!IsNull(account)){
|
||||
requestPayload['account'] =account;
|
||||
}
|
||||
|
||||
if(!IsNull(customer_vault_id)){
|
||||
requestPayload['customer_vault_id'] =customer_vault_id;
|
||||
}
|
||||
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
var payload = PaylineRequest.createPayload(
|
||||
argumentCollection=requestPayload
|
||||
);
|
||||
|
||||
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
}
|
||||
|
||||
function canSwipe(){
|
||||
return false;
|
||||
}
|
||||
|
||||
function authorize(Any required money, Any requred account, Struct options={}){
|
||||
|
||||
//create the struct to send:
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
|
||||
|
||||
var payload = PaylineRequest.createPayload(
|
||||
requestType="auth",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
money=money,
|
||||
account=account,
|
||||
options=options
|
||||
);
|
||||
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
}
|
||||
|
||||
function capture(Any required money, String required authorization, Struct options={}){
|
||||
|
||||
options['transactionid'] = authorization;
|
||||
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
var payload = PaylineRequest.createPayload(
|
||||
requestType="capture",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
money=money,
|
||||
options=options
|
||||
);
|
||||
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
}
|
||||
|
||||
function credit(Any required transactionID, Any required money, Struct options={}) {
|
||||
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
var payload = PaylineRequest.createPayload(
|
||||
requestType="credit",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
money=money,
|
||||
transactionId = transactionID,
|
||||
options=options
|
||||
);
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
function refund(Any required transactionID, Any required money, Struct options={}) {
|
||||
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
var payload = PaylineRequest.createPayload(
|
||||
requestType="refund",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
money=money,
|
||||
transactionId = transactionID,
|
||||
options=options
|
||||
);
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function void(Any required transactionID, Struct options={}) {
|
||||
|
||||
options['transactionid'] = transactionID;
|
||||
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
var payload = PaylineRequest.createPayload(
|
||||
requestType="void",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
options=options
|
||||
);
|
||||
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function validate(Any requred account, Struct options={}){
|
||||
|
||||
//create the struct to send:
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
|
||||
|
||||
var payload = PaylineRequest.createPayload(
|
||||
requestType="validate",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
account=account,
|
||||
options=options
|
||||
);
|
||||
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
}
|
||||
|
||||
function update(Any required transactionID, Struct options={}){
|
||||
|
||||
//create the struct to send:
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
|
||||
|
||||
var payload = PaylineRequest.createPayload(
|
||||
requestType="update",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
transactionid=transactionID,
|
||||
options=options
|
||||
);
|
||||
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
}
|
||||
|
||||
function store(required customer){
|
||||
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
|
||||
|
||||
var payload = PaylineRequest.createPayload(
|
||||
requestType="add_customer",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=arguments.customer
|
||||
|
||||
);
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
function unstore(required String customer_vault_id ){
|
||||
var payload = [];
|
||||
var auth = getMerchantAuthentication();
|
||||
|
||||
ArrayAppend(payload, {
|
||||
"name": "customer_vault_id",
|
||||
"value": customer_vault_id
|
||||
});
|
||||
ArrayAppend(payload, {
|
||||
"name": "customer_vault",
|
||||
"value": "delete_customer"
|
||||
});
|
||||
|
||||
|
||||
ArrayAppend(payload, {
|
||||
"name": "username",
|
||||
"value": auth.username
|
||||
});
|
||||
ArrayAppend(payload, {
|
||||
"name": "password",
|
||||
"value": auth.password
|
||||
});
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
function getCustomer(required String customer_vault_id ){
|
||||
|
||||
var payload = [];
|
||||
var auth = getMerchantAuthentication();
|
||||
//We are not doing a full query implementation, so let's just see what it returns.
|
||||
ArrayAppend(payload, {
|
||||
"name": "customer_vault_id",
|
||||
"value": customer_vault_id
|
||||
});
|
||||
ArrayAppend(payload, {
|
||||
"name": "report_type",
|
||||
"value": "customer_vault"
|
||||
});
|
||||
|
||||
ArrayAppend(payload, {
|
||||
"name": "report_type",
|
||||
"value": "customer_vault"
|
||||
});
|
||||
ArrayAppend(payload, {
|
||||
"name": "username",
|
||||
"value": auth.username
|
||||
});
|
||||
ArrayAppend(payload, {
|
||||
"name": "password",
|
||||
"value": auth.password
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload, url=variables.cfpayment.QUERY_URL);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
function updateCustomer(required customer){
|
||||
|
||||
var PaylineRequest = new PaylineRequest(getTestMode());
|
||||
|
||||
|
||||
var payload = PaylineRequest.createPayload(
|
||||
requestType="update_customer",
|
||||
merchantAuthentication=getMerchantAuthentication(),
|
||||
customer=arguments.customer
|
||||
|
||||
);
|
||||
|
||||
//Raw result
|
||||
var result = super.process(payload = payload);
|
||||
result["service"] = super.getService();
|
||||
result["testmode"] = super.getTestMode();
|
||||
|
||||
|
||||
|
||||
var resp = new PaylineResponse(argumentCollection=result);
|
||||
return resp;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//FACTORY METHODS
|
||||
|
||||
public customer function createCustomer(){
|
||||
return new customer(argumentCollection=arguments);
|
||||
}
|
||||
|
||||
public address function createAddress(){
|
||||
return new address(argumentCollection=arguments);
|
||||
}
|
||||
/*
|
||||
Override basic doHTTPCall meethod
|
||||
*/
|
||||
private Struct function doHttpCall(
|
||||
String required url,
|
||||
String method="GET",
|
||||
numeric required timeout,
|
||||
struct headers={},
|
||||
Array payload=[],
|
||||
boolean encoded=true,
|
||||
Struct files={}){
|
||||
|
||||
|
||||
|
||||
var CFHTTP = "";
|
||||
var key = "";
|
||||
var keylist = "";
|
||||
var skey = "";
|
||||
var paramType = "body";
|
||||
|
||||
|
||||
|
||||
var ValidMethodTypes = "URL,GET,POST,PUT,DELETE";
|
||||
if(!listFindNoCase(ValidMethodTypes, arguments.method)){
|
||||
throw(message="Invalid Method",type="cfpayment.InvalidParameter.Method");
|
||||
}
|
||||
|
||||
if(arguments.method EQ "URL"){
|
||||
paramType = "url";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var HTTP = new HTTP(url=arguments.url, method=arguments.method, timeout=arguments.timeout, throwonerror="no");
|
||||
|
||||
for(var h in headers){
|
||||
HTTP.addParam(name=h, value=headers[h], type="header");
|
||||
}
|
||||
|
||||
//The actual array of form attributes
|
||||
for(var p in payload){
|
||||
|
||||
|
||||
HTTP.addParam(name=p.name, value=p.value, type="formField");
|
||||
}
|
||||
|
||||
|
||||
for(var f in files){
|
||||
HTTP.addParam(name=f, file=files[f], type="file");
|
||||
}
|
||||
|
||||
|
||||
var res = HTTP.send();
|
||||
|
||||
return res.getPrefix();
|
||||
}
|
||||
|
||||
|
||||
function getMerchantAuthentication(){
|
||||
return {
|
||||
"username":variables.cfpayment.username,
|
||||
"password": variables.cfpayment.password
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
798
cfpayment/api/gateway/paypal/payflow/payflowGateway.cfc
Normal file
798
cfpayment/api/gateway/paypal/payflow/payflowGateway.cfc
Normal file
|
|
@ -0,0 +1,798 @@
|
|||
<!---
|
||||
Copyright 2012 Andrew Penhorwood (http://www.coldbits.com/)
|
||||
|
||||
Based on nvpgateway.cfc by Joseph Lamoree (http://www.lamoree.com/) & Brian Ghidinelli (http://www.ghidinelli.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.
|
||||
|
||||
Paypal Reference: https://cms.paypal.com/cms_content/US/en_US/files/developer/PayflowGateway_Guide.pdf
|
||||
|
||||
Configuration
|
||||
Partner: provided by PayPal ( partner )
|
||||
MerchantAccount: provided by PayPal ( vendor )
|
||||
Username: provided by PayPal ( username )
|
||||
Password: provided by PayPal ( pwd )
|
||||
CheckAVS: true (default) or false; enforce Address Verification Service checking
|
||||
CheckCVV: true (default) or false; enforce Card Verification Value checking
|
||||
Masking: true (default) or false; Masks account data to comply with PCI DSS
|
||||
--->
|
||||
<cfcomponent extends="cfpayment.api.gateway.base" hint="Name-Value Pair API for Payflow" output="false">
|
||||
|
||||
<!--- cfpayment structure values override base class --->
|
||||
<cfset variables.cfpayment['GATEWAY_NAME'] = "Payflow Gateway via Name-Value Pairs">
|
||||
<cfset variables.cfpayment['GATEWAY_VERSION'] = "1.0">
|
||||
<cfset variables.cfpayment['GATEWAY_TEST_URL'] = "https://pilot-payflowpro.paypal.com">
|
||||
<cfset variables.cfpayment['GATEWAY_LIVE_URL'] = "https://payflowpro.paypal.com">
|
||||
<cfset variables.cfpayment['GATEWAY_REFERENCE'] = "Gateway Developer Guide and Reference - 31-July-2012">
|
||||
<cfset variables.cfpayment['GATEWAY_MASKING'] = true>
|
||||
<cfset variables.cfpayment['GATEWAY_CHECKAVS'] = true>
|
||||
<cfset variables.cfpayment['GATEWAY_CHECKCVV'] = true>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
purchase =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "purchase"
|
||||
access = "public"
|
||||
returntype = "any"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="money" type="any" required="true">
|
||||
<cfargument name="account" type="any" required="true">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#">
|
||||
|
||||
<cfset var payload = structNew()>
|
||||
|
||||
<cfset addCustomer(payload=payload, account=arguments.account, options=arguments.options)>
|
||||
<cfset addCreditCard(payload=payload, account=arguments.account)>
|
||||
<cfset addOptions(payload, arguments.options)>
|
||||
|
||||
<cfset payload['TRXTYPE'] = "S"> <!--- Sale Transaction --->
|
||||
<cfset payload['AMT'] = trim(arguments.money.getAmount())>
|
||||
<cfset payload['CURRENCY'] = arguments.money.getCurrency()>
|
||||
|
||||
<cfreturn process(payload=payload, options=arguments.options)>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
authorize =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "authorize"
|
||||
access = "public"
|
||||
returntype = "any"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="money" type="any" required="true">
|
||||
<cfargument name="account" type="any" required="true">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#">
|
||||
|
||||
<cfset var payload = structNew()>
|
||||
|
||||
<cfset addCustomer(payload=payload, account=arguments.account, options=arguments.options)>
|
||||
<cfset addCreditCard(payload=payload, account=arguments.account)>
|
||||
<cfset addOptions(payload, arguments.options)>
|
||||
|
||||
<cfset payload['TRXTYPE'] = "A"> <!--- Authorization Transaction --->
|
||||
<cfset payload['AMT'] = trim(arguments.money.getAmount())>
|
||||
<cfset payload['CURRENCY'] = arguments.money.getCurrency()>
|
||||
|
||||
<cfreturn process(payload=payload, options=arguments.options)>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
capture =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "capture"
|
||||
access = "public"
|
||||
returntype = "any"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="money" type="any" required="true">
|
||||
<cfargument name="authorization" type="any" required="true">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#">
|
||||
|
||||
<cfset var payload = structNew()>
|
||||
|
||||
<cfset addOptions(payload, arguments.options)>
|
||||
|
||||
<cfset payload['TRXTYPE'] = "D"> <!--- Delayed Capture Transaction --->
|
||||
<cfset payload['origID'] = arguments.authorization>
|
||||
<cfset payload['AMT'] = trim(arguments.money.getAmount())>
|
||||
<cfset payload['CURRENCY'] = arguments.money.getCurrency()>
|
||||
|
||||
<cfreturn process(payload=payload, options=arguments.options)>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
credit =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "credit"
|
||||
access = "public"
|
||||
returntype = "any"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="money" type="any" required="true">
|
||||
<cfargument name="transactionID" type="any" required="true">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#">
|
||||
|
||||
<cfset var payload = structNew()>
|
||||
|
||||
<cfset addOptions(payload, arguments.options)>
|
||||
|
||||
<cfset payload['TRXTYPE'] = "C"> <!--- Credit Transaction --->
|
||||
<cfset payload['origID'] = arguments.transactionID>
|
||||
<cfset payload['AMT'] = trim(arguments.money.getAmount())>
|
||||
<cfset payload['CURRENCY'] = arguments.money.getCurrency()>
|
||||
|
||||
<cfreturn process(payload=payload, options=arguments.options)>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
status =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "status"
|
||||
access = "public"
|
||||
returntype = "any"
|
||||
output = "false"
|
||||
purpose = "Inquiry Transaction by TransactionID. Other types of inquiry transactions are not supported."
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="money" type="any" required="true">
|
||||
<cfargument name="transactionID" type="any" required="true">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#">
|
||||
|
||||
<cfset var payload = structNew()>
|
||||
|
||||
<cfset addOptions(payload, arguments.options)>
|
||||
|
||||
<cfset payload['TRXTYPE'] = "I"> <!--- Inquiry Transaction --->
|
||||
<cfset payload['origID'] = arguments.transactionID>
|
||||
|
||||
<cfreturn process(payload=payload, options=arguments.options)>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
void =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "void"
|
||||
access = "public"
|
||||
returntype = "any"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="transactionID" type="any" required="true">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#">
|
||||
|
||||
<cfset var payload = structNew()>
|
||||
|
||||
<cfset addOptions(payload, arguments.options)>
|
||||
|
||||
<cfset payload['TRXTYPE'] = "V"> <!--- Void Transaction --->
|
||||
<cfset payload['origID'] = arguments.transactionID>
|
||||
|
||||
<cfreturn process(payload=payload, options=arguments.options)>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getIsCCEnabled =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getIsCCEnabled"
|
||||
access = "public"
|
||||
returntype = "boolean"
|
||||
output = "false"
|
||||
purpose = "determine whether or not this gateway can accept credit card transactions"
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/31/2012">
|
||||
|
||||
<cfreturn true>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- ------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
get/set methods -
|
||||
------------------------------------------------------------------------------------------------------------------------------------------- --->
|
||||
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getCheckAVS =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getCheckAVS"
|
||||
access = "public"
|
||||
returntype = "boolean"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfreturn variables.cfpayment.GATEWAY_CHECKAVS>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
setCheckAVS =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "setCheckAVS"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="checkAVS" type="boolean" required="true">
|
||||
|
||||
<cfset variables.cfpayment['GATEWAY_CHECKAVS'] = arguments.checkAVS>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getCheckCVV =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getCheckCVV"
|
||||
access = "public"
|
||||
returntype = "boolean"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfreturn variables.cfpayment.GATEWAY_CHECKCVV>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
setCheckCVV =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "setCheckCVV"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="checkCVV" type="boolean" required="true">
|
||||
|
||||
<cfset variables.cfpayment['GATEWAY_CHECKCVV'] = arguments.checkCVV>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getMasking =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getMasking"
|
||||
access = "public"
|
||||
returntype = "boolean"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfreturn variables.cfpayment.GATEWAY_MASKING>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
setMasking =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "setMasking"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="masking" type="boolean" required="true">
|
||||
|
||||
<cfset variables.cfpayment['GATEWAY_MASKING'] = arguments.masking>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getPartner =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getPartner"
|
||||
access = "public"
|
||||
returntype = "string"
|
||||
output = "false"
|
||||
purpose = "returns the payflow gateway partner value"
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfreturn variables.cfpayment.GATEWAY_PARTNER>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
setPartner =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "setPartner"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="partner" type="string" required="true">
|
||||
|
||||
<cfset variables.cfpayment.GATEWAY_PARTNER = arguments.partner>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- ------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
private internal methods -
|
||||
------------------------------------------------------------------------------------------------------------------------------------------- --->
|
||||
|
||||
|
||||
<!--- =======================================================================================================
|
||||
addCustomer =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "addCustomer"
|
||||
access = "private"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = "populate payload with customer billing information"
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="payload" type="struct" required="true">
|
||||
<cfargument name="account" type="any" required="true">
|
||||
<cfargument name="options" type="struct" required="true">
|
||||
|
||||
<cfset var p = arguments.payload>
|
||||
<cfset var a = arguments.account>
|
||||
<cfset var o = arguments.options>
|
||||
|
||||
<cfset p['BILLTOFIRSTNAME'] = a.getFirstName()>
|
||||
<cfset p['BILLTOLASTNAME'] = a.getLastName()>
|
||||
<cfset p['BILLTOSTREET'] = a.getAddress()>
|
||||
<cfset p['BILLTOCITY'] = a.getCity()>
|
||||
<cfset p['BILLTOSTATE'] = a.getRegion()>
|
||||
<cfset p['BILLTOCOUNTRY'] = a.getCountry()>
|
||||
<cfset p['BILLTOZIP'] = a.getPostalCode()>
|
||||
|
||||
<cfif len(a.getPhoneNumber())>
|
||||
<cfset p['BILLTOPHONENUM'] = a.getPhoneNumber()>
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(o, "email") and len(o.email)>
|
||||
<cfset p['BILLTOEMAIL'] = o.email>
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(o, "company") and len(o.company)>
|
||||
<cfset p['COMPANYNAME'] = o.company>
|
||||
</cfif>
|
||||
|
||||
<!--- enforce use of required AVS name/value pairs --->
|
||||
<cfif getCheckAVS() AND ( len(p.BILLTOSTREET) EQ 0 OR len(p.BILLTOZIP) EQ 0 )>
|
||||
<cfthrow type="cfpayment.Gateway.Error" message="Missing Argument" detail="The of the following arguments are required: BillToStreet and BillToZip">
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
addCreditCard =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "addCreditCard"
|
||||
access = "private"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = "populate payload with credit card information"
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="payload" type="struct" required="true">
|
||||
<cfargument name="account" type="any" required="true">
|
||||
|
||||
<cfset var p = arguments.payload>
|
||||
<cfset var a = arguments.account>
|
||||
<cfset var expMonth = a.getMonth()>
|
||||
<cfset var expYear = right(a.getYear(),2)> <!--- paypal uses 2 digit dates --->
|
||||
|
||||
<cfif len(expMonth) EQ 1>
|
||||
<cfset expMonth = "0" & expMonth>
|
||||
</cfif>
|
||||
|
||||
<cfset p['ACCT'] = a.getAccount()>
|
||||
<cfset p['CVV2'] = a.getVerificationValue()>
|
||||
<cfset p['EXPDATE'] = expMonth & expYear>
|
||||
<cfset p['TENDER'] = "C"> <!--- CreditCard --->
|
||||
|
||||
<!--- enforce use of required Card Verification Value name/value pair --->
|
||||
<cfif getCheckCVV() AND ( len(p.CVV2) EQ 0 )>
|
||||
<cfthrow type="cfpayment.Gateway.Error" message="Missing Argument" detail="The of the following argument is required: Card Verification Value (CVV)">
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
addOptions =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "addOptions"
|
||||
access = "private"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = "populate payload with optional name/value pairs"
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="payload" type="struct" required="true">
|
||||
<cfargument name="options" type="struct" required="true">
|
||||
|
||||
<cfset var p = arguments.payload>
|
||||
<cfset var o = arguments.options>
|
||||
|
||||
<cfif structKeyExists(o, "orderID")>
|
||||
<cfset p['INVNUM'] = o.orderID>
|
||||
<cfset p['comment1'] = o.orderID> <!--- copy orderID into comment1 so it appears on all reports in paypal manager --->
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
addCredentials =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "addCredentials"
|
||||
access = "private"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = "populate payload with paypal manager logon credentials. Normally this is an API only user"
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="payload" type="struct" required="true">
|
||||
|
||||
<cfset var p = arguments.payload>
|
||||
|
||||
<cfset p['PARTNER'] = getPartner()>
|
||||
<cfset p['VENDOR'] = getMerchantAccount()>
|
||||
<cfset p['USER'] = getUsername()>
|
||||
<cfset p['PWD'] = getPassword()>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
addHeaders =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "addHeaders"
|
||||
access = "private"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = "supplies the CFHTTP header name/value pairs used by the gateway."
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="headers" type="struct" required="true">
|
||||
|
||||
<cfset var h = arguments.headers>
|
||||
|
||||
<cfset h['X-VPS-Request-ID'] = createUUID()> <!--- X-VPS-Request-ID is a required http header. Docs say 1-32 characters?? gateway request will not work without it --->
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
addDetailReponses =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "addDetailReponses"
|
||||
access = "private"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="payload" type="struct" required="true">
|
||||
|
||||
<cfset var p = arguments.payload>
|
||||
|
||||
<cfset p['VERBOSITY'] = "HIGH">
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
mask =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "mask"
|
||||
access = "private"
|
||||
returntype = "string"
|
||||
output = "false"
|
||||
purpose = "mask value part of name/value pairs according to industry standard rules"
|
||||
author = "Brian Ghidinelli or Joseph Lamoree modified by Andrew Penhorwood"
|
||||
created = "2008">
|
||||
|
||||
<cfargument name="name" type="string" required="true">
|
||||
<cfargument name="value" type="string" required="true">
|
||||
|
||||
<cfset var n = arguments.name>
|
||||
<cfset var v = arguments.value>
|
||||
<cfset var masked = "">
|
||||
|
||||
<!--- Don't let any exceptions stop the transaction --->
|
||||
<cftry>
|
||||
<cfif (compareNoCase("ACCT", n) EQ 0) AND (len(v) GT 4)>
|
||||
<cfset masked = repeatString("X", len(v) - 4) & right(v, 4)>
|
||||
<cfelseif inList("CVV2,PWD", n)>
|
||||
<cfset masked = repeatString("X", len(v))>
|
||||
<cfelse>
|
||||
<cfset masked = v>
|
||||
</cfif>
|
||||
|
||||
<cfcatch type="any">
|
||||
<!--- Fail without disclosing any data --->
|
||||
<cfset masked = "MaskingException on #n#">
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfreturn masked>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
inList =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "inList"
|
||||
access = "private"
|
||||
returntype = "boolean"
|
||||
output = "no"
|
||||
hint = "looks for an item in a list and returns true if item is present"
|
||||
author = "Andrew Penhorwood"
|
||||
created = "01/14/2010">
|
||||
|
||||
<cfargument name="list" type="string" required="yes">
|
||||
<cfargument name="item" type="string" required="yes">
|
||||
<cfargument name="delimiter" type="string" default=",">
|
||||
<cfargument name="noCase" type="boolean" default="true">
|
||||
|
||||
<cfset var result = false>
|
||||
|
||||
<cfif arguments.noCase>
|
||||
<cfset result = ListFindNoCase(arguments.list, arguments.item, arguments.delimiter) NEQ 0>
|
||||
<cfelse>
|
||||
<cfset result = ListFind(arguments.list, arguments.item, arguments.delimiter) NEQ 0>
|
||||
</cfif>
|
||||
|
||||
<cfreturn result>
|
||||
</cffunction>
|
||||
|
||||
<!--- ------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
response methods -
|
||||
------------------------------------------------------------------------------------------------------------------------------------------- --->
|
||||
|
||||
<!--- =======================================================================================================
|
||||
process =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "process"
|
||||
access = "private"
|
||||
returntype = "any"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="payload" type="struct" required="true">
|
||||
<cfargument name="options" type="struct" required="true">
|
||||
|
||||
<cfset var response = "null">
|
||||
<cfset var results = structNew()>
|
||||
<cfset var headers = structNew()>
|
||||
<cfset var rd = "null">
|
||||
<cfset var n = "">
|
||||
<cfset var cSUCCESS = 0> <!--- pseudo constant --->
|
||||
|
||||
<!---
|
||||
Minimum Requirements for Payflow Gateway:
|
||||
|
||||
The following is the minimum set of NAME/VALUE pairs that must be submitted to the payment gateway for each credit card transaction.
|
||||
|
||||
headers
|
||||
X-VPS-Request-ID - 36 alphanumeric character string - generated automatically
|
||||
|
||||
formfields
|
||||
PARTNER ......... Partner - value provided by Paypal, normally in an email.
|
||||
VENDOR .......... Merchant's Login ID (set by user when signing up for account
|
||||
USER ............ Defined in Paypal Manager (https://manager.paypal.com) for API transactions
|
||||
PWD ............. Defined in Paypal Manager (https://manager.paypal.com) for API transactions
|
||||
|
||||
TRXTYPE ......... Paypal Code - Type of Transaction to perform
|
||||
AMT ............. Amount of Transaction (xxxx.xx format)
|
||||
TENDER .......... Paypal Code - Method of Payment
|
||||
ACCT ............ Credit Card Number
|
||||
EXPDATE ......... Credit Card Expiration date (mmyy)
|
||||
CVVS ............ Credit Card Verification Value (needed for CVV to work, called Card Security Code by Paypal)
|
||||
|
||||
BILLTOSTREET .... Customer Street (needed for AVS to work)
|
||||
BILLTOZIP ....... Customer Postal Code (needed for AVS to work)
|
||||
--->
|
||||
|
||||
<cfset addCredentials(arguments.payload)>
|
||||
<cfset addHeaders(headers)>
|
||||
<cfset addDetailReponses(arguments.payload)>
|
||||
<cfset response = createResponse(argumentCollection = super.process(payload=arguments.payload, headers=headers, encoded="false"))>
|
||||
|
||||
<cfif response.hasError()>
|
||||
<!--- Service did not receive an HTTP response --->
|
||||
<cfset response.setStatus(getService().getStatusUnknown())>
|
||||
<cfelse>
|
||||
<cfset results = parseResponse(response.getResult())>
|
||||
<cfset response.setParsedResult(results)>
|
||||
|
||||
<!--- request declined --->
|
||||
<cfif results.result NEQ cSUCCESS>
|
||||
<cfset response.setStatus(getService().getStatusDeclined())>
|
||||
<cfif structKeyExists(results, "RESPMSG")>
|
||||
<cfset response.setMessage(results.RESPMSG)>
|
||||
</cfif>
|
||||
|
||||
<!--- request successful --->
|
||||
<cfelseif results.result EQ cSUCCESS>
|
||||
<cfset response.setStatus(getService().getStatusSuccessful())>
|
||||
|
||||
<cfif structKeyExists(arguments.payload, "TRXTYPE")>
|
||||
<!--- authorize (Authorization Transaction) & purchase (Sale Transaction) --->
|
||||
<cfif inList("A,S", arguments.payload.TRXTYPE)>
|
||||
<cfif structKeyExists(results, "PNREF")>
|
||||
<cfset response.setTransactionId(results.PNREF)>
|
||||
<cfset response.setAuthorization(results.PNREF)>
|
||||
</cfif>
|
||||
|
||||
<!--- capture (Delayed Capture Transaction) --->
|
||||
<cfelseif inList("D,C,I,V", arguments.payload.TRXTYPE)>
|
||||
<cfif structKeyExists(results, "PNREF")>
|
||||
<cfset response.setTransactionId(results.PNREF)>
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<!--- handle common response fields --->
|
||||
<cfif structKeyExists(results, "RESPMSG")>
|
||||
<cfset response.setMessage(results.RESPMSG)>
|
||||
</cfif>
|
||||
|
||||
<!--- handle Address Verification Service field --->
|
||||
<cfif structKeyExists(results, "PROCAVS")>
|
||||
<cfset response.setAVSCode( normalizeAVSresponse(results.PROCAVS) )>
|
||||
</cfif>
|
||||
|
||||
<!--- handle Card Verification Value field --->
|
||||
<cfif structKeyExists(results, "PROCCVV2")>
|
||||
<cfset response.setCVVCode( normalizeCVVresponse(results.PROCCVV2) )>
|
||||
</cfif>
|
||||
|
||||
<cfelse>
|
||||
<cfset response.setStatus(getService().getStatusFailure())>
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<!--- Mask the request data --->
|
||||
<cfif getMasking()>
|
||||
<cfset rd = response.getRequestData()>
|
||||
<cfif isStruct(rd) AND structKeyExists(rd, "payload")>
|
||||
<cfloop collection="#rd.PAYLOAD#" item="n">
|
||||
<cfset rd.PAYLOAD[n] = mask(n, rd.PAYLOAD[n])>
|
||||
</cfloop>
|
||||
<cfset response.setRequestData(rd)>
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<cfreturn response>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- ------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
response methods -
|
||||
------------------------------------------------------------------------------------------------------------------------------------------- --->
|
||||
|
||||
|
||||
<!--- =======================================================================================================
|
||||
normalizeAVSresponse =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "normalizeAVSresponse"
|
||||
access = "private"
|
||||
returntype = "string"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="paypalCode" type="string" required="true">
|
||||
|
||||
<cfset var code = arguments.paypalCode>
|
||||
|
||||
<!--- possible paypal code that match response.cfc codes A,B,C,D,E,G,N,P,R,S,U,W,X,Y,Z --->
|
||||
|
||||
<!--- codes that don't match response.cfc --->
|
||||
<cfif code EQ "F"> <!--- UK match on address and postal --->
|
||||
<cfset code = "X">
|
||||
|
||||
<cfelseif code EQ "I"> <!--- International Unavaliable --->
|
||||
<cfset code = "G">
|
||||
|
||||
<cfelse> <!--- anything else (all others in paypal docs) --->
|
||||
<cfset code = "E">
|
||||
</cfif>
|
||||
|
||||
<cfreturn code>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
normalizeCVVresponse =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "normalizeCVVresponse"
|
||||
access = "private"
|
||||
returntype = "string"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "08/30/2012">
|
||||
|
||||
<cfargument name="paypalCode" type="string" required="true">
|
||||
|
||||
<cfset var code = arguments.paypalCode>
|
||||
|
||||
<!--- possible paypal code that match response.cfc codes M,N,P --->
|
||||
|
||||
<!--- codes that don't match response.cfc --->
|
||||
<cfif code EQ "X"> <!--- No Response --->
|
||||
<cfset code = "U">
|
||||
|
||||
<cfelse> <!--- anything else (S,U) Service Not Supported,Unavaliable --->
|
||||
<cfset code = "X">
|
||||
</cfif>
|
||||
|
||||
<cfreturn code>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
parseResponse =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "parseResponse"
|
||||
access = "private"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = "parse gateway response into name/value pairs"
|
||||
author = "Joseph Lamoree or Brian Ghidinelli modified by Andrew Penhorwood"
|
||||
created = "2008">
|
||||
|
||||
<cfargument name="data" type="string" required="true">
|
||||
|
||||
<cfset var parsed = structNew()>
|
||||
<cfset var pair = "">
|
||||
<cfset var name = "">
|
||||
<cfset var value = "">
|
||||
|
||||
<cfloop index="pair" list="#arguments.data#" delimiters="&">
|
||||
<cfset name = listFirst(pair, "=")>
|
||||
|
||||
<cfif listLen(pair, "=") GT 2>
|
||||
<cfset value = urlDecode(listRest(pair,"="))>
|
||||
<cfelseif listLen(pair, "=") EQ 2>
|
||||
<cfset value = urlDecode(listLast(pair,"="))>
|
||||
<cfelse>
|
||||
<cfset value = "">
|
||||
</cfif>
|
||||
|
||||
<!--- determine if we need to mask value for display --->
|
||||
<cfif inList("CVV2,PWD,ACCT", name) and getMasking()>
|
||||
<cfset parsed[name] = mask(name, value)>
|
||||
<cfelse>
|
||||
<cfset parsed[name] = value>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfreturn parsed>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
410
cfpayment/api/gateway/paypal/payflow/test/payflowLibrary.cfc
Normal file
410
cfpayment/api/gateway/paypal/payflow/test/payflowLibrary.cfc
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2013 Andrew Penhorwood (http://www.coldbits.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 name="payflowLibrary" output="false">
|
||||
|
||||
<!--- =======================================================================================================
|
||||
init =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "init"
|
||||
access = "public"
|
||||
returntype = "component"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/25/2013">
|
||||
|
||||
<cfset var config = StructNew()>
|
||||
|
||||
<!--- Notes:
|
||||
1. It appears that paypal's service does not like the @ in the password even though Paypal manager allowed me to use that in my password.
|
||||
I could never authenticate until I removed the @.
|
||||
2. You must setup a API user inside of Paypal Manager that accepts API_FULL_TRANSACTIONS. I also setup the IP access just in case.
|
||||
This user is different then the Admin user that you use to access paypal manager.
|
||||
--->
|
||||
|
||||
<!--- BEGIN *** These values MUST be configured according to the info sent to you from Paypal *** --->
|
||||
<cfset config['AcceptedCardTypes'] = "Visa,AmEx,Discover,MasterCard"> <!--- Card Types your account accepts. Possible values: AmEx,AmExCorp,DinersClub,Discover,JCB,MasterCard,Visa --->
|
||||
<cfset config['Partner'] = "">
|
||||
<cfset config['MerchantAccount'] = "">
|
||||
<cfset config['userName'] = "">
|
||||
<cfset config['password'] = "">
|
||||
<!--- END *** These values MUST be configured according to the info sent to you from Paypal *** --->
|
||||
|
||||
<cfset variables['config'] = config>
|
||||
<cfset variables['person'] = genPerson()> <!--- create test person. override data points here if you don't like the default ones --->
|
||||
|
||||
<cfreturn this>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getPerson =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getPerson"
|
||||
access = "public"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/25/2013">
|
||||
|
||||
<cfreturn variables.person>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getAcceptedCardTypes =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getAcceptedCardTypes"
|
||||
access = "public"
|
||||
returntype = "string"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/25/2013">
|
||||
|
||||
<cfreturn variables.config.AcceptedCardTypes>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getPartner =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getPartner"
|
||||
access = "public"
|
||||
returntype = "string"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/25/2013">
|
||||
|
||||
<cfreturn variables.config.Partner>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getMerchantAccount =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getMerchantAccount"
|
||||
access = "public"
|
||||
returntype = "string"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/25/2013">
|
||||
|
||||
<cfreturn variables.config.MerchantAccount>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getUserName =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getUserName"
|
||||
access = "public"
|
||||
returntype = "string"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/25/2013">
|
||||
|
||||
<cfreturn variables.config.userName>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
getPassword =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "getPassword"
|
||||
access = "public"
|
||||
returntype = "string"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/25/2013">
|
||||
|
||||
<cfreturn variables.config.password>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genValidOptions =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genValidOptions"
|
||||
access = "public"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="orderID" type="string" default="1234Order">
|
||||
|
||||
<cfset var options = StructNew()>
|
||||
|
||||
<cfset options['address'] = person.address>
|
||||
<cfset options['email'] = person.email>
|
||||
<cfset options['order_id'] = arguments.orderID>
|
||||
|
||||
<cfreturn options>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genPerson =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genPerson"
|
||||
access = "public"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="FirstName" type="string" default="Fred">
|
||||
<cfargument name="LastName" type="string" default="Flintstone">
|
||||
<cfargument name="domain" type="string" default="bogus.com">
|
||||
|
||||
<!--- if you are wonder this address is for Paypal, Inc --->
|
||||
<cfargument name="phone" type="string" default="402-935-2050">
|
||||
<cfargument name="Address" type="string" default="2211 N 1st St">
|
||||
<cfargument name="City" type="string" default="San Jose">
|
||||
<cfargument name="State" type="string" default="CA">
|
||||
<cfargument name="PostalCode" type="string" default="95131">
|
||||
<cfargument name="Country" type="string" default="USA">
|
||||
|
||||
<cfset var person = StructNew()>
|
||||
|
||||
<cfset person['FirstName'] = arguments.UserFirstName>
|
||||
<cfset person['LastName'] = arguments.LaerFirstName>
|
||||
<cfset person['email'] = person.UserFirstName & "." & person.LaerFirstName & "@" & arguments.domain>
|
||||
|
||||
<cfset person.address = StructNew()>
|
||||
<cfset person.address['phone'] = arguments.phone>
|
||||
<cfset person.address['Address1'] = arguments.Address>
|
||||
<cfset person.address['City'] = arguments.City>
|
||||
<cfset person.address['State'] = arguments.State>
|
||||
<cfset person.address['PostalCode'] = arguments.PostalCode>
|
||||
<cfset person.address['Country'] = arguments.Country>
|
||||
|
||||
<cfreturn person>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genAmount =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genAmount"
|
||||
access = "public"
|
||||
returntype = "numeric"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfset var dollars = RandRange(10,1000,"SHA1PRNG")>
|
||||
<cfset var cents = RandRange(10,99,"SHA1PRNG") / 100>
|
||||
|
||||
<cfreturn dollars + cents>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genCreditCard =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genCreditCard"
|
||||
access = "public"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="svc" type="component" required="yes">
|
||||
<cfargument name="cardtype" type="string" required="no">
|
||||
|
||||
<cfset card = genValidCard(svc)>
|
||||
|
||||
<cfswitch expression="#LCase(arguments.cardtype)#">
|
||||
<cfcase value="AmEx,AmericanExpress,American Express">
|
||||
<cfset card = genAmEx(svc)>
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="AmExCorp,AmericanExpressCorp,American Express Corp">
|
||||
<cfset card = genAmExCorp(svc)>
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="DinersClub,Diners Club">
|
||||
<cfset card = genDinersClub(svc)>
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="Discover">
|
||||
<cfset card = genDiscover(svc)>
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="JCB">
|
||||
<cfset card = genJCB(svc)>
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="MasterCard">
|
||||
<cfset card = genMasterCard(svc)>
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="Visa">
|
||||
<cfset card = genVisa(svc)>
|
||||
</cfcase>
|
||||
</cfswitch>
|
||||
|
||||
<cfreturn card>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genValidCard =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genValidCard"
|
||||
access = "private"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood based on code by Brian Ghidinelli"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="svc" type="component" required="yes">
|
||||
<cfargument name="cardNumber" type="string" default="4111111111111111">
|
||||
|
||||
<!--- these values simulate a valid card with matching avs/cvv --->
|
||||
<cfset var creditcard = svc.createCreditCard()>
|
||||
|
||||
<!--- who --->
|
||||
<cfset creditcard.setFirstName( person.UserFirstName )>
|
||||
<cfset creditcard.setLastName( person.LaerFirstName )>
|
||||
<cfset creditcard.setAddress( person.address.Address1 )>
|
||||
<cfset creditcard.setPostalCode( person.address.Postalcode )>
|
||||
|
||||
<!--- account info --->
|
||||
<cfset creditcard.setAccount( arguments.cardNumber )>
|
||||
<cfset creditcard.setMonth( Month(now()) )>
|
||||
<cfset creditcard.setYear( year(now())+1 )>
|
||||
<cfset creditcard.setVerificationValue(123)>
|
||||
|
||||
<cfreturn creditcard>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genAmEx =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genAmEx"
|
||||
access = "private"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="svc" type="component" required="yes">
|
||||
|
||||
<cfreturn genValidCard(svc, "371449635398431")>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genAmExCorp =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genAmExCorp"
|
||||
access = "private"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="svc" type="component" required="yes">
|
||||
|
||||
<cfreturn genValidCard(svc, "378734493671000")>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genDinersClub =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genDinersClub"
|
||||
access = "private"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="svc" type="component" required="yes">
|
||||
|
||||
<cfreturn genValidCard(svc, "38520000023237")>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genDiscover =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genDiscover"
|
||||
access = "private"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="svc" type="component" required="yes">
|
||||
|
||||
<cfreturn genValidCard(svc, "6011000990139424")>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genJCB =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genJCB"
|
||||
access = "private"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="svc" type="component" required="yes">
|
||||
|
||||
<cfreturn genValidCard(svc, "3566002020360505")>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genMasterCard =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genMasterCard"
|
||||
access = "private"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="svc" type="component" required="yes">
|
||||
|
||||
<cfreturn genValidCard(svc, "5105105105105100")>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
genVisa =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "genVisa"
|
||||
access = "private"
|
||||
returntype = "struct"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="svc" type="component" required="yes">
|
||||
|
||||
<cfreturn genValidCard(svc, "4012888888881881")>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
340
cfpayment/api/gateway/paypal/payflow/test/payflowTest.cfc
Normal file
340
cfpayment/api/gateway/paypal/payflow/test/payflowTest.cfc
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2013 Andrew Penhorwood (http://www.coldbits.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 name="payflowtest" extends="mxunit.framework.TestCase" output="false">
|
||||
|
||||
<!--- =======================================================================================================
|
||||
setUp =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "setUp"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfset var gwParams = "">
|
||||
|
||||
<cfset variables['lib'] = createObject("component", "payflowLibrary").init()>
|
||||
|
||||
<cftry>
|
||||
<!--- create a config that is not in svn --->
|
||||
<cfset gwParams = createObject("component", "cfpayment.localconfig.config").init("developer")>
|
||||
|
||||
<cfcatch>
|
||||
<!--- if gwParams doesn't exist (or otherwise bombs), create a generic structure with blank values --->
|
||||
<cfset gwParams = StructNew() />
|
||||
<cfset gwParams.Path = "paypal.payflow.payflowGateway">
|
||||
|
||||
<!--- Account Information from Paypal. This should be the developer (test) account information. --->
|
||||
<cfset gwParams.Partner = lib.getPartner()>
|
||||
<cfset gwParams.MerchantAccount = lib.getMerchantAccount()>
|
||||
<cfset gwParams.userName = lib.getUserName()>
|
||||
<cfset gwParams.password = lib.getPassword()>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<!--- create global variables --->
|
||||
<cfset variables['svc'] = createObject("component", "cfpayment.api.core").init(gwParams)>
|
||||
<cfset variables['gw'] = svc.getGateway()> <!--- create gw and get reference --->
|
||||
<cfset variables['person'] = lib.getPerson()>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testPurchaseForAllCardTypes =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testPurchaseForAllCardTypes"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfset var AcceptedCardTypes = lib.getAcceptedCardTypes()>
|
||||
<cfset var type = "visa">
|
||||
|
||||
<cfloop index="type" list="#AcceptedCardTypes#">
|
||||
<cfset testPurchase(type)>
|
||||
</cfloop>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testAuthorizeAndCaptureForAllCardTypes =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testAuthorizeAndCaptureForAllCardTypes"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfset var AcceptedCardTypes = lib.getAcceptedCardTypes()>
|
||||
<cfset var type = "visa">
|
||||
|
||||
<cfloop index="type" list="#AcceptedCardTypes#">
|
||||
<cfset testAuthorizeAndCapture(type)>
|
||||
</cfloop>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testCreditForAllCardTypes =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testCreditForAllCardTypes"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfset var AcceptedCardTypes = lib.getAcceptedCardTypes()>
|
||||
<cfset var type = "visa">
|
||||
|
||||
<cfloop index="type" list="#AcceptedCardTypes#">
|
||||
<cfset testCredit(type)>
|
||||
</cfloop>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testStatusForAllCardTypes =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testStatusForAllCardTypes"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfset var AcceptedCardTypes = lib.getAcceptedCardTypes()>
|
||||
<cfset var type = "visa">
|
||||
|
||||
<cfloop index="type" list="#AcceptedCardTypes#">
|
||||
<cfset testStatus(type)>
|
||||
</cfloop>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testVoidForAllCardTypes =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testVoidForAllCardTypes"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfset var AcceptedCardTypes = lib.getAcceptedCardTypes()>
|
||||
<cfset var type = "visa">
|
||||
|
||||
<cfloop index="type" list="#AcceptedCardTypes#">
|
||||
<cfset testVoid(type)>
|
||||
</cfloop>
|
||||
</cffunction>
|
||||
|
||||
<!--- -------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
private test - These are individual test used by the xxxxAllCartType methods. If you want to test just a single method change the access to public -
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------- --->
|
||||
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testPurchase =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testPurchase"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="cardtype" type="string" default="Visa">
|
||||
|
||||
<cfset var amount = lib.genAmount()>
|
||||
<cfset var creditcard = lib.genCreditCard( svc, arguments.cardtype )>
|
||||
<cfset var money = svc.createMoney()>
|
||||
<cfset var options = lib.genValidOptions()>
|
||||
<cfset var result = "">
|
||||
|
||||
<cfset money.init(amount * 100, "USD")><!--- in cents --->
|
||||
|
||||
<cfset response = gw.purchase(money, creditCard, options)>
|
||||
|
||||
<cfset result = response.getParsedResult()>
|
||||
<cfset assertTrue(response.getSuccess(), "The gateway purcahse response not successful for #cardtype#.")>
|
||||
|
||||
<cfset assertTrue( structKeyExists(result, "BillToFirstName") and result.BillToFirstName EQ person.UserFirstName, "The PayPal customer first name should have been #person.UserFirstName#." )>
|
||||
<cfset assertTrue( structKeyExists(result, "BillToLastName") and result.BillToLastName EQ person.LaerFirstName, "The PayPal customer last name should have been #person.LaerFirstName#." )>
|
||||
<cfset assertTrue( structKeyExists(result, "AMT") and result.AMT EQ amount, "The transaction amount should have been #amount#." )>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testAuthorizeAndCapture =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testAuthorizeAndCapture"
|
||||
access = "private"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="cardtype" type="string" default="Visa">
|
||||
|
||||
<cfset var amount = lib.genAmount()>
|
||||
<cfset var creditcard = lib.genCreditCard( svc, arguments.cardtype )>
|
||||
<cfset var money = svc.createMoney()>
|
||||
<cfset var options = lib.genValidOptions()>
|
||||
<cfset var result = "">
|
||||
<cfset var TransactionID = 0>
|
||||
|
||||
<cfset money.init(amount * 100, "USD")><!--- in cents --->
|
||||
|
||||
<!--- Authorization --->
|
||||
<cfset response = gw.authorize(money, creditCard, options)>
|
||||
<cfset assertTrue(response.getSuccess(), "The gateway authorize response not successful for #cardtype#.")>
|
||||
|
||||
<cfset TransactionID = response.getTransactionId()>
|
||||
<cfset assertTrue( Len(TransactionID) GT 0, "The TransactionID not returned by Authorize transaction.")>
|
||||
|
||||
<cfset result = response.getParsedResult()>
|
||||
|
||||
<cfset assertTrue( structKeyExists(result, "BillToFirstName") and result.BillToFirstName EQ person.UserFirstName, "The PayPal customer first name should have been #person.UserFirstName#." )>
|
||||
<cfset assertTrue( structKeyExists(result, "BillToLastName") and result.BillToLastName EQ person.LaerFirstName, "The PayPal customer last name should have been #person.LaerFirstName#." )>
|
||||
<cfset assertTrue( structKeyExists(result, "AMT") and result.AMT EQ amount, "The transaction amount should have been #amount#." )>
|
||||
|
||||
<!--- Capture --->
|
||||
<cfset response = gw.capture(money, TransactionID, options)>
|
||||
<cfset assertTrue( response.getSuccess(), "The gateway capture response not successful for #cardtype# TransactionID: #TransactionID#." )>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testCredit =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testCredit"
|
||||
access = "private"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="cardtype" type="string" default="Visa">
|
||||
|
||||
<cfset var amount = lib.genAmount()>
|
||||
<cfset var creditcard = lib.genCreditCard( svc, arguments.cardtype )>
|
||||
<cfset var money = svc.createMoney()>
|
||||
<cfset var options = lib.genValidOptions()>
|
||||
<cfset var result = "">
|
||||
<cfset var TransactionID = 0>
|
||||
|
||||
<cfset money.init(amount * 100, "USD")><!--- in cents --->
|
||||
|
||||
<!--- purchase --->
|
||||
<cfset response = gw.purchase(money, creditCard, options)>
|
||||
<cfset assertTrue(response.getSuccess(), "The gateway purchase response not successful for #cardtype#.")>
|
||||
|
||||
<cfset result = response.getParsedResult()>
|
||||
<cfset assertTrue( structKeyExists(result, "AMT") and result.AMT EQ amount, "The transaction amount should have been #amount#." )>
|
||||
|
||||
<cfset TransactionID = response.getTransactionId()>
|
||||
|
||||
<!--- credit --->
|
||||
<cfset response = gw.credit(money, TransactionID, options)>
|
||||
<cfset assertTrue( response.getSuccess(), "The gateway credit response not successful for #cardtype# TransactionID: #TransactionID#." )>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testStatus =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testStatus"
|
||||
access = "private"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="cardtype" type="string" default="Visa">
|
||||
|
||||
<cfset var amount = lib.genAmount()>
|
||||
<cfset var creditcard = lib.genCreditCard( svc, arguments.cardtype )>
|
||||
<cfset var money = svc.createMoney()>
|
||||
<cfset var options = lib.genValidOptions()>
|
||||
<cfset var result = "">
|
||||
<cfset var TransactionID = 0>
|
||||
|
||||
<cfset money.init(amount * 100, "USD")><!--- in cents --->
|
||||
|
||||
<!--- Authorization --->
|
||||
<cfset response = gw.authorize(money, creditCard, options)>
|
||||
<cfset assertTrue(response.getSuccess(), "The gateway authorize response not successful for #cardtype#.")>
|
||||
|
||||
<cfset TransactionID = response.getTransactionId()>
|
||||
<cfset assertTrue( Len(TransactionID) GT 0, "The TransactionID not returned by Authorize transaction.")>
|
||||
|
||||
<!--- Status --->
|
||||
<cfset response = gw.status(money, TransactionID, options)>
|
||||
<cfset assertTrue( response.getSuccess(), "The gateway status response not successful for #cardtype# TransactionID: #TransactionID#." )>
|
||||
|
||||
<cfset result = response.getParsedResult()>
|
||||
|
||||
<cfset assertTrue( structKeyExists(result, "FirstName") and result.UserFirstName EQ person.UserFirstName, "The PayPal customer first name should have been #person.UserFirstName#." )>
|
||||
<cfset assertTrue( structKeyExists(result, "LastName") and result.LaerFirstName EQ person.LaerFirstName, "The PayPal customer last name should have been #person.LaerFirstName#." )>
|
||||
<cfset assertTrue( structKeyExists(result, "AMT") and result.AMT EQ amount, "The transaction amount should have been #amount#." )>
|
||||
<cfset assertTrue( structKeyExists(result, "ORIGPNREF") and result.ORIGPNREF EQ TransactionID, "The original transaction ID not returned." )>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testVoid =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testVoid"
|
||||
access = "private"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfargument name="cardtype" type="string" default="Visa">
|
||||
|
||||
<cfset var amount = lib.genAmount()>
|
||||
<cfset var creditcard = lib.genCreditCard( svc, arguments.cardtype )>
|
||||
<cfset var money = svc.createMoney()>
|
||||
<cfset var options = lib.genValidOptions()>
|
||||
<cfset var result = "">
|
||||
<cfset var TransactionID = 0>
|
||||
|
||||
<cfset money.init(amount * 100, "USD")><!--- in cents --->
|
||||
|
||||
<!--- Authorization --->
|
||||
<cfset response = gw.authorize(money, creditCard, options)>
|
||||
<cfset assertTrue(response.getSuccess(), "The gateway authorize response not successful for #cardtype#.")>
|
||||
|
||||
<cfset TransactionID = response.getTransactionId()>
|
||||
<cfset assertTrue( Len(TransactionID) GT 0, "The TransactionID not returned by Authorize transaction.")>
|
||||
|
||||
<!--- Status --->
|
||||
<cfset response = gw.void(TransactionID, options)>
|
||||
<cfset assertTrue( response.getSuccess(), "The gateway status response not successful for #cardtype# TransactionID: #TransactionID#." )>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2013 Andrew Penhorwood (http://www.coldbits.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 name="payflowBasicAccess" extends="mxunit.framework.TestCase" output="false">
|
||||
|
||||
<!--- =======================================================================================================
|
||||
setUp =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "setUp"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfset variables['lib'] = createObject("component", "payflowLibrary").init()>
|
||||
</cffunction>
|
||||
|
||||
<!--- =======================================================================================================
|
||||
testPurchase =
|
||||
================================================================================================== --->
|
||||
<cffunction name = "testGatewayAccess"
|
||||
access = "public"
|
||||
returntype = "void"
|
||||
output = "false"
|
||||
purpose = ""
|
||||
author = "Andrew Penhorwood"
|
||||
created = "06/22/2013">
|
||||
|
||||
<cfset var creditcard = 0>
|
||||
<cfset var gwParams = 0>
|
||||
<cfset var options = 0>
|
||||
<cfset var result = 0>
|
||||
<cfset var money = 0>
|
||||
<cfset var svc = 0>
|
||||
<cfset var gw = 0>
|
||||
<cfset var amount = 56.78>
|
||||
|
||||
<cftry>
|
||||
<!--- create a config that is not in svn --->
|
||||
<cfset gwParams = createObject("component", "cfpayment.localconfig.config").init("developer")>
|
||||
|
||||
<cfcatch>
|
||||
<!--- if gwParams doesn't exist (or otherwise bombs), create a generic structure with blank values --->
|
||||
<cfset gwParams = StructNew() />
|
||||
<cfset gwParams.Path = "paypal.payflow.payflowGateway">
|
||||
|
||||
<!--- Account Information from Paypal. This should be the developer (test) account information. --->
|
||||
<cfset gwParams.Partner = lib.getPartner()>
|
||||
<cfset gwParams.MerchantAccount = lib.getMerchantAccount()>
|
||||
<cfset gwParams.userName = lib.getUserName()>
|
||||
<cfset gwParams.password = "bogusPassword">
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<!--- Failure to Authenticate --->
|
||||
<cfset svc = createObject("component", "cfpayment.api.core").init(gwParams)>
|
||||
<cfset gw = svc.getGateway()> <!--- create gw and get reference --->
|
||||
|
||||
<cfset creditcard = lib.genCreditCard(svc)>
|
||||
<cfset money = svc.createMoney()>
|
||||
<cfset options = lib.genValidOptions()>
|
||||
|
||||
<cfset money.init(amount * 100, "USD")><!--- in cents --->
|
||||
<cfset response = gw.purchase(money, creditCard, options)>
|
||||
|
||||
<cfset result = response.getParsedResult()>
|
||||
<cfset assertTrue( structKeyExists(result, "RESPMSG") and result.RESPMSG EQ "User authentication failed", "Authentication passed but should have failed." )>
|
||||
|
||||
<!--- Authenticate and handle purchase transaction --->
|
||||
<cfset gwParams.password = lib.getPassword()>
|
||||
<cfset svc = createObject("component", "cfpayment.api.core").init(gwParams)>
|
||||
<cfset gw = svc.getGateway()> <!--- create gw and get reference --->
|
||||
|
||||
<!--- create items for a purchase transation --->
|
||||
<cfset creditcard = lib.genCreditCard(svc)>
|
||||
<cfset money = svc.createMoney()>
|
||||
<cfset options = lib.genValidOptions()>
|
||||
|
||||
<cfset money.init(amount * 100, "USD")><!--- in cents --->
|
||||
<cfset response = gw.purchase(money, creditCard, options)>
|
||||
<cfset assertTrue(response.getSuccess(), "The gateway response not successful for #cardtype#.")>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
8
cfpayment/api/gateway/paypal/payflow/test/readme.txt
Normal file
8
cfpayment/api/gateway/paypal/payflow/test/readme.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
You must configure your paypal credentials in payflowLibrary.cfc init method. This is the only place you will need to change any of the values.
|
||||
|
||||
Log into Paypal manager - > Account Administration - > Manager Users
|
||||
|
||||
This page will allow you to see all of the users on that account. The role for the API user but we API_FULL_TRANSACTION. If you don't have
|
||||
a user with that role then you will need to create one back clicking on the "Add User" link.
|
||||
|
||||
Paypal requires you to setup a API user for the gateway.
|
||||
120
cfpayment/api/gateway/paypal/wpp/GatewayException.cfc
Normal file
120
cfpayment/api/gateway/paypal/wpp/GatewayException.cfc
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<!---
|
||||
|
||||
Copyright 2009 Joseph Lamoree (http://www.lamoree.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 output="false">
|
||||
|
||||
<cfset variables.errorInfo = structNew() />
|
||||
|
||||
<cffunction name="init" returntype="GatewayException" access="public" output="false">
|
||||
<cfargument name="exception" type="any" required="false" />
|
||||
<cfargument name="errorCode" type="string" required="false" />
|
||||
<cfargument name="type" type="string" required="false" />
|
||||
<cfargument name="message" type="string" required="false" />
|
||||
<cfargument name="detail" type="string" required="false" />
|
||||
|
||||
<cfif structKeyExists(arguments, "exception")>
|
||||
<cfset setException(arguments.exception) />
|
||||
<cfelseif structKeyExists(arguments, "errorCode")>
|
||||
<cfset setErrorCode(getProperty(arguments, "errorCode")) />
|
||||
<cfelse>
|
||||
<cfset setType(getProperty(arguments, "type")) />
|
||||
<cfset setMessage(getProperty(arguments, "message")) />
|
||||
<cfset setDetail(getProperty(arguments, "detail")) />
|
||||
</cfif>
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="doThrow" returntype="void" access="public" output="false">
|
||||
<cfthrow type="#getType()#" message="#getMessage()#" detail="#getDetail()#" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="setException" returntype="void" access="private" output="false">
|
||||
<cfargument name="exception" type="any" required="true" />
|
||||
|
||||
<cfset var p = getProperty(arguments.exception, "message") />
|
||||
<cfset var n = 0 />
|
||||
|
||||
<cfset variables.exception = arguments.exception />
|
||||
<cfif n gt 0>
|
||||
<cfset setErrorCode(n) />
|
||||
<cfelse>
|
||||
<cfset setType(getProperty(variables.exception, "type")) />
|
||||
<cfset setMessage(getProperty(variables.exception, "message")) />
|
||||
<cfset setDetail(getProperty(variables.exception, "detail")) />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="setErrorCode" returntype="void" access="private" output="false">
|
||||
<cfargument name="errorCode" type="any" required="true" />
|
||||
|
||||
<cfset var e = "null" />
|
||||
|
||||
<cfset variables.errorCode = arguments.errorCode />
|
||||
<cfif structKeyExists(variables.errorInfo, variables.errorCode)>
|
||||
<cfset e = variables.errorInfo[variables.errorCode] />
|
||||
<cfset setType(e.type) />
|
||||
<cfset setMessage(e.message) />
|
||||
<cfset setDetail(e.message) />
|
||||
<cfelse>
|
||||
<cfset setType("UnknownGatewayException") />
|
||||
<cfset setMessage("An unknown exception has been thrown.") />
|
||||
<cfset setDetail("") />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getProperty" returntype="any" access="private" output="false">
|
||||
<cfargument name="props" type="any" required="true" />
|
||||
<cfargument name="name" type="string" required="true" />
|
||||
<cfargument name="default" type="any" required="true" default="" />
|
||||
|
||||
<cfif structKeyExists(arguments.props, arguments.name)>
|
||||
<cfreturn arguments.props[arguments.name] />
|
||||
<cfelse>
|
||||
<cfreturn arguments.default />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getErrorCode" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.errorCode />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getType" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.type />
|
||||
</cffunction>
|
||||
<cffunction name="setType" returntype="void" access="private" output="false">
|
||||
<cfargument name="type" type="string" required="true" />
|
||||
<cfset variables.type = arguments.type />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getMessage" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.message />
|
||||
</cffunction>
|
||||
<cffunction name="setMessage" returntype="void" access="private" output="false">
|
||||
<cfargument name="message" type="string" required="true" />
|
||||
<cfset variables.message = arguments.message />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getDetail" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.detail />
|
||||
</cffunction>
|
||||
<cffunction name="setDetail" returntype="void" access="private" output="false">
|
||||
<cfargument name="detail" type="string" required="true" />
|
||||
<cfset variables.detail = arguments.detail />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
408
cfpayment/api/gateway/paypal/wpp/nvpgateway.cfc
Normal file
408
cfpayment/api/gateway/paypal/wpp/nvpgateway.cfc
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
<!---
|
||||
|
||||
Copyright 2009 Joseph Lamoree (http://www.lamoree.com/)
|
||||
Copyright 2008 Brian Ghidinelli (http://www.ghidinelli.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.
|
||||
|
||||
|
||||
TODO: Add support for API Certificate Security, as well as API Signature Security
|
||||
|
||||
Configuration
|
||||
Username: provided by PayPal in syntax of e-mail address
|
||||
Password: provided by PayPal as 16 alphanumeric char string
|
||||
APIVersion: 56.0 (default)
|
||||
CredentialType: signature (default) or certificate
|
||||
Signature: required for signature credential authentication type
|
||||
Certificate: required for certificate credential authentication type
|
||||
FraudManagement: off (default) or on; Enables robust fraud management, which is an optional PayPal service
|
||||
Masking: on (default) or off; Masks account data to comply with PCI DSS
|
||||
ReturnURL The URL that PayPal will use to return the customer
|
||||
CancelURL The URL that PayPal will use if a customer cancels the order
|
||||
|
||||
--->
|
||||
<cfcomponent extends="cfpayment.api.gateway.base" hint="Name-Value Pair API Gateway for PayPal Website Payments Pro" output="false">
|
||||
|
||||
<!--- cfpayment structure values override base class --->
|
||||
<cfset variables.cfpayment.GATEWAY_NAME = "Name-Value Pair API Gateway for PayPal Website Payments Pro" />
|
||||
<cfset variables.cfpayment.GATEWAY_VERSION = "1.0" />
|
||||
<cfset variables.cfpayment.GATEWAY_TEST_URL = "https://api-3t.sandbox.paypal.com/nvp" />
|
||||
<cfset variables.cfpayment.GATEWAY_LIVE_URL = "https://api-3t.paypal.com/nvp" />
|
||||
<cfset variables.cfpayment.GATEWAY_TEST_CLIENT_URL = "https://www.sandbox.paypal.com/cgi-bin/webscr" />
|
||||
<cfset variables.cfpayment.GATEWAY_LIVE_CLIENT_URL = "https://www.paypal.com/cgi-bin/webscr" />
|
||||
<cfset variables.cfpayment.GATEWAY_API_VERSION = "56.0" />
|
||||
<cfset variables.cfpayment.GATEWAY_CREDENTIAL_TYPE = "signature" />
|
||||
<cfset variables.cfpayment.GATEWAY_SIGNATURE = "" />
|
||||
<cfset variables.cfpayment.GATEWAY_CERTIFICATE = "" />
|
||||
<cfset variables.cfpayment.GATEWAY_MASKING = "on" />
|
||||
<cfset variables.cfpayment.GATEWAY_FRAUD_MANAGEMENT = "off" />
|
||||
<cfset variables.cfpayment.GATEWAY_RETURN_URL = "http://localhost/index.cfm?event=confirmPayPalOrder" />
|
||||
<cfset variables.cfpayment.GATEWAY_CANCEL_URL = "http://localhost/index.cfm?event=cancelPayPalOrder" />
|
||||
|
||||
|
||||
<cffunction name="purchase" returntype="any" access="public" output="false">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<cfset post.AMT = arguments.money.getAmount() />
|
||||
<cfset post.CURRENCYCODE = arguments.money.getCurrency() />
|
||||
<cfset post.METHOD = "DoDirectPayment" />
|
||||
<cfset addCustomer(post=post, account=arguments.account, options=arguments.options) />
|
||||
<cfset addCreditCard(post=post, account=arguments.account) />
|
||||
<cfset addClient(post, arguments.options) />
|
||||
|
||||
<!--- TODO: Support Sale, Authorization, and Order? --->
|
||||
<cfset post.PAYMENTACTION = "Sale" />
|
||||
|
||||
<cfreturn process(payload=post, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="setExpressCheckout" returntype="any" access="public" output="false">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<cfset post.METHOD = "SetExpressCheckout" />
|
||||
<cfset post.AMT = arguments.money.getAmount() />
|
||||
<cfset post.CURRENCYCODE = arguments.money.getCurrency() />
|
||||
<cfset post.RETURNURL = getReturnURL() />
|
||||
<cfset post.CANCELURL = getCancelURL() />
|
||||
|
||||
<!--- TODO: Support Sale, Authorization, and Order? --->
|
||||
<cfset post.PAYMENTACTION = "Sale" />
|
||||
|
||||
<cfreturn process(payload=post, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getExpressCheckoutDetails" returntype="any" access="public" output="false">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<cfset post.METHOD = "GetExpressCheckoutDetails" />
|
||||
<cfset post.TOKEN = arguments.options.tokenId />
|
||||
<cfreturn process(payload=post, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="doExpressCheckoutPayment" returntype="any" access="public" output="false">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = structNew() />
|
||||
|
||||
<cfset post.METHOD = "DoExpressCheckoutPayment" />
|
||||
<cfset post.AMT = arguments.money.getAmount() />
|
||||
<cfset post.CURRENCYCODE = arguments.money.getCurrency() />
|
||||
<cfset post.TOKEN = arguments.options.tokenId />
|
||||
<cfset post.PAYERID = arguments.options.payerId />
|
||||
|
||||
<!--- TODO: Support Sale, Authorization, and Order? --->
|
||||
<cfset post.PAYMENTACTION = "Sale" />
|
||||
|
||||
<cfreturn process(payload=post, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="cancelExpressCheckout" returntype="any" access="public" output="false">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var result = structNew() />
|
||||
|
||||
<cfreturn result />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getExpressCheckoutForward" returntype="string" access="public" output="false">
|
||||
<cfargument name="tokenId" type="string" required="true" />
|
||||
|
||||
<cfset var u = "" />
|
||||
|
||||
<cfif getTestMode()>
|
||||
<cfset u = variables.cfpayment.GATEWAY_TEST_CLIENT_URL />
|
||||
<cfelse>
|
||||
<cfset u = variables.cfpayment.GATEWAY_LIVE_CLIENT_URL />
|
||||
</cfif>
|
||||
<cfset u = u & "?cmd=_express-checkout&token=" & urlEncodedFormat(arguments.tokenId) />
|
||||
<cfreturn u />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="process" returntype="any" access="private" output="false">
|
||||
<cfargument name="payload" type="struct" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfset var response = "null" />
|
||||
<cfset var results = structNew() />
|
||||
<cfset var rd = "null" />
|
||||
<cfset var n = "" />
|
||||
|
||||
<cfset arguments.payload.VERSION = getAPIVersion() />
|
||||
<cfset addCredentials(arguments.payload) />
|
||||
<cfset response = createResponse(argumentCollection = super.process(payload=arguments.payload)) />
|
||||
|
||||
<cfif response.hasError()>
|
||||
<!--- Service did not receive an HTTP response --->
|
||||
<cfset response.setStatus(getService().getStatusUnknown()) />
|
||||
<cfelse>
|
||||
<cfset results = parseResponse(response.getResult()) />
|
||||
<cfset response.setParsedResult(results) />
|
||||
|
||||
<cfif arguments.payload.METHOD eq "DoDirectPayment">
|
||||
<cfif structKeyExists(results, "AVSCODE")>
|
||||
<cfset response.setAVSCode(results.AVSCODE) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(results, "CVV2MATCH")>
|
||||
<cfset response.setCVVCode(results.CVV2MATCH) />
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<cfif results.ACK eq "Failure">
|
||||
<cfset response.setStatus(getService().getStatusDeclined()) />
|
||||
<cfif structKeyExists(results, "L_LONGMESSAGE0")>
|
||||
<cfset response.setMessage(results.L_LONGMESSAGE0) />
|
||||
</cfif>
|
||||
<cfelseif results.ACK eq "Success">
|
||||
<cfset response.setStatus(getService().getStatusSuccessful()) />
|
||||
|
||||
|
||||
|
||||
<!--- Credit Cards --->
|
||||
<cfif structKeyExists(arguments.payload, "PAYMENTACTION")>
|
||||
<cfif arguments.payload.PAYMENTACTION eq "Authorization">
|
||||
<cfif structKeyExists(results, "TRANSACTIONID")>
|
||||
<cfset response.setAuthorization(results.TRANSACTIONID) />
|
||||
</cfif>
|
||||
<cfelseif arguments.payload.PAYMENTACTION eq "Sale">
|
||||
<cfif structKeyExists(results, "TRANSACTIONID")>
|
||||
<cfset response.setTransactionId(results.TRANSACTIONID) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(results, "TOKEN")>
|
||||
<cfset response.setTokenId(results.TOKEN) />
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cfif>
|
||||
<cfelse>
|
||||
<cfset response.setStatus(getService().getStatusFailure()) />
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<!--- Mask the request data --->
|
||||
<cfif getMasking() eq "on">
|
||||
<cfset rd = response.getRequestData() />
|
||||
<cfif isStruct(rd) AND structKeyExists(rd, "payload")>
|
||||
<cfloop collection="#rd.PAYLOAD#" item="n">
|
||||
<cfset rd.PAYLOAD[n] = mask(n, rd.PAYLOAD[n]) />
|
||||
</cfloop>
|
||||
<cfset response.setRequestData(rd) />
|
||||
</cfif>
|
||||
</cfif>
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="parseResponse" returntype="struct" access="private" output="false">
|
||||
<cfargument name="data" type="string" required="true" />
|
||||
|
||||
<cfset var parsed = structNew() />
|
||||
<cfset var pair = "" />
|
||||
<cfset var name = "" />
|
||||
<cfset var value = "" />
|
||||
|
||||
<cfloop list="#arguments.data#" index="pair" delimiters="&">
|
||||
<cfset name = listFirst(pair, "=") />
|
||||
<cfif listLen(pair, "=") gt 1>
|
||||
<cfset value = urlDecode(listLast(pair, "=")) />
|
||||
<cfelse>
|
||||
<cfset value = "" />
|
||||
</cfif>
|
||||
<cfif getMasking() eq "on">
|
||||
<cfset parsed[name] = mask(name, value) />
|
||||
<cfelse>
|
||||
<cfset parsed[name] = value />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
<cfreturn parsed />
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<cffunction name="addCredentials" returntype="void" access="private" output="false">
|
||||
<cfargument name="payload" type="struct" required="true" />
|
||||
|
||||
<cfset arguments.payload.USER = getUsername() />
|
||||
<cfset arguments.payload.PWD = getPassword() />
|
||||
|
||||
<cfif getCredentialType() eq "signature">
|
||||
<cfset arguments.payload.SIGNATURE = getSignature() />
|
||||
<cfelseif getCredentialType() eq "certificate">
|
||||
<cfset arguments.payload.CERTIFICATE = getCertificate() />
|
||||
<cfelse>
|
||||
<cfset createObject("component", "GatewayException").init(type="UnsupportedCredentialTypeException", message="An unsupported credential type was specified.").doThrow() />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addClient" returntype="void" access="private" output="false">
|
||||
<cfargument name="payload" type="struct" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfif not structKeyExists(arguments.options, "ipAddress")>
|
||||
<cfset createObject("component", "GatewayException").init(type="RequiredParameterMissingException", message="The ipAddress is a required parameter.").doThrow() />
|
||||
</cfif>
|
||||
<cfset arguments.payload.IPADDRESS = arguments.options.ipAddress />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addCustomer" returntype="void" access="private" output="false">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfset var p = arguments.post />
|
||||
<cfset var a = arguments.account />
|
||||
|
||||
<cfset p.UserFirstName = a.getFirstName() />
|
||||
<cfset p.LaerFirstName = a.getLastName() />
|
||||
<cfset p.STREET = a.getAddress() />
|
||||
<cfset p.STREET2 = a.getAddress2() />
|
||||
<cfset p.CITY = a.getCity() />
|
||||
<cfset p.STATE = a.getRegion() />
|
||||
<cfset p.COUNTRYCODE = a.getCountry() />
|
||||
<cfset p.ZIP = a.getPostalCode() />
|
||||
<cfset p.PHONENUM = a.getPhoneNumber() />
|
||||
<cfif structKeyExists(arguments.options, "email") and arguments.options.email neq "">
|
||||
<cfset p.EMAIL = arguments.options.email />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "company") and arguments.options.company neq "">
|
||||
<cfset p.BUSINESS = arguments.options.company />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addCreditCard" returntype="void" access="private" output="false">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
|
||||
<cfset var p = arguments.post />
|
||||
<cfset var a = arguments.account />
|
||||
|
||||
<cfif a.getIsVisa()>
|
||||
<cfset p.CREDITCARDTYPE = "Visa" />
|
||||
<cfelseif a.getIsMasterCard()>
|
||||
<cfset p.CREDITCARDTYPE = "MasterCard" />
|
||||
<cfelseif a.getIsAmex()>
|
||||
<cfset p.CREDITCARDTYPE = "Amex" />
|
||||
<cfelseif a.getIsDiscover()>
|
||||
<cfset p.CREDITCARDTYPE = "Discover" />
|
||||
<cfelse>
|
||||
<cfset createObject("component", "GatewayException").init(type="UnsupportedCardTypeException", message="An unsupported credit card type was specified.").doThrow() />
|
||||
</cfif>
|
||||
|
||||
<cfset p.ACCT = a.getAccount() />
|
||||
<cfset p.EXPDATE = a.getMonth() & a.getYear() />
|
||||
<cfset p.CVV2 = a.getVerificationValue() />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mask" returntype="string" access="private" output="false">
|
||||
<cfargument name="name" type="string" required="true" />
|
||||
<cfargument name="value" type="string" required="true" />
|
||||
|
||||
<cfscript>
|
||||
var r = "";
|
||||
var n = arguments.name;
|
||||
var v = arguments.value;
|
||||
|
||||
// Don't let any exceptions stop the transaction
|
||||
try {
|
||||
if (compareNoCase("ACCT", n) eq 0) {
|
||||
r = repeatString("X", len(v) - 4) + right(v, 4);
|
||||
} else if (listContainsNoCase("CVV2,PWD,SIGNATURE", n) gt 0) {
|
||||
r = repeatString("X", len(v));
|
||||
} else {
|
||||
r = v;
|
||||
}
|
||||
}
|
||||
catch(Any e) {
|
||||
// Fail without disclosing any data
|
||||
r = "MaskingException on #n#";
|
||||
}
|
||||
return r;
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getCredentialType" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.cfpayment.GATEWAY_CREDENTIAL_TYPE />
|
||||
</cffunction>
|
||||
<cffunction name="setCredentialType" returntype="void" access="public" output="false">
|
||||
<cfargument name="credentialType" type="string" required="true" />
|
||||
<cfset variables.cfpayment.GATEWAY_CREDENTIAL_TYPE = arguments.credentialType />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getAPIVersion" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.cfpayment.GATEWAY_API_VERSION />
|
||||
</cffunction>
|
||||
<cffunction name="setAPIVersion" returntype="void" access="public" output="false">
|
||||
<cfargument name="apiVersion" type="string" required="true" />
|
||||
<cfset variables.cfpayment.GATEWAY_API_VERSION = arguments.apiVersion />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getSignature" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.cfpayment.GATEWAY_SIGNATURE />
|
||||
</cffunction>
|
||||
<cffunction name="setSignature" returntype="void" access="public" output="false">
|
||||
<cfargument name="signature" type="string" required="true" />
|
||||
<cfset variables.cfpayment.GATEWAY_SIGNATURE = arguments.signature />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getCertificate" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.cfpayment.GATEWAY_CERTIFICATE />
|
||||
</cffunction>
|
||||
<cffunction name="setCertificate" returntype="void" access="public" output="false">
|
||||
<cfargument name="certificate" type="string" required="true" />
|
||||
<cfset variables.cfpayment.GATEWAY_CERTIFICATE = arguments.certificate />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getFraudManagement" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.cfpayment.GATEWAY_FRAUD_MANAGEMENT />
|
||||
</cffunction>
|
||||
<cffunction name="setFraudManagement" returntype="void" access="public" output="false">
|
||||
<cfargument name="fraudManagement" type="string" required="true" />
|
||||
<cfset variables.cfpayment.GATEWAY_FRAUD_MANAGEMENT = arguments.fraudManagement />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getMasking" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.cfpayment.GATEWAY_MASKING />
|
||||
</cffunction>
|
||||
<cffunction name="setMasking" returntype="void" access="public" output="false">
|
||||
<cfargument name="masking" type="string" required="true" />
|
||||
<cfset variables.cfpayment.GATEWAY_MASKING = arguments.masking />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getReturnURL" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.cfpayment.GATEWAY_RETURN_URL />
|
||||
</cffunction>
|
||||
<cffunction name="setReturnURL" returntype="void" access="public" output="false">
|
||||
<cfargument name="returnURL" type="string" required="true" />
|
||||
<cfset variables.cfpayment.GATEWAY_RETURN_URL = arguments.returnURL />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getCancelURL" returntype="string" access="public" output="false">
|
||||
<cfreturn variables.cfpayment.GATEWAY_CANCEL_URL />
|
||||
</cffunction>
|
||||
<cffunction name="setCancelURL" returntype="void" access="public" output="false">
|
||||
<cfargument name="cancelURL" type="string" required="true" />
|
||||
<cfset variables.cfpayment.GATEWAY_CANCEL_URL = arguments.cancelURL />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
30
cfpayment/api/gateway/paypal/wpp/soapgateway.cfc
Normal file
30
cfpayment/api/gateway/paypal/wpp/soapgateway.cfc
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<!---
|
||||
|
||||
Copyright 2009 Joseph Lamoree (http://www.lamoree.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.
|
||||
|
||||
|
||||
TODO: Everything
|
||||
|
||||
--->
|
||||
<cfcomponent extents="cfpayment.api.gateway.base" hint="SOAP API Gateway for PayPal Website Payments Pro" output="false">
|
||||
|
||||
<!--- cfpayment structure values override base class --->
|
||||
<cfset variables.cfpayment.GATEWAY_NAME = "SOAP API Gateway for PayPal Website Payments Pro" />
|
||||
<cfset variables.cfpayment.GATEWAY_VERSION = "1.0" />
|
||||
<cfset variables.cfpayment.GATEWAY_TEST_URL = "https://api-3t.sandbox.paypal.com/2.0/" />
|
||||
<cfset variables.cfpayment.GATEWAY_LIVE_URL = "https://api-3t.paypal.com/2.0/" />
|
||||
|
||||
|
||||
</cfcomponent>
|
||||
299
cfpayment/api/gateway/paypal/wpp/tests/NVPGatewayTest.cfc
Normal file
299
cfpayment/api/gateway/paypal/wpp/tests/NVPGatewayTest.cfc
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
<!---
|
||||
|
||||
Copyright 2009 Joseph Lamoree (http://www.lamoree.com/)
|
||||
Copyright 2008 Brian Ghidinelli (http://www.ghidinelli.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.
|
||||
|
||||
|
||||
Create gateway configuration file: NVPGatewayTest.properties (remove leading whitespace):
|
||||
gateway.username=paypal_99999999_biz_api1.paypal.com
|
||||
gateway.password=abc123xyz789
|
||||
gateway.credentialType=signature
|
||||
gateway.signature=random_character_string
|
||||
gateway.certificate=
|
||||
gateway.apiVersion=56.0
|
||||
gateway.returnURL=http://localhost/cfpayment/api/gateway/paypal/wpp/tests/NVPGatewayTest.cfc?method=testRemote&method=testCompleteExpressCheckout
|
||||
gateway.cancelURL=http://localhost/cfpayment/api/gateway/paypal/wpp/tests/NVPGatewayTest.cfc?method=testRemote&method=testCancelExpressCheckout
|
||||
gateway.testMode=true
|
||||
|
||||
validCustomer.UserFirstName=Jeff
|
||||
validCustomer.LaerFirstName=Lebowski
|
||||
validCustomer.address=609 Venenzia Ave.
|
||||
validCustomer.city=Venice
|
||||
validCustomer.region=CA
|
||||
validCustomer.postalCode=90291
|
||||
|
||||
validCard.account=4111111111111111
|
||||
validCard.expMonth=10
|
||||
validCard.expYear=2010
|
||||
validCard.verificationValue=000
|
||||
|
||||
invalidCard.account=4111111111111111
|
||||
invalidCard.expMonth=10
|
||||
invalidCard.expYear=2010
|
||||
invalidCard.verificationValue=000
|
||||
|
||||
purchase.amount=4995
|
||||
purchase.bogusAmount=0
|
||||
purchase.currency=USD
|
||||
purchase.bogusCurrency=XXX
|
||||
purchase.ipAddress=10.1.1.1
|
||||
purchase.bogusIPAddress=ipaddr
|
||||
|
||||
paypalCustomer.UserFirstName=Test
|
||||
paypalCustomer.LaerFirstName=User
|
||||
paypalCustomer.email=paypal_99999999_per@paypal.com
|
||||
--->
|
||||
<cfcomponent extends="mxunit.framework.TestCase">
|
||||
|
||||
<cfset variables.core = "null" />
|
||||
<cfset variables.gateway = "null" />
|
||||
<cfset variables.configFile = reReplaceNoCase(getMetaData(this).path, "\.cfc$", ".properties") />
|
||||
|
||||
<cffunction name="setUp" returntype="void" access="public" output="false">
|
||||
<cfset var gatewayConfig = readProperties("gateway") />
|
||||
|
||||
<cfset gatewayConfig.path = "paypal.wpp.NVPGateway" />
|
||||
<cfset variables.core = createObject("component", "cfpayment.api.core").init(config=gatewayConfig) />
|
||||
<cfset variables.gateway = variables.core.getGateway() />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testPurchase" returntype="void" access="public" output="false">
|
||||
<cfset var purchase = readProperties("purchase") />
|
||||
<cfset var response = "null" />
|
||||
<cfset var money = "null" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<!--- Valid card, proper amount --->
|
||||
<cfset options.ipAddress = purchase.ipAddress />
|
||||
<cfset money = variables.core.createMoney(cents=purchase.amount, currency=purchase.currency) />
|
||||
<cfset response = variables.gateway.purchase(money=money, account=createValidCard(), options=options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The purchase should have succeeded.") />
|
||||
|
||||
<!--- Invalid card --->
|
||||
<cfset response = variables.gateway.purchase(money=money, account=createInvalidCard(), options=options) />
|
||||
<cfset assertTrue(not response.getSuccess(), "The purchase should not have succeeded, due to invalid credit card.") />
|
||||
|
||||
<!--- Bad IP Address --->
|
||||
<cfset options.ipAddress = purchase.bogusIPAddress />
|
||||
<cfset response = variables.gateway.purchase(money=money, account=createInvalidCard(), options=options) />
|
||||
<cfset assertTrue(not response.getSuccess(), "The purchase should not have succeeded, due to a bogus IP address.") />
|
||||
|
||||
<!--- Bad purchase amount --->
|
||||
<cfset money = variables.core.createMoney(cents=purchase.bogusAmount, currency=purchase.currency) />
|
||||
<cfset response = variables.gateway.purchase(money=money, account=createInvalidCard(), options=options) />
|
||||
<cfset assertTrue(not response.getSuccess(), "The purchase should not have succeeded, due to invalid amount.") />
|
||||
|
||||
<!--- Bogus currency --->
|
||||
<cfset money = variables.core.createMoney(cents=purchase.amount, currency=purchase.bogusCurrency) />
|
||||
<cfset response = variables.gateway.purchase(money=money, account=createInvalidCard(), options=options) />
|
||||
<cfset assertTrue(not response.getSuccess(), "The purchase should not have succeeded, due to a bogus currency.") />
|
||||
|
||||
<!--- Duplicate Invoices --->
|
||||
|
||||
<!--- AVS Validation --->
|
||||
|
||||
<!--- CVV2 Validation --->
|
||||
|
||||
<!--- Expiration Validation --->
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
|
||||
<cffunction name="testBeginExpressCheckout" returntype="void" access="public" output="false">
|
||||
<cfset var purchase = readProperties("purchase") />
|
||||
<cfset var response = "null" />
|
||||
<cfset var money = "null" />
|
||||
<cfset var tokenId = "" />
|
||||
|
||||
<cfset money = variables.core.createMoney(cents=purchase.amount, currency=purchase.currency) />
|
||||
<cfset response = variables.gateway.setExpressCheckout(money) />
|
||||
<cfset assertTrue(response.getSuccess(), "The gateway response should have been successful.") />
|
||||
<cfset tokenId = response.getTokenId() />
|
||||
<cfset assertTrue(tokenId neq "", "The response token should not be an empty string.") />
|
||||
<cflocation url="#variables.gateway.getExpressCheckoutForward(tokenId)#" addtoken="false" />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testCompleteExpressCheckout" returntype="void" access="public" output="false">
|
||||
<cfset var purchase = readProperties("purchase") />
|
||||
<cfset var customer = readProperties("paypalCustomer") />
|
||||
<cfset var response = "null" />
|
||||
<cfset var money = "null" />
|
||||
<cfset var data = "null" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset assertTrue(structKeyExists(url, "token"), "The URL should contain the PayPal Express Checkout token parameter.") />
|
||||
<cfset assertTrue(structKeyExists(url, "payerId"), "The URL should contain the PayPal Express Checkout payerId parameter.") />
|
||||
<cfset options.tokenId = URL.token />
|
||||
<cfset options.payerId = URL.payerId />
|
||||
|
||||
<!--- Get the details of the PayPal customer --->
|
||||
<cfset response = variables.gateway.getExpressCheckoutDetails(options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The gateway response should have been successful.") />
|
||||
<cfset data = response.getParsedResult() />
|
||||
<cfset assertTrue(structKeyExists(data, "email") and data.email eq customer.email, "The PayPal customer e-mail address should have been #customer.email#.") />
|
||||
<cfset assertTrue(structKeyExists(data, "firstName") and data.UserFirstName eq customer.UserFirstName, "The PayPal customer first name should have been #customer.UserFirstName#.") />
|
||||
<cfset assertTrue(structKeyExists(data, "lastName") and data.LaerFirstName eq customer.LaerFirstName, "The PayPal customer last name should have been #customer.LaerFirstName#.") />
|
||||
|
||||
<!--- Complete the payment --->
|
||||
<cfset money = variables.core.createMoney(cents=purchase.amount, currency=purchase.currency) />
|
||||
<cfset response = variables.gateway.doExpressCheckoutPayment(money, options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The gateway response should have been successful.") />
|
||||
<cfset assertTrue(response.getTransactionId() neq "", "The response transactionId should not be an empty string.") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testCancelExpressCheckout" returntype="void" access="public" output="false">
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.tokenId = URL.token />
|
||||
<cfset assertTrue(options.tokenId neq "", "The token should be passed in as a URL parameter.") />
|
||||
<cfset variables.gateway.cancelExpressCheckout(options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testAuthorizeOnly" access="public" returntype="void" output="false">
|
||||
<cfset var purchase = readProperties("purchase") />
|
||||
<cfset var response = "null" />
|
||||
<cfset var money = "null" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.ipAddress = purchase.ipAddress />
|
||||
<cfset money = variables.core.createMoney(cents=purchase.amount, currency=purchase.currency) />
|
||||
<cfset response = variables.gateway.authorize(money=money, account=createValidCard(), options=options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorize did not succeed") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testAuthorizeThenCapture" access="public" returntype="void" output="false">
|
||||
<cfset var purchase = readProperties("purchase") />
|
||||
<cfset var money = "null" />
|
||||
<cfset var response = "null" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.ipAddress = purchase.ipAddress />
|
||||
<cfset money = variables.core.createMoney(cents=purchase.amount, currency=purchase.currency) />
|
||||
<cfset response = variables.gateway.authorize(money=money, account=createValidCard(), options=options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed") />
|
||||
|
||||
<cfset response = variables.gateway.capture(money=money, authorization=response.getTransactionId(), options=options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The capture did not succeed") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testAuthorizeThenCredit" access="public" returntype="void" output="false">
|
||||
<cfset var purchase = readProperties("purchase") />
|
||||
<cfset var money = "null" />
|
||||
<cfset var response = "null" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.ipAddress = purchase.ipAddress />
|
||||
<cfset money = variables.core.createMoney(cents=purchase.amount, currency=purchase.currency) />
|
||||
<cfset response = variables.gateway.authorize(money=money, account=createValidCard(), options=options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed") />
|
||||
|
||||
<cfset response = variables.gateway.credit(transactionid=response.getTransactionID(), money=money, options=options) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "You cannot credit a preauth") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testAuthorizeThenVoid" access="public" returntype="void" output="false">
|
||||
<cfset var purchase = readProperties("purchase") />
|
||||
<cfset var money = "null" />
|
||||
<cfset var response = "null" />
|
||||
<cfset var options = structNew() />
|
||||
<cfset var account = createValidCard() />
|
||||
|
||||
<cfset options.ipAddress = purchase.ipAddress />
|
||||
<cfset money = variables.core.createMoney(cents=purchase.amount, currency=purchase.currency) />
|
||||
<cfset response = variables.gateway.authorize(money=money, account=createValidCard(), options=options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The authorization did not succeed") />
|
||||
|
||||
<cfset response = variables.gateway.void(transactionid=response.getTransactionID(), options=options) />
|
||||
<cfset assertTrue(NOT response.getSuccess(), "The void of an authorization did not succeed") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testPurchaseThenCredit" access="public" returntype="void" output="false">
|
||||
<cfset var purchase = readProperties("purchase") />
|
||||
<cfset var money = "null" />
|
||||
<cfset var response = "null" />
|
||||
<cfset var options = structNew() />
|
||||
|
||||
<cfset options.ipAddress = purchase.ipAddress />
|
||||
<cfset money = variables.core.createMoney(cents=purchase.amount, currency=purchase.currency) />
|
||||
<cfset response = variables.gateway.purchase(money=money, account=createValidCard(), options=options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The purchase did not succeed") />
|
||||
|
||||
<cfset response = variables.gateway.credit(transactionid=response.getTransactionID(), money=money, options=options) />
|
||||
<cfset assertTrue(response.getSuccess(), "The credit of a purchase did not succeed") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<cffunction name="createValidCard" access="private" returntype="any" output="false">
|
||||
<cfset var account = variables.core.createCreditCard() />
|
||||
<cfset var validCustomer = readProperties("validCustomer") />
|
||||
<cfset var validCard = readProperties("validCard") />
|
||||
|
||||
<cfset account.setAccount(validCard.account) />
|
||||
<cfset account.setMonth(validCard.expMonth) />
|
||||
<cfset account.setYear(validCard.expYear) />
|
||||
<cfset account.setFirstName(validCustomer.UserFirstName) />
|
||||
<cfset account.setLastName(validCustomer.LaerFirstName) />
|
||||
<cfset account.setAddress(validCustomer.address) />
|
||||
<cfset account.setPostalCode(validCustomer.postalCode) />
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createInvalidCard" access="private" returntype="any" output="false">
|
||||
<cfset var account = variables.core.createCreditCard() />
|
||||
<cfset var validCustomer = readProperties("validCustomer") />
|
||||
<cfset var invalidCard = readProperties("invalidCard") />
|
||||
|
||||
<cfset account.setAccount(invalidCard.account) />
|
||||
<cfset account.setMonth(invalidCard.expMonth) />
|
||||
<cfset account.setYear(invalidCard.expYear) />
|
||||
<cfset account.setFirstName(validCustomer.UserFirstName) />
|
||||
<cfset account.setLastName(validCustomer.LaerFirstName) />
|
||||
<cfset account.setAddress(validCustomer.address) />
|
||||
<cfset account.setPostalCode(validCustomer.postalCode) />
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="readProperties" returntype="struct" access="private" output="false">
|
||||
<cfargument name="prefix" type="string" required="false" default="" />
|
||||
|
||||
<cfset var file = variables.configFile />
|
||||
<cfset var properties = structNew() />
|
||||
<cfset var line = "" />
|
||||
<cfset var name = "" />
|
||||
|
||||
<cfif not fileExists(file)>
|
||||
<cfthrow type="FileNotFoundException" message="The properties file (#file#) was not found" />
|
||||
</cfif>
|
||||
|
||||
<cfloop file="#file#" index="line">
|
||||
<cfif reFindNoCase("^[\._a-z0-9]+=", line) eq 1>
|
||||
<cfset name = listFirst(line, "=") />
|
||||
<cfif arguments.prefix neq "">
|
||||
<cfif findNoCase(arguments.prefix & ".", name) eq 1>
|
||||
<cfset properties[listLast(name, ".")] = listRest(line, "=") />
|
||||
</cfif>
|
||||
<cfelse>
|
||||
<cfset properties[name] = listRest(line, "=") />
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
<cfreturn properties />
|
||||
</cffunction>
|
||||
|
||||
|
||||
</cfcomponent>
|
||||
84
cfpayment/api/gateway/paypal/wpp/tests/readme.html
Normal file
84
cfpayment/api/gateway/paypal/wpp/tests/readme.html
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>cfpayment PayPal Website Payments Pro Gateway</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 62.5%;
|
||||
}
|
||||
|
||||
div#page {
|
||||
margin: 1em;
|
||||
font-size: 1.4em;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
code {
|
||||
white-space: pre;
|
||||
margin: 0;
|
||||
padding: 0 1em 1em 1em;
|
||||
line-height: 1em;
|
||||
border: 1px solid #666;
|
||||
display: block;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #00c;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="page">
|
||||
<h1>cfpayment PayPal Website Payments Pro Gateway</h1>
|
||||
<p>
|
||||
This page contains information on using and testing the two types of <a href="http://cfpayment.riaforge.org/">cfpayment</a> gateways used with PayPal: Name-Value Pair and SOAP.
|
||||
</p>
|
||||
|
||||
<h2>Name-Value Pair API</h2>
|
||||
<p>
|
||||
The cfpayment core is created with gateway configuration options like so:
|
||||
</p>
|
||||
<code>
|
||||
config = structNew();
|
||||
config.path = "paypal.wpp.NVPGateway";
|
||||
config.username = "paypal_99999999_biz_api1.paypal.com";
|
||||
config.password= "abc123xyz789";
|
||||
config.signature= "AbcDEfgHiJKlMNoPQrstUvWXYz0123456789";
|
||||
config.returnURL = "http://localhost/cfpayment/api/gateway/paypal/wpp/tests/NVPGatewayTest.cfc?method=runTestRemote&method=testCompleteExpressCheckout";
|
||||
config.cancelURL = "http://localhost/cfpayment/api/gateway/paypal/wpp/tests/NVPGatewayTest.cfc?method=runTestRemote&method=testCancelExpressCheckout";
|
||||
|
||||
cfpayment = createObject("component", "cfpayment.api.core").init(config=config);
|
||||
gateway = cfpayment.getGateway();
|
||||
</code>
|
||||
|
||||
<h2>SOAP API</h2>
|
||||
<p>
|
||||
The PayPal SOAP API support is a big <kbd>TODO</kbd> right now.
|
||||
</p>
|
||||
|
||||
<h2>Tests</h2>
|
||||
|
||||
<p>The <kbd>NVPGatewayTest</kbd> MXUnit Test Case contains many individual tests, however it's best to call the two major test methods directly, as the Express Checkout process has a specific order. Before running the Express Checkout test, login to the <a href="https://developer.paypal.com/">PayPal Sandbox</a>.</p>
|
||||
<ul>
|
||||
<li> <a href="NVPGatewayTest.cfc?method=runTestRemote&testMethod=testPurchase">NVPGatewayTest.testPurchase()</a>: Test the PayPal <strong>Direct Payment</strong> functionality of the gateway</li>
|
||||
<li> <a href="NVPGatewayTest.cfc?method=runTestRemote&testMethod=testBeginExpressCheckout">NVPGatewayTest.testBeginExpressCheckout()</a>: Test the PayPal <strong>Express Checkout</strong> process. The test call the PayPal server with the <kbd>SetExpressCheckout</kbd> command. It then forwards the browser to PayPal to authenticate and confirm payment details. The return URL is to the portion of the test class that: 1) gets customer details, and 2) completes the payment.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
644
cfpayment/api/gateway/skipjack/skipjack.cfc
Normal file
644
cfpayment/api/gateway/skipjack/skipjack.cfc
Normal file
|
|
@ -0,0 +1,644 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2008 Mark Mazelin (http://www.mkville.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="Base SkipJack Interface" extends="cfpayment.api.gateway.base" hint="Common functionality for SkipJack Gateway" output="false">
|
||||
|
||||
<!---
|
||||
PROGRAM: skipjack.cfc
|
||||
UPDATES:
|
||||
22-JAN-2009-MBM: added len() check on ParsedResult.szAuthorizationDeclinedMessage in ParseAuthorizeMessage()
|
||||
30-JAN-2009-MBM: added logic to MapGenericResponse() to find AuditId in response query and set response.TransactionId with the value (used for credit/newcharge items)
|
||||
removed isValidCVV and isValidAVS checks in ParseAuthorizeMessage() since we don't pass in the validity options
|
||||
13-JAN-2011-MBM: change live url to use www instead of ms
|
||||
--->
|
||||
<cfset variables.cfpayment.GATEWAY_NAME = "SkipJack" />
|
||||
<cfset variables.cfpayment.GATEWAY_VERSION = "1.1" />
|
||||
<cfset variables.cfpayment.GATEWAY_LIVE_URL = "https://www.skipjackic.com/scripts/EvolvCC.dll?" />
|
||||
<cfset variables.cfpayment.GATEWAY_TEST_URL = "https://developer.skipjackic.com/scripts/EvolvCC.dll?" />
|
||||
<!--- gateway-specific variables --->
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD = StructNew() />
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD["authorize"] = "AuthorizeAPI" />
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD["credit"] = "SJAPI_TransactionChangeStatusRequest" />
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD["newcharge"] = "SJAPI_TransactionChangeStatusRequest" />
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD["void"] = "SJAPI_TransactionChangeStatusRequest" />
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD["capture"] = "SJAPI_TransactionChangeStatusRequest" />
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD["status"] = "SJAPI_TransactionStatusRequest" />
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD["recurring_add"] = "SJAPI_RecurringPaymentAdd" />
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD["recurring_edit"] = "SJAPI_RecurringPaymentEdit" />
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD["recurring_delete"] = "SJAPI_RecurringPaymentDelete" />
|
||||
<cfset variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD["recurring_get"] = "SJAPI_RecurringPaymentRequest" />
|
||||
|
||||
<cfset variables.cfpayment.PERIODICITY_MAP["weekly"] = "0" /><!--- starting date + 7 days --->
|
||||
<cfset variables.cfpayment.PERIODICITY_MAP["biweekly"] = "1" /><!--- starting date + 14 days --->
|
||||
<cfset variables.cfpayment.PERIODICITY_MAP["semimonthly"] = "2" /><!--- Starting date + 15 days --->
|
||||
<cfset variables.cfpayment.PERIODICITY_MAP["monthly"] = "3" /><!--- Every month --->
|
||||
<cfset variables.cfpayment.PERIODICITY_MAP["quadweekly"] = "4" /><!--- Every fourth week --->
|
||||
<cfset variables.cfpayment.PERIODICITY_MAP["bimonthly"] = "5" /><!--- Every other month --->
|
||||
<cfset variables.cfpayment.PERIODICITY_MAP["quarterly"] = "6" /><!--- Every third month --->
|
||||
<cfset variables.cfpayment.PERIODICITY_MAP["semiyearly"] = "7" /><!--- Twice a year --->
|
||||
<cfset variables.cfpayment.PERIODICITY_MAP["yearly"] = "8" /><!--- Once a year --->
|
||||
<!--- not supported: daily --->
|
||||
|
||||
<cfset variables.cfpayment.GatewayAction = "" />
|
||||
|
||||
<!--- CONSTANTS --->
|
||||
<cfset variables.cfpayment.SKIPJACK_ORDER_STRING_DUMMY_VALUES = "1~None~0.00~0~N~||" />
|
||||
<cfset variables.cfpayment.SKIPJACK_ADD_RECURRING_RESPONSE_COLUMN_HEADERS = ListToArray("SerialNumber,ResponseCode,NumberOfRecords,RecurringPaymentId,OrderNumber,zReserved1,zReserved2,zReserved3,zReserved4,zReserved5,zReserved6,zReserved7") />
|
||||
<cfset variables.cfpayment.SKIPJACK_EDIT_RECURRING_RESPONSE_COLUMN_HEADERS = ListToArray("SerialNumber,ResponseCode,zReserved1,zReserved2,zReserved3,zReserved4,zReserved5,zReserved6,zReserved7,zReserved8,zReserved9,zReserved10") />
|
||||
<cfset variables.cfpayment.SKIPJACK_DELETE_RECURRING_RESPONSE_COLUMN_HEADERS = ListToArray("SerialNumber,ResponseCode,zReserved1,zReserved2,zReserved3,zReserved4,zReserved5,zReserved6,zReserved7,zReserved8,zReserved9,zReserved10") />
|
||||
<cfset variables.cfpayment.SKIPJACK_GET_RECURRING_RESPONSE_COLUMN_HEADERS = ListToArray("SerialNumber,ResponseCode,NumberOfRecords,zReserved1,zReserved2,zReserved3,zReserved4,zReserved5,zReserved6,zReserved7,zReserved8,zReserved9") />
|
||||
<!--- don't make these an array b/c we need them as a plain string list --->
|
||||
<cfset variables.cfpayment.SKIPJACK_GET_RECURRING_RESPONSE_DATA_COLUMN_HEADERS = "SerialNumber,DeveloperSerialNumber,RecurringPaymentId,CustomerName,PaymentFrequency,RecurringAmount,TransactionDate,TotalTransactions,RemainingTransactions,Email,Address1,Address2,Address3,Address4,City,State,PostalCode,Country,Phone,Fax,AccountNumber,ExpMonth,ExpYear,ItemNumber,ItemDescription,Comment,OrderNumber" />
|
||||
<cfset variables.cfpayment.SKIPJACK_CHANGE_STATUS_RESPONSE_COLUMN_HEADERS = ListToArray("SerialNumber,ResponseCode,NumberOfRecords,zReserved1,zReserved2,zReserved3,zReserved4,zReserved5,zReserved6,zReserved7,zReserved8,zReserved9") />
|
||||
<!--- don't make these an array b/c we need them as a plain string list --->
|
||||
<cfset variables.cfpayment.SKIPJACK_CHANGE_STATUS_RESPONSE_DATA_COLUMN_HEADERS = "SerialNumber,TransactionAmount,DesiredStatus,StatusResponse,StatusResponseMessage,OrderNumber,AuditID" />
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_STATUS_RESPONSE_COLUMN_HEADERS = ListToArray("SerialNumber,ResponseCode,NumberOfRecords,zReserved1,zReserved2,zReserved3,zReserved4,zReserved5,zReserved6,zReserved7,zReserved8,zReserved9") />
|
||||
<!--- don't make these an array b/c we need them as a plain string list --->
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_STATUS_RESPONSE_DATA_COLUMN_HEADERS = "SerialNumber,TransactionAmount,TransactionStatusCode,TransactionStatusMessage,OrderNumber,TransactionDateTime,TransactionID,ApprovalCode,BatchNumber" />
|
||||
|
||||
<!---
|
||||
___SCENARIOS___ (from SkipJack_Integration_Guide.pdf, pp 70-79)
|
||||
* APPROVED: szReturnCode = 1, szIsApproved = 1, szAuthorizationResponseCode = 6 digit code, AuthCode = 6 digit code
|
||||
* DECLINED: szReturnCode = 1, szIsApproved = 0, szAuthorizationResponseCode = empty, AuthCode = empty
|
||||
* NOT PROCESSED: szReturnCode = -35, szIsApproved = empty, szAuthorizationResponseCode = empty, AuthCode = empty
|
||||
* APPROVED: szReturnCode = 1, szIsApproved = 1, szAuthorizationResponseCode = 6 digit code, AuthCode = 6 digit code, szAVSResponseCode = X (full AVS match, but AVS filtering off)
|
||||
* APPROVED: szReturnCode = 1, szIsApproved = 1, szAuthorizationResponseCode = 6 digit code, AuthCode = 6 digit code, szAVSResponseCode = P (partial AVS match, SkipJack AVS filtering threshold not breached)
|
||||
* DECLINED: szReturnCode = 1, szIsApproved = 0, szAuthorizationResponseCode = 6 digit code, AuthCode = 6 digit code, szAVSResponseCode = P (partial AVS match, SkipJack AVS filtering reached therefore declined)
|
||||
* APPROVED: szReturnCode = 1, szIsApproved = 1, szAuthorizationResponseCode = 6 digit code, AuthCode = 6 digit code, szCVV2ResponseCode = M (CVV Match)
|
||||
* DECLINED: szReturnCode = 1, szIsApproved = 0, szAuthorizationResponseCode = empty, AuthCode = empty, szCVV2ResponseCode = N (CVV No Match - VISA and MasterCard)
|
||||
* APPROVED: szReturnCode = 1, szIsApproved = 1, szAuthorizationResponseCode = 6 digit code, AuthCode = 6 digit code, szCVV2ResponseCode = empty (AMEX or Discover check the CVV but do not return a CVV response code, but this passed the CVV check b/c the transaction was not declined)
|
||||
* DECLINED: szReturnCode = 1, szIsApproved = 0, szAuthorizationResponseCode = empty, AuthCode = empty, szCVV2ResponseCode = empty (AMEX or Discover check the CVV but do not return a CVV response code, but this failed the CVV check b/c the transaction was declined)
|
||||
|
||||
__EXAMPLE DECLINED MESSAGES__
|
||||
Fail Amount : Authorization failed, card declined.
|
||||
Fail AVS : ? not sure
|
||||
Fail CVV : CVV2 Value supplied is invalid
|
||||
Fail CCNum : Invalid credit card number
|
||||
--->
|
||||
<!--- return codes --->
|
||||
<cfset variables.cfpayment.SKIPJACK_SUCCESS_MESSAGE = "The transaction was successful.">
|
||||
|
||||
<cfset variables.cfpayment.SKIPJACK_CHANGE_STATUS_SETTLE="SETTLE">
|
||||
<cfset variables.cfpayment.SKIPJACK_CHANGE_STATUS_DELETE="DELETE">
|
||||
<cfset variables.cfpayment.SKIPJACK_CHANGE_STATUS_CREDIT="CREDIT">
|
||||
<cfset variables.cfpayment.SKIPJACK_CHANGE_STATUS_NEWCHARGE="AUTHORIZEADDITIONAL">
|
||||
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_CURRENT_STATUS=StructNew()>
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_CURRENT_STATUS["0"]="Idle">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_CURRENT_STATUS["1"]="Authorized">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_CURRENT_STATUS["2"]="Denied">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_CURRENT_STATUS["3"]="Settled">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_CURRENT_STATUS["4"]="Credited">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_CURRENT_STATUS["5"]="Deleted">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_CURRENT_STATUS["6"]="Archived">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_CURRENT_STATUS["7"]="Pre-Authorized">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_CURRENT_STATUS["8"]="Split Settled">
|
||||
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_PENDING_STATUS=StructNew()>
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_PENDING_STATUS["0"]="Idle">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_PENDING_STATUS["1"]="Pending Credit">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_PENDING_STATUS["2"]="Pending Settlement">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_PENDING_STATUS["3"]="Pending Authorization">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_PENDING_STATUS["4"]="Pending Manual Settlement">
|
||||
<cfset variables.cfpayment.SKIPJACK_TRANSACTION_PENDING_STATUS["5"]="Pending Recurring">
|
||||
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES=StructNew()>
|
||||
<!--- <cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-1"]="Error in request"> --->
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["0"]="Communication failure">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["1"]="Success">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-1"]="Invalid Command">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-2"]="Parameter Missing">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-3"]="Failed retrieving response">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-4"]="Invalid Status">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-5"]="Failed reading security flags">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-6"]="Developer serial number not found">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-7"]="Invalid Serial Number">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-11"]="Failed Adding Recurring Payment">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-12"]="Invalid Recurring Payment Frequency">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-13"]="Failed Delete of Recurring Payment">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-14"]="Failed Edit of Recurring Payment">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-15"]="Failure (Close Current Open Batch)">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-35"]="Invalid credit card number">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-37"]="Merchant processor unavailable">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-39"]="Length or value of HTML Serial Number">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-51"]="Length or value of zip code">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-52"]="Length or value in shipto zip code">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-53"]="Length or value in expiration date">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-54"]="Length or value of month or year of credit card account number">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-55"]="Length or value in streetaddress">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-56"]="Length or value in shiptoaddress">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-57"]="Length or value in transactionamount">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-58"]="Length or value in merchant name">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-59"]="Length or value in merchant address">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-60"]="Length or value in merchant state">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-61"]="Error length or value in shipto state">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-62"]="Error length or value in order string">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-64"]="Error empty phone number">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-65"]="Error empty sjname">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-66"]="Error empty e-mail">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-67"]="Error empty street address">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-68"]="Error empty city">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-69"]="Error empty state">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-70"]="Error empty zipcode">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-71"]="Empty ordernumber">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-72"]="Empty accountnumber">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-73"]="Empty month">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-74"]="Empty year">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-75"]="Empty serialnumber">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-76"]="Empty transactionamount">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-77"]="Empty orderstring">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-78"]="Empty shiptophone">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-79"]="Length or value sjname">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-80"]="Length shipto name">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-81"]="Length or value customer location">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-82"]="Length or value state">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-83"]="Length or value shiptophone">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-84"]="Duplicate ordernumber"><!--- only returned when reject dup trans is enabled --->
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-85"]="Airline leg info invalid Airline leg field value is invalid or empty.">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-86"]="Airline ticket info invalid Airline ticket info field is invalid or empty">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-87"]="Point of Sale check routing number must be 9 numeric digits Point of Sale check routing number is invalid or empty.">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-88"]="Point of Sale check account number missing or invalid Point of Sale check account number is invalid or empty.">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-89"]="Point of Sale check MICR missing or invalid Point of Sale check MICR invalid or empty.">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-90"]="Point of Sale check number missing or invalid Point of Sale check number invalid or empty.">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-91"]="Security Number invalid or empty">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-92"]="Approval code invalid">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-93"]="Blind credits request refused">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-94"]="Blind credits failed">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-95"]="Voice authorization request refused">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-96"]="Voice authorizations failed">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-97"]="Fraud rejection">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-98"]="Invalid discount amount">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-99"]="POS PIN Debit Pin Block Debit-specific">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-100"]="POS PIN Debit Invalid Key Serial Number Debit-specific">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-101"]="Invalid authentication data">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-102"]="Authentication data not allowed">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-103"]="POS Check Invalid Birth Date POS check dateofbirth variable contains a birth date in an incorrect format. Use MM/DD/YYYY format for this variable.">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-104"]="POS Check Invalid Identification Type POS check identificationtype variable contains a identification type value which is invalid. Use the single digit value where Social Security Number=1, Drivers License=2 for this variable.">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-105"]="Invalid trackdata">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-106"]="POS Check Invalid Account Type">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-107"]="POS PIN Debit Invalid Sequence Number">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-108"]="Invalid transaction ID">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-109"]="Invalid from account type">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-110"]="Pos Error Invalid To Account Type">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-112"]="Pos Error Invalid Auth Option">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-113"]="Pos Error Transaction Failed">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-114"]="Pos Error Invalid Incoming Eci">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-115"]="POS Check Invalid Check Type">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-116"]="POS Check Invalid Lane Number POS Check lane or cash register number is invalid. Use a valid lane or cash register number that has been configured in the Skipjack Merchant Account.">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-117"]="POS Check Invalid Cashier Number">
|
||||
<cfset variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES["-503"]="Request timed out">
|
||||
|
||||
<cffunction name="init" output="false" access="public" returntype="any" hint="">
|
||||
<cfset super.init(argumentCollection=arguments)>
|
||||
<cfset variables.cfpayment.csvutils=CreateObject("component", "cfpayment.api.utils.csvutils")>
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<!--- shared process wrapper with gateway/transaction error handling --->
|
||||
<cffunction name="process" output="false" access="private" returntype="any">
|
||||
<cfargument name="payload" type="struct" required="true" />
|
||||
|
||||
<cfset var response = "" />
|
||||
|
||||
<!--- send it over the wire using the base gateway --->
|
||||
<cfset response = createResponse(argumentCollection = super.process(argumentCollection = arguments)) />
|
||||
|
||||
<!--- we do some meta-checks for gateway-level errors (as opposed to auth/decline errors) --->
|
||||
<cfif NOT response.hasError()>
|
||||
|
||||
<!--- we need to have a result we can parse; otherwise that's an error in itself --->
|
||||
<cfif len(response.getResult())>
|
||||
<!--- parse response results --->
|
||||
<cfset ParseResponse(response)>
|
||||
<cfelse>
|
||||
<!--- this is bad, because SkipJack didn't return a result --->
|
||||
<cfset response.setStatus(getService().getStatusUnknown()) />
|
||||
</cfif>
|
||||
</cfif>
|
||||
<!--- <cfdump var="#response.getMemento()#" label="response"><cfabort> --->
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getGatewayAction" access="public" output="false" returntype="string">
|
||||
<cfargument name="shortaction" type="boolean" default="true"/>
|
||||
<!--- some processing (e.g. recurring) adds a mode to the end; normally return the action without the mode --->
|
||||
<cfif arguments.shortaction>
|
||||
<cfreturn ListFirst(variables.cfpayment.gatewayAction, "_") />
|
||||
<cfelse>
|
||||
<cfreturn variables.cfpayment.gatewayAction />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
<cffunction name="setGatewayAction" access="public" output="false" returntype="void">
|
||||
<cfset variables.cfpayment.gatewayAction = arguments[1] />
|
||||
</cffunction>
|
||||
|
||||
<!--- override getGatewayURL to inject the extra URL method per gateway method --->
|
||||
<cffunction name="getGatewayURL" access="public" output="false" returntype="any" hint="">
|
||||
<cfset var gatewayURL=super.getGatewayURL()>
|
||||
<cfif structKeyExists(variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD, getGatewayAction(shortaction=false))>
|
||||
<cfset gatewayURL=gatewayURL & variables.cfpayment.SKIPJACK_GATEWAY_URL_METHOD[getGatewayAction(shortaction=false)]>
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid GatewayAction Specified" type="cfpayment.InvalidParameter.GatewayAction" />
|
||||
</cfif>
|
||||
<cfreturn gatewayURL>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!---
|
||||
|
||||
PARSE RESPONSE
|
||||
|
||||
--->
|
||||
<cffunction name="ParseResponse" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="Response" type="any" required="true"/>
|
||||
<cfset var ResponseMap="">
|
||||
<cfif ListFindNoCase("authorize", getGatewayAction())>
|
||||
<cfset ResponseMap=ParseAuthorizeResponse(argumentCollection=arguments)>
|
||||
<cfset arguments.Response.setAuthorization(ResponseMap.AuthCode)>
|
||||
<cfif structKeyExists(ResponseMap, "szTransactionFileName")>
|
||||
<cfset arguments.Response.setTransactionId(ResponseMap.szTransactionFileName)>
|
||||
<cfelseif structKeyExists(ResponseMap, "szTransactionId")>
|
||||
<cfset arguments.Response.setTransactionId(ResponseMap.szTransactionId)>
|
||||
</cfif>
|
||||
<!--- Skipjack will often return a zero AVS Response Code when the CVV fails, so we check for it and ignore it since it is an invalid value --->
|
||||
<cfif trim(ResponseMap.szAVSResponseCode) NEQ "0">
|
||||
<cfset arguments.Response.setAVSCode(ResponseMap.szAVSResponseCode)>
|
||||
</cfif>
|
||||
<cfset arguments.Response.setCVVCode(ResponseMap.szCVV2ResponseCode)>
|
||||
<cfelseif ListFindNoCase("recurring", getGatewayAction())>
|
||||
<cfif ListLast(getGatewayAction(shortaction=false), "_") eq "get">
|
||||
<cfset ResponseMap=ParseGetRecurringResponse(argumentCollection=arguments)>
|
||||
<cfelse>
|
||||
<cfset ResponseMap=ParseRecurringResponse(argumentCollection=arguments)>
|
||||
<cfif structKeyExists(ResponseMap, "RecurringPaymentId")>
|
||||
<cfset arguments.Response.setTransactionId(ResponseMap.RecurringPaymentId)>
|
||||
</cfif>
|
||||
</cfif>
|
||||
<cfelseif ListFindNoCase("capture,credit,void,newcharge", getGatewayAction())>
|
||||
<cfset ResponseMap=ParseChangeStatusResponse(argumentCollection=arguments)>
|
||||
<cfelseif ListFindNoCase("status", getGatewayAction())>
|
||||
<cfset ResponseMap=ParseGetTransactionStatusResponse(argumentCollection=arguments)>
|
||||
<cfelse>
|
||||
<!--- comment out cfdump for production --->
|
||||
<!--- <cfsavecontent variable="tmp"><cfdump var="#arguments.Response.getResult()#"></cfsavecontent> --->
|
||||
<cfthrow message="Invalid Logic to ParseResponse for #getGatewayAction()#" type="cfpayment.InvalidParameter.skipjack.GatewayAction" detail="#tmp#">
|
||||
</cfif>
|
||||
<!--- save the parsed result --->
|
||||
<cfset arguments.Response.setParsedResult(duplicate(ResponseMap))>
|
||||
<!--- set the status based on the success factor --->
|
||||
<cfif isStruct(ResponseMap) AND StructKeyExists(ResponseMap, "success") AND ResponseMap.success>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusSuccessful())>
|
||||
<cfelse>
|
||||
<cfif arguments.Response.getStatus() EQ getService().getStatusPending()>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusUnknown())>
|
||||
</cfif>
|
||||
</cfif>
|
||||
<!--- now parse any messages we need to return --->
|
||||
<cfset ParseMessage(arguments.response)>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="ParseMessage" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true"/>
|
||||
<cfset var ParsedResult=arguments.Response.getParsedResult()>
|
||||
<cfset var message="">
|
||||
<cfif ListFindNoCase("authorize", getGatewayAction())>
|
||||
<cfset message=ParseAuthorizeMessage(arguments.response)>
|
||||
<cfelse>
|
||||
<!--- generic message handling --->
|
||||
<cfif len(arguments.Response.getMessage())>
|
||||
<!--- don't change the message if it's already set (e.g. line 2 of response) --->
|
||||
<cfreturn>
|
||||
</cfif>
|
||||
<cfif arguments.Response.getSuccess()>
|
||||
<cfset message=variables.cfpayment.SKIPJACK_SUCCESS_MESSAGE>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusSuccessful())>
|
||||
<cfelseif StructKeyExists(ParsedResult, "ResponseCode") AND (ParsedResult.ResponseCode)>
|
||||
<cfif structKeyExists(variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES, ParsedResult.ResponseCode)>
|
||||
<cfset message=variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES[ParsedResult.ResponseCode]>
|
||||
<cfelse>
|
||||
<cfset message="Unknown Gateway ResponseCode">
|
||||
</cfif>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusFailure())>
|
||||
<!--- <cfthrow message="Invalid Logic to ParseMessage for #getGatewayAction()#" type="cfpayment.InvalidParameter.skipjack.GatewayAction"> --->
|
||||
<cfelse>
|
||||
<cfif structKeyExists(ParsedResult, "szAuthorizationDeclinedMessage") and (len(ParsedResult.szAuthorizationDeclinedMessage))>
|
||||
<cfset message=ParsedResult.szAuthorizationDeclinedMessage>
|
||||
<cfelse>
|
||||
<!--- <cfsavecontent variable="tmp"><cfdump var="#arguments.response.getMemento()#" label="response"></cfsavecontent><cfthrow detail="#tmp#"> --->
|
||||
<cfset message="Unknown Gateway Failure">
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cfif>
|
||||
<cfset arguments.Response.setMessage(message)>
|
||||
</cffunction>
|
||||
|
||||
<!---
|
||||
|
||||
AUTHORIZE
|
||||
|
||||
--->
|
||||
<cffunction name="ParseAuthorizeResponse" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true"/>
|
||||
<cfset var ResponseMap=MapAuthorizeResponse(arguments.response)>
|
||||
<cfset ResponseMap["success"]=StructKeyExists(ResponseMap, "szIsApproved") and (ResponseMap.szIsApproved EQ "1")>
|
||||
<!--- <cfdump var="#ResponseMap#" label="ResponseMap"><cfabort> --->
|
||||
<cfreturn ResponseMap />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="MapAuthorizeResponse" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true"/>
|
||||
<cfset var lines=SplitLines(arguments.Response.getResult())>
|
||||
<cfset var keys="">
|
||||
<cfset var values="">
|
||||
<cfset var ctr=0>
|
||||
<cfset var res=StructNew()>
|
||||
<cfif ArrayLen(lines) NEQ 2>
|
||||
<cfthrow message="Invalid Authorize Response Result" type="cfpayment.skipjack.InvalidResponseResult">
|
||||
</cfif>
|
||||
<cfset keys=SplitLine(lines[1])>
|
||||
<cfset values=SplitLine(lines[2])>
|
||||
<cfloop from="1" to="#ArrayLen(keys)#" index="ctr">
|
||||
<cfset res[keys[ctr]]=values[ctr]>
|
||||
</cfloop>
|
||||
<!--- <cfdump var="#lines#" label="lines"><cfdump var="#keys#" label="keys"><cfdump var="#values#" label="values"><cfdump var="#res#" label="res"><cfabort> --->
|
||||
<cfreturn res />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="ParseAuthorizeMessage" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true"/>
|
||||
<cfset var ret="">
|
||||
<cfset var ParsedResult=arguments.Response.getParsedResult()>
|
||||
<cfif arguments.Response.getSuccess()>
|
||||
<cfset ret=variables.cfpayment.SKIPJACK_SUCCESS_MESSAGE>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusSuccessful())>
|
||||
<!--- give error message priority to the szAuthorizationDeclinedMessage returned from skipjack --->
|
||||
<cfelseif StructKeyExists(ParsedResult, "szAuthorizationDeclinedMessage") and (len(ParsedResult.szAuthorizationDeclinedMessage))>
|
||||
<cfset ret=ParsedResult.szAuthorizationDeclinedMessage>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusFailure())>
|
||||
<!--- <cfelseif not arguments.Response.isValidCVV(AllowBlankCode=true)><!--- TODO: should these extra "allow" arguments be configurable --->
|
||||
<cfset ret="Security Code Error: " & arguments.Response.getCVVMessage()>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusFailure())>
|
||||
<cfelseif not arguments.Response.isValidAVS(AllowStreetOnlyMatch=true)><!--- TODO: should these extra "allow" arguments be configurable --->
|
||||
<cfset ret="Address Verification Error: " & arguments.Response.getAVSMessage()>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusFailure())> --->
|
||||
<cfelseif ParsedResult.szReturnCode>
|
||||
<cfset ret=variables.cfpayment.SKIPJACK_RETURN_CODE_MESSAGES[ParsedResult.szReturnCode]>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusFailure())>
|
||||
<cfelse>
|
||||
<cfset ret=ParsedResult.szAuthorizationDeclinedMessage>
|
||||
</cfif>
|
||||
<cfreturn ret>
|
||||
</cffunction>
|
||||
|
||||
<!---
|
||||
|
||||
RECURRING
|
||||
|
||||
--->
|
||||
<cffunction name="ParseRecurringResponse" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true"/>
|
||||
<cfset var ResponseMap=MapRecurringResponse(arguments.response)>
|
||||
<cfif arguments.response.getStatus() EQ getService().getStatusPending()>
|
||||
<cfset ResponseMap["success"]=StructKeyExists(ResponseMap, "ResponseCode") and (ResponseMap.ResponseCode EQ "0")>
|
||||
<cfelse>
|
||||
<cfset ResponseMap["success"]=false>
|
||||
</cfif>
|
||||
<cfreturn ResponseMap />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="MapRecurringResponse" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true"/>
|
||||
<cfset var lines=SplitLines(arguments.Response.getResult())>
|
||||
<cfset var keys="">
|
||||
<cfset var values="">
|
||||
<cfset var ctr=0>
|
||||
<cfset var numKeys=0>
|
||||
<cfset var numValues=0>
|
||||
<cfset var res=StructNew()>
|
||||
<cfif ArrayLen(lines) GTE 1 AND ArrayLen(lines) LTE 2>
|
||||
<cfset keys=variables.cfpayment.SKIPJACK_ADD_RECURRING_RESPONSE_COLUMN_HEADERS>
|
||||
<cfset values=SplitLine(lines[1])>
|
||||
<cfset numKeys=ArrayLen(keys)>
|
||||
<cfset numValues=ArrayLen(values)>
|
||||
<cfif numKeys eq numValues>
|
||||
<cfloop from="1" to="#numKeys#" index="ctr">
|
||||
<cfset res[keys[ctr]]=values[ctr]>
|
||||
</cfloop>
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid Recurring Response Result (keys/values)" type="cfpayment.skipjack.InvalidResponseResult">
|
||||
</cfif>
|
||||
<cfif ArrayLen(lines) EQ 2>
|
||||
<!--- extra message on line two --->
|
||||
<cfset arguments.response.setMessage(lines[2])>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusFailure())>
|
||||
</cfif>
|
||||
<cfelse>
|
||||
<!--- <cfsavecontent variable="tmp"><cfdump var="#lines#" label="lines"><cfdump var="#keys#" label="keys"><cfdump var="#values#" label="values"></cfsavecontent>
|
||||
<cfthrow message="Invalid Recurring Response Result" type="cfpayment.skipjack.InvalidResponseResult" detail="#tmp#"> --->
|
||||
<cfthrow message="Invalid Recurring Response Result" type="cfpayment.skipjack.InvalidResponseResult">
|
||||
</cfif>
|
||||
<!--- <cfdump var="#lines#" label="lines"><cfdump var="#keys#" label="keys"><cfdump var="#values#" label="values"> --->
|
||||
<cfreturn res />
|
||||
</cffunction>
|
||||
|
||||
<!---
|
||||
GET RECURRING
|
||||
--->
|
||||
<cffunction name="ParseGetRecurringResponse" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true" />
|
||||
<cfreturn MapGenericDataResponse(
|
||||
arguments.response,
|
||||
variables.cfpayment.SKIPJACK_GET_RECURRING_RESPONSE_COLUMN_HEADERS,
|
||||
variables.cfpayment.SKIPJACK_GET_RECURRING_RESPONSE_DATA_COLUMN_HEADERS
|
||||
) />
|
||||
</cffunction>
|
||||
|
||||
<!---
|
||||
GET CHANGE_STATUS
|
||||
--->
|
||||
<cffunction name="ParseChangeStatusResponse" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true" />
|
||||
<cfset var StatusResponseList="">
|
||||
<cfset var ResponseMap=MapGenericDataResponse(
|
||||
arguments.response,
|
||||
variables.cfpayment.SKIPJACK_CHANGE_STATUS_RESPONSE_COLUMN_HEADERS,
|
||||
variables.cfpayment.SKIPJACK_CHANGE_STATUS_RESPONSE_DATA_COLUMN_HEADERS
|
||||
) />
|
||||
<!--- do further processing to check for individual failures --->
|
||||
<cfif ResponseMap["success"]>
|
||||
<cfif structKeyExists(ResponseMap, "ResultDataQuery") and isQuery(ResponseMap.ResultDataQuery)>
|
||||
<cfset StatusResponseList=ValueList(ResponseMap.ResultDataQuery.StatusResponse)>
|
||||
<cfif ListFindNoCase(StatusResponseList, "UNSUCCESSFUL") OR ListFindNoCase(StatusResponseList, "NOT ALLOWED")>
|
||||
<cfset ResponseMap["success"]=false>
|
||||
<cfset arguments.Response.setMessage("The transaction succeeded, but one or more individual items failed.")>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusDeclined())>
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cfif>
|
||||
<cfreturn ResponseMap />
|
||||
</cffunction>
|
||||
|
||||
<!---
|
||||
GET TRANSACTION STATUS
|
||||
--->
|
||||
<cffunction name="ParseGetTransactionStatusResponse" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true" />
|
||||
<cfreturn MapGenericDataResponse(
|
||||
arguments.response,
|
||||
variables.cfpayment.SKIPJACK_TRANSACTION_STATUS_RESPONSE_COLUMN_HEADERS,
|
||||
variables.cfpayment.SKIPJACK_TRANSACTION_STATUS_RESPONSE_DATA_COLUMN_HEADERS
|
||||
) />
|
||||
</cffunction>
|
||||
|
||||
<!---
|
||||
|
||||
GENERIC RESPONSE DATA MAPPERS
|
||||
|
||||
--->
|
||||
<!--- the error message is actually on a second line, separated by chr(10)+chr(13)
|
||||
FROM: Skipjack Integration Guide.pdf, pp 87-97
|
||||
1. Status Record (Header Record) is the first record returned and contains information about the
|
||||
subsequent records.
|
||||
1 - HTML Serial Number
|
||||
2 - Error Code
|
||||
Response Error Code indicating success or error conditions.
|
||||
0 = Success
|
||||
-1 = Invalid Command
|
||||
-2 = Parameter Missing
|
||||
-3 = Failed retrieving response
|
||||
-4 = Invalid Status
|
||||
-5 = Failed reading security flags
|
||||
-6 = Developer serial number not found
|
||||
-7 = Invalid Serial Number
|
||||
3 - Number of records in the response
|
||||
|
||||
2. Response Record (Data Record) is the second and subsequent record(s) returned for
|
||||
successful transactions (szErrorCode=0) and includes transaction information described in
|
||||
the table below.
|
||||
An Error Record is returned as the third record only when an error condition exists
|
||||
(szErrorCode != 0). An Error Record contains a brief text description of the transaction error.
|
||||
|
||||
"123123123123","-6","","","","","","","","","",""
|
||||
Developer serialnumber doesn't match account.
|
||||
|
||||
"123123123123","-2","","","","","","","","","",""
|
||||
Parameter Missing: (szDeveloperSerialNumber)
|
||||
|
||||
**This is a successful, non-error return (for get transaction response):
|
||||
"123123123123","0","1","","","","","","","","",""
|
||||
"123123123123","100.0000","30","Settled","987987987987","08/22/07 23:55:15","11223344556677.103","123456","456456456456"
|
||||
--->
|
||||
<cffunction name="MapGenericDataResponse" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true" />
|
||||
<cfargument name="ResponseColumnHeaders" type="any" required="true" />
|
||||
<cfargument name="DataColumnHeaders" type="any" required="true" />
|
||||
<cfset var ResponseMap=MapGenericResponse(argumentCollection = arguments) />
|
||||
<cfif arguments.response.getStatus() EQ getService().getStatusPending()>
|
||||
<cfset ResponseMap["success"]=StructKeyExists(ResponseMap, "ResponseCode") and (ResponseMap.ResponseCode EQ "0")>
|
||||
<cfelse>
|
||||
<cfset ResponseMap["success"]=false>
|
||||
</cfif>
|
||||
<cfreturn ResponseMap />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="MapGenericResponse" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="Response" type="any" required="true"/>
|
||||
<cfargument name="ResponseColumnHeaders" type="any" required="true" />
|
||||
<cfargument name="DataColumnHeaders" type="any" required="true" />
|
||||
<cfset var lines=SplitLines(arguments.Response.getResult())>
|
||||
<cfset var keys="">
|
||||
<cfset var values="">
|
||||
<cfset var ctr=0>
|
||||
<cfset var numKeys=0>
|
||||
<cfset var numValues=0>
|
||||
<cfset var res=StructNew()>
|
||||
<cfset var dataArray="">
|
||||
<cfset var dataList="">
|
||||
<cfif ArrayLen(lines) GTE 1>
|
||||
<cfset keys=arguments.ResponseColumnHeaders>
|
||||
<cfset values=SplitLine(lines[1])>
|
||||
<cfset numKeys=ArrayLen(keys)>
|
||||
<cfset numValues=ArrayLen(values)>
|
||||
<cfif numKeys eq numValues>
|
||||
<cfloop from="1" to="#numKeys#" index="ctr">
|
||||
<cfset res[keys[ctr]]=values[ctr]>
|
||||
</cfloop>
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid Response Result (keys/values=#numKeys#/#numValues#)" detail="#lines.toString()#" type="cfpayment.skipjack.InvalidResponseResult">
|
||||
</cfif>
|
||||
<cfif StructKeyExists(res, "NumberOfRecords") and (isNumeric(res.NumberOfRecords)) and (res.NumberOfRecords GT 0)>
|
||||
<!--- successful return: map out returned data records --->
|
||||
<!--- save to the result structure --->
|
||||
<cfset dataArray=duplicate(lines)>
|
||||
<!--- remove the first line from the lines array --->
|
||||
<cfset ArrayDeleteAt(dataArray, 1)>
|
||||
<!--- append the column names as the first row --->
|
||||
<cfset ArrayPrepend(dataArray, arguments.DataColumnHeaders)>
|
||||
<!--- convert to a list for passing to CSVtoQuery function --->
|
||||
<cfset dataList=ArrayToList(dataArray, chr(10))>
|
||||
<!--- convert to a query --->
|
||||
<!--- <cfsavecontent variable="tmp"><cfdump var="#variables.cfpayment.csvutils.CSVtoQuery(CSV=dataList, FirstRowColumnNames=true, trim=true, trimData=true)#"></cfsavecontent><cfthrow message="Invalid Response Result (keys/values)" type="cfpayment.skipjack.InvalidResponseResult" detail="#tmp#"> --->
|
||||
<cfset res.ResultDataQuery=variables.cfpayment.csvutils.CSVtoQuery(CSV=dataList, FirstRowColumnNames=true, trim=true, trimData=true)>
|
||||
<cfset res.ResultDataArray=duplicate(dataArray)>
|
||||
<!--- if the result of this request returns a single record, see if there is an audit id; if so, set the response transaction id value to it (e.g. during a credit/newcharge call) --->
|
||||
<cfif (res.ResultDataQuery.RecordCount EQ 1)>
|
||||
<!--- change status request returns AuditId --->
|
||||
<cfif ListFindNoCase(res.ResultDataQuery.ColumnList, "AuditID") AND len(res.ResultDataQuery.AuditID)>
|
||||
<cfset arguments.Response.setTransactionId(res.ResultDataQuery.AuditID)>
|
||||
<!--- get trans status request returns TransactionId --->
|
||||
<cfelseif ListFindNoCase(res.ResultDataQuery.ColumnList, "TransactionID") AND len(res.ResultDataQuery.TransactionID)>
|
||||
<cfset arguments.Response.setTransactionId(res.ResultDataQuery.TransactionID)>
|
||||
</cfif>
|
||||
</cfif>
|
||||
<cfelseif StructKeyExists(res, "ResponseCode") and (res.ResponseCode NEQ "0") AND (ArrayLen(lines) EQ 2)>
|
||||
<!--- extra message on line two --->
|
||||
<cfset arguments.response.setMessage(lines[2])>
|
||||
<cfset arguments.Response.setStatus(getService().getStatusFailure())>
|
||||
</cfif>
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid Response Result" type="cfpayment.skipjack.InvalidResponseResult">
|
||||
</cfif>
|
||||
<!--- <cfdump var="#lines#" label="lines"><cfdump var="#keys#" label="keys"><cfdump var="#values#" label="values"> --->
|
||||
<cfreturn res />
|
||||
</cffunction>
|
||||
|
||||
<!---
|
||||
|
||||
HELPER FUNCTIONS
|
||||
|
||||
--->
|
||||
<cffunction name="SplitLines" output="false" access="private" returntype="any" hint="Split result lines on carriage return/line feed character. Returns an array of strings.">
|
||||
<cfargument name="lines" type="string" required="true"/>
|
||||
<!--- normalize EOL character --->
|
||||
<cfset var modlines=replace(replace(arguments.lines, "#chr(13)##chr(10)#", chr(10), "ALL"), chr(13), chr(10), "ALL")>
|
||||
<!--- <cfreturn javacast("string", arguments.lines).split("\n")> ---><!--- \r\n --->
|
||||
<cfreturn ListToArray(arguments.lines, chr(10))><!--- \r\n --->
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="SplitLine" output="false" access="private" returntype="any" hint="Split a csv line on double-quote and commas. Returns an array of strings.">
|
||||
<cfargument name="line" type="string" required="true"/>
|
||||
<cfset var modline=javacast("string", arguments.line).trim()>
|
||||
<cfset var lineLen=ListLen(modline)>
|
||||
<!--- change delimiter to char 9 --->
|
||||
<cfset modline=modline.replace(""",""", chr(9))>
|
||||
<!--- remove beginning and ending double-quotes --->
|
||||
<cfset modline=modline.substring(1, modline.length()-1)>
|
||||
<!--- split on the char 9 and return (use lineLen to include possible trailing empty values) --->
|
||||
<cfreturn modline.split(chr(9), lineLen)>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
515
cfpayment/api/gateway/skipjack/skipjack_cc.cfc
Normal file
515
cfpayment/api/gateway/skipjack/skipjack_cc.cfc
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2008 Mark Mazelin (http://www.mkville.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.
|
||||
|
||||
UPDATES:
|
||||
3-FEB-2009-MBM: added check for order_id and szNewOrderNumber to payload in newcharge() method
|
||||
--->
|
||||
<cfcomponent displayname="SkipJack Credit Card Object" extends="skipjack" hint="Used for processing credit card payments via SkipJack" output="false">
|
||||
|
||||
<cffunction name="getIsCCEnabled" access="public" output="false" returntype="boolean">
|
||||
<cfreturn true />
|
||||
</cffunction>
|
||||
|
||||
<!--- implement primary methods --->
|
||||
<cffunction name="authorize" output="false" access="public" returntype="any" hint="Perform an authorization immediately followed by a capture/settle">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" /><!--- credit card or eft object --->
|
||||
<cfargument name="options" type="struct" default="#StructNew()#" />
|
||||
<cfset var payload = StructNew() />
|
||||
<cfset setGatewayAction("authorize") />
|
||||
|
||||
<!--- check for required options --->
|
||||
<cfset VerifyRequiredOptions(arguments.options, "email,order_id") />
|
||||
|
||||
<!--- setup payload --->
|
||||
<cfset addInvoice(payload, arguments.options) />
|
||||
<cfset addCreditCard(payload, arguments.account) />
|
||||
<cfset addAddress(payload, arguments.options, arguments.account) />
|
||||
<cfset addCustomerData(payload, arguments.options) />
|
||||
<cfset addUserDefined(payload, arguments.options) />
|
||||
<cfset addMisc(payload, arguments.options) />
|
||||
<cfset addCredentials(payload, arguments.options) />
|
||||
<cfset addAmount(payload, arguments.money) />
|
||||
<cfreturn process(payload=payload, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="capture" access="public" output="false" returntype="any" hint="Confirms an authorization with direction to charge the account">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="authorization" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" default="#StructNew()#" />
|
||||
<cfset var payload = StructNew() />
|
||||
<cfset setGatewayAction("capture") />
|
||||
|
||||
<cfset addStatusAction(payload, variables.cfpayment.SKIPJACK_CHANGE_STATUS_SETTLE) />
|
||||
<cfset addForcedSettlement(payload, arguments.options) />
|
||||
<cfset addTransactionId(payload, arguments.authorization) />
|
||||
<cfset addCredentials(payload, arguments.options) />
|
||||
<cfset addAmount(payload, arguments.money) />
|
||||
|
||||
<cfreturn process(payload=payload, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="credit" access="public" output="false" returntype="any" hint="Returns an amount back to the previously charged account. Only for use with captured transactions.">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="identification" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" default="#StructNew()#" />
|
||||
<cfset var payload = StructNew() />
|
||||
<cfset setGatewayAction("credit") />
|
||||
|
||||
<cfset addStatusAction(payload, variables.cfpayment.SKIPJACK_CHANGE_STATUS_CREDIT) />
|
||||
<cfset addForcedSettlement(payload, arguments.options) />
|
||||
<cfset addTransactionId(payload, arguments.identification) />
|
||||
<cfset addCredentials(payload, arguments.options) />
|
||||
<cfset addAmount(payload, arguments.money) />
|
||||
|
||||
<cfreturn process(payload=payload, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="newcharge" access="public" output="false" returntype="any" hint="">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="identification" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" default="#StructNew()#" />
|
||||
<cfset var payload = StructNew() />
|
||||
<cfset setGatewayAction("newcharge") />
|
||||
|
||||
<!--- check for required options --->
|
||||
<cfset VerifyRequiredOptions(arguments.options, "order_id") /><!--- if order_id not passed, it will default to "1", which is likely undesireable--->
|
||||
|
||||
<cfset addInvoice(payload, arguments.options) />
|
||||
<cfset addStatusAction(payload, variables.cfpayment.SKIPJACK_CHANGE_STATUS_NEWCHARGE) />
|
||||
<cfset addForcedSettlement(payload, arguments.options) />
|
||||
<cfset addTransactionId(payload, arguments.identification) />
|
||||
<cfset addCredentials(payload, arguments.options) />
|
||||
<cfset addAmount(payload, arguments.money) />
|
||||
|
||||
<cfreturn process(payload=payload, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="purchase" output="false" access="public" returntype="any" hint="Perform an authorization immediately followed by a capture/settle">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="true" /><!--- credit card or eft object --->
|
||||
<cfargument name="options" type="struct" default="#StructNew()#" />
|
||||
<cfset var response = "" />
|
||||
|
||||
<cfset response = authorize(argumentCollection=arguments) />
|
||||
|
||||
<cfif response.getSuccess()>
|
||||
<cfset response = capture(arguments.money, response.getTransactionId(), arguments.options) />
|
||||
</cfif>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="recurring" output="false" access="public" returntype="any" hint="Perform an add/edit recurring transaction">
|
||||
<cfargument name="mode" type="any" required="true" /><!--- must be one of: add, edit, delete, get --->
|
||||
<cfargument name="money" type="any" required="false" />
|
||||
<cfargument name="account" type="any" required="false" /><!--- credit card or eft object --->
|
||||
<cfargument name="options" type="struct" default="#StructNew()#" />
|
||||
<cfset var payload = StructNew() />
|
||||
<cfset setGatewayAction("recurring") />
|
||||
|
||||
<!--- setup payload --->
|
||||
<cfif ListFindNoCase("add,edit", arguments.mode)>
|
||||
<cfif not StructKeyExists(arguments, "money")>
|
||||
<cfthrow message="Money is a required parameter." type="cfpayment.MissingParameter.Money">
|
||||
</cfif>
|
||||
<cfif not StructKeyExists(arguments, "account")>
|
||||
<cfthrow message="Account is a required parameter." type="cfpayment.MissingParameter.Account">
|
||||
</cfif>
|
||||
<!--- check for required options --->
|
||||
<cfset VerifyRequiredOptions(arguments.options, "email,order_id") />
|
||||
<!--- populate the payload --->
|
||||
<cfset addInvoice(payload, arguments.options) />
|
||||
<cfset addCreditCard(payload, arguments.account) />
|
||||
<cfset addAddress(payload, arguments.options, arguments.account) />
|
||||
<cfset addCustomerData(payload, arguments.options) />
|
||||
<cfset addUserDefined(payload, arguments.options) />
|
||||
<cfset addMisc(payload, arguments.options) />
|
||||
<cfset addCredentials(payload, arguments.options) />
|
||||
<cfset addAmount(payload, arguments.money) />
|
||||
<cfset addRecurringFields(payload, arguments.mode, arguments.options) />
|
||||
<cfelseif ListFindNoCase("delete,get", arguments.mode)>
|
||||
<!--- populate the payload --->
|
||||
<cfset addCredentials(payload, arguments.options) />
|
||||
<cfset addRecurringFields(payload, arguments.mode, arguments.options) />
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid Recurring Mode Logic" type="cfpayment">
|
||||
</cfif>
|
||||
|
||||
<!--- append the mode to the gateway action so we can get at the proper gateway url --->
|
||||
<cfset setGatewayAction("recurring_#arguments.mode#") />
|
||||
<cfreturn process(payload=payload, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="status" access="public" output="false" returntype="any" hint="Reconstruct a response object for a previously executed transaction">
|
||||
<cfargument name="transactionid" type="any" required="true" /><!--- in SkipJack, this is actually the application-generated unique order number --->
|
||||
<cfargument name="options" type="struct" required="false" />
|
||||
<cfset var payload = StructNew() />
|
||||
<cfset setGatewayAction("status") />
|
||||
|
||||
<cfset payload["szOrderNumber"]=arguments.transactionid>
|
||||
<!--- also allow the transaction date to be passed in --->
|
||||
<cfif isDate(GetOption(arguments.options, "transaction_date"))>
|
||||
<!--- format should be mm/dd/yyyy --->
|
||||
<cfset payload["szDate"]=DateFormat(GetOption(arguments.options, "transaction_date"), "mm/dd/yyyy")>
|
||||
</cfif>
|
||||
<cfset addCredentials(payload, arguments.options) />
|
||||
<cfreturn process(payload=payload, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="void" access="public" output="false" returntype="any" hint="Cancels a previously captured transaction that has not yet settled">
|
||||
<cfargument name="authorization" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" default="#StructNew()#" />
|
||||
<cfset var payload = StructNew() />
|
||||
<cfset setGatewayAction("void") />
|
||||
|
||||
<cfset addStatusAction(payload, variables.cfpayment.SKIPJACK_CHANGE_STATUS_DELETE) />
|
||||
<cfset addForcedSettlement(payload, arguments.options) />
|
||||
<cfset addTransactionId(payload, arguments.authorization) />
|
||||
<cfset addCredentials(payload, arguments.options) />
|
||||
|
||||
<cfreturn process(payload=payload, options=arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!---
|
||||
|
||||
PRIVATE METHODS
|
||||
|
||||
--->
|
||||
<cffunction name="addInvoice" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="options" type="any" required="true"/>
|
||||
<cfset var ctr = 0 />
|
||||
<cfset var currOrder = "" />
|
||||
<cfset var orderStr = "" />
|
||||
<cfif ListFindNoCase("authorize", getGatewayAction())>
|
||||
<cfset arguments.payload["ordernumber"]=GetOption(arguments.options, "order_id") />
|
||||
<cfset arguments.payload["customercode"]=GetOption(arguments.options, "Customer") />
|
||||
<cfset arguments.payload["invoicenumber"]=GetOption(arguments.options, "Invoice") />
|
||||
<cfset arguments.payload["orderdescription"]=GetOption(arguments.options, "Description") />
|
||||
<cfif StructKeyExists(arguments.options, "Order")>
|
||||
<cfif isArray(arguments.options.order)>
|
||||
<!--- array of structs --->
|
||||
<cfset arguments.payload["orderstring"]="" />
|
||||
<cfloop from="1" to="#ArrayLen(arguments.options.order)#" index="ctr">
|
||||
<!---
|
||||
==Order Keys==
|
||||
* Required *
|
||||
SKU (ItemNumber)
|
||||
Description (ItemDescription)
|
||||
DeclaredValue (ItemCost)
|
||||
Quantity
|
||||
Taxable (Y/N)
|
||||
* Optional *
|
||||
UnitOfMeasure
|
||||
ItemDiscount
|
||||
ExtendedAmount
|
||||
CommodityCode
|
||||
VatTaxAmount
|
||||
VatTaxRate
|
||||
AlternateTaxAmount
|
||||
TaxRate
|
||||
TaxType
|
||||
TaxAmount
|
||||
--->
|
||||
<cfset currOrder = arguments.options.order[ctr] />
|
||||
<cfif isStruct(currOrder)>
|
||||
<cftry>
|
||||
<cfset orderStr="">
|
||||
<cfset orderStr=ListAppend(orderStr, currOrder.sku, "~") />
|
||||
<cfset orderStr=ListAppend(orderStr, replace(currOrder.description, "~", "_", "ALL"), "~") />
|
||||
<cfset orderStr=ListAppend(orderStr, currOrder.declaredValue, "~") />
|
||||
<cfset orderStr=ListAppend(orderStr, currOrder.quantity, "~") />
|
||||
<cfset orderStr=ListAppend(orderStr, currOrder.taxable, "~") />
|
||||
<!--- <cfset orderStr=ListAppend(orderStr, currOrder.taxRate, "~")> --->
|
||||
<cfset arguments.payload["orderstring"]=ListAppend(arguments.payload["orderstring"], orderStr, "||") />
|
||||
<cfcatch>
|
||||
<cfthrow message="Invalid OrderStruct" type="cfpayment.InvalidParameter.OrderStruct" />
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid OrderArray" type="cfpayment.InvalidParameter.OrderArray" />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
<cfelse>
|
||||
<!--- simple string --->
|
||||
<cfset arguments.payload["orderstring"]=arguments.options.order />
|
||||
</cfif>
|
||||
<cfelse>
|
||||
<cfset arguments.payload["orderstring"]=variables.cfpayment.SKIPJACK_ORDER_STRING_DUMMY_VALUES />
|
||||
</cfif>
|
||||
<cfelseif ListFindNoCase("recurring", getGatewayAction())>
|
||||
<!--- required fields --->
|
||||
<cfset arguments.payload["rtOrderNumber"]=GetOption(arguments.options, "order_id") />
|
||||
<cfset arguments.payload["rtItemNumber"]=GetOption(arguments.options, "ItemNumber") />
|
||||
<cfset arguments.payload["rtItemDescription"]=GetOption(arguments.options, "ItemDescription") />
|
||||
<cfelseif ListFindNoCase("newcharge", getGatewayAction())>
|
||||
<cfset arguments.payload["szNewOrderNumber"]=GetOption(arguments.options, "order_id") />
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid GatewayAction Logic in AddInvoice" type="cfpayment.InvalidParameter" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addAddress" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="options" type="any" required="true"/>
|
||||
<cfargument name="account" type="any" required="true"/>
|
||||
<cfset var address = "" />
|
||||
<cfset var billing_address = "" />
|
||||
<cfset var shipping_address = "" />
|
||||
<!---
|
||||
There are 3 different addresses you can use. There are billing_address, shipping_address, or you can
|
||||
just pass in address and it will be used for both. This is the common pattern to use for the address:
|
||||
|
||||
if billing_address is passed, use that for billing_address, otherwise use address
|
||||
if shipping_address is passed, use that for shipping_address, otherwise use billing_address
|
||||
|
||||
Address Structure - The address is a structure with the following keys:
|
||||
* name
|
||||
* company
|
||||
* address1
|
||||
* address2
|
||||
* city
|
||||
* state
|
||||
* country
|
||||
* postalcode
|
||||
* phone
|
||||
--->
|
||||
<cfif StructKeyExists(arguments.options, "billing_address")>
|
||||
<cfset billing_address = arguments.options.billing_address />
|
||||
<cfelse>
|
||||
<cfif StructKeyExists(arguments.options, "address")>
|
||||
<cfset billing_address = arguments.options.address />
|
||||
<cfelse>
|
||||
<cfthrow message="Missing Address Structure" type="cfpayment.MissingParameter.Address" />
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<!--- note: name gets set in the addCreditCard() method --->
|
||||
<cfif getGatewayAction() eq "recurring">
|
||||
<cfset arguments.payload["rtAddress1"] = getOption(billing_address, "address1") />
|
||||
<cfset arguments.payload["rtAddress2"] = getOption(billing_address, "address2") />
|
||||
<cfset arguments.payload["rtCity"] = getOption(billing_address, "city") />
|
||||
<cfset arguments.payload["rtState"] = getOption(billing_address, "state") />
|
||||
<cfset arguments.payload["rtPostalcode"] = getOption(billing_address, "postalcode") />
|
||||
<cfset arguments.payload["rtCountry"] = getOption(billing_address, "country") />
|
||||
<cfset arguments.payload["rtPhone"] = getOption(billing_address, "phone") />
|
||||
<cfelse>
|
||||
<cfset arguments.payload["streetaddress"] = getOption(billing_address, "address1") />
|
||||
<cfset arguments.payload["streetaddress2"] = getOption(billing_address, "address2") />
|
||||
<cfset arguments.payload["city"] = getOption(billing_address, "city") />
|
||||
<cfset arguments.payload["state"] = getOption(billing_address, "state") />
|
||||
<cfset arguments.payload["zipcode"] = getOption(billing_address, "postalcode") />
|
||||
<cfset arguments.payload["country"] = getOption(billing_address, "country") />
|
||||
<cfset arguments.payload["phone"] = getOption(billing_address, "phone") />
|
||||
<cfif StructKeyExists(arguments.options, "shipping_address")>
|
||||
<cfset arguments.payload["shipToName"] = getOption(arguments.options.shipping_address, "name") />
|
||||
<cfset arguments.payload["shipToStreetaddress"] = getOption(arguments.options.shipping_address, "address1") />
|
||||
<cfset arguments.payload["shipToCity"] = getOption(arguments.options.shipping_address, "city") />
|
||||
<cfset arguments.payload["shipToState"] = getOption(arguments.options.shipping_address, "region") />
|
||||
<cfset arguments.payload["shipToZipcode"] = getOption(arguments.options.shipping_address, "postalcode") />
|
||||
<cfset arguments.payload["shipToCountry"] = getOption(arguments.options.shipping_address, "country") />
|
||||
<cfset arguments.payload["shipToPhone"] = getOption(arguments.options.shipping_address, "phone") />
|
||||
</cfif>
|
||||
<!--- skipjack requires shiptophone to be sent --->
|
||||
<cfif (not structKeyExists(arguments.payload, "shipToPhone")) and (structKeyExists(arguments.payload, "phone"))>
|
||||
<cfset arguments.payload["shipToPhone"] = arguments.payload["phone"] />
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addCustomerData" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="options" type="any" required="true"/>
|
||||
<cfif ListFindNoCase("authorize", getGatewayAction())>
|
||||
<cfset arguments.payload["email"]=arguments.options.Email />
|
||||
<cfelseif getGatewayAction() eq "recurring">
|
||||
<cfset arguments.payload["rtEmail"]=arguments.options.Email />
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid GatewayAction Logic in AddCustomerData" type="cfpayment.InvalidParameter" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addMisc" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="options" type="any" required="true"/>
|
||||
<cfif getGatewayAction() eq "recurring">
|
||||
<cfset arguments.payload["rtComment"]=getOption(arguments.options, "Comment") />
|
||||
<cfelse>
|
||||
<cfset arguments.payload["comment"]=getOption(arguments.options, "Comment") />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addAmount" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="money" type="any" required="true"/>
|
||||
<cfif ListFindNoCase("authorize", getGatewayAction())>
|
||||
<cfset arguments.payload["transactionamount"]=arguments.money.getAmount() />
|
||||
<cfelseif getGatewayAction() eq "recurring">
|
||||
<cfset arguments.payload["rtAmount"]=arguments.money.getAmount() />
|
||||
<cfelse>
|
||||
<cfset arguments.payload["szAmount"]=arguments.money.getAmount() />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addCredentials" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="options" type="any" required="true"/>
|
||||
<cfif ListFindNoCase("authorize", getGatewayAction())>
|
||||
<cfset arguments.payload["Serialnumber"]=getMerchantAccount() />
|
||||
<cfelse>
|
||||
<cfset arguments.payload["szSerialNumber"]=getMerchantAccount() />
|
||||
</cfif>
|
||||
<cfif ListFindNoCase("recurring,capture,void,credit,newcharge,status", getGatewayAction())>
|
||||
<cfset arguments.payload["szDeveloperSerialNumber"] = getOption(arguments.options, "DeveloperSerialNumber") />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addStatusAction" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="statusAction" type="any" required="true"/>
|
||||
<cfset arguments.payload["szDesiredStatus"]=arguments.statusAction />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addTransactionId" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="transactionId" type="any" required="true"/>
|
||||
<cfset arguments.payload["szTransactionId"]=arguments.transactionId />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addForcedSettlement" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="options" type="any" required="true"/>
|
||||
<cfif len(GetOption(arguments.options, "force_settlement"))>
|
||||
<cfset arguments.payload["szForceSettlement"]=GetOption(arguments.options, "force_settlement") />
|
||||
<cfelse>
|
||||
<cfset arguments.payload["szForceSettlement"]="0" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addUserDefined" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="options" type="any" required="true"/>
|
||||
<cfset var keylist = "" />
|
||||
<cfset var key = "" />
|
||||
<cfset var udfStruct = StructNew() />
|
||||
<!--- User-Defined Data --->
|
||||
<!---
|
||||
NOTE: For SkiJack reporting purposes, these must be put in the same order each-and-every time. Note that SkipJack will report
|
||||
the values in REVERSE order of how they are specified via the cfhttpparam tags, so the order here must be the reverse
|
||||
of what we actually want later. To assure the order, we will create a separate structure under the payload key and pass
|
||||
the _keylist along. The base.process() method will check for a structure vs. simple value and for the _keylist and
|
||||
assure that they will go in the order specified in the _keylist.
|
||||
--->
|
||||
<cfif structKeyExists(arguments.options, "UserDefined") and isStruct(arguments.options.UserDefined)>
|
||||
<cfset udfStruct=StructCopy(arguments.options.UserDefined)>
|
||||
<!--- user defined fields will show up in reverse order of how they are output in the http params section --->
|
||||
<cfif NOT structKeyExists(arguments.options.UserDefined, "_KeyList")>
|
||||
<!--- alphabetize the keys for consistency --->
|
||||
<cfset udfStruct._keylist=ListSort(StructKeyList(udfStruct), "textnocase", "asc") />
|
||||
</cfif>
|
||||
<!--- put in reverse alpha-order so they show up in alpha order in the skipjack admin --->
|
||||
<cfset udfStruct._keylist=ListReverse(udfStruct._keylist)>
|
||||
<!--- add to the payload (note that this key won't actually get output anywhere) --->
|
||||
<cfset arguments.payload["USERDEFINED"]=StructCopy(udfStruct) />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addCreditCard" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="account" type="any" required="true"/>
|
||||
<cfif getGatewayAction() eq "recurring">
|
||||
<cfset arguments.payload["rtAccountnumber"]=arguments.account.getAccount() />
|
||||
<cfset arguments.payload["rtExpMonth"]=arguments.account.getMonth() />
|
||||
<cfset arguments.payload["rtExpYear"]=arguments.account.getYear() />
|
||||
<cfset arguments.payload["rtName"]=arguments.account.getName() />
|
||||
<cfelse>
|
||||
<cfset arguments.payload["accountnumber"]=arguments.account.getAccount() />
|
||||
<cfset arguments.payload["month"]=arguments.account.getMonth() />
|
||||
<cfset arguments.payload["year"]=arguments.account.getYear() />
|
||||
<cfset arguments.payload["cvv2"]=arguments.account.getVerificationValue() />
|
||||
<cfset arguments.payload["sjName"]=arguments.account.getName() />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="addRecurringFields" output="false" access="private" returntype="void" hint="">
|
||||
<cfargument name="payload" type="any" required="true"/>
|
||||
<cfargument name="mode" type="any" required="true"/>
|
||||
<cfargument name="options" type="any" required="true"/>
|
||||
<cfif ListFindNoCase("add", arguments.mode)>
|
||||
<cfset arguments.payload["rtStartingDate"] = getOption(arguments.options, "StartingDate") />
|
||||
<!--- frequency is stored as a normalized option named "periodicity" --->
|
||||
<cfset arguments.payload["rtFrequency"] = getPeriodicityValue(getOption(arguments.options, "Periodicity")) />
|
||||
<cfset arguments.payload["rtTotalTransactions"] = getOption(arguments.options, "TotalTransactions") />
|
||||
<cfelseif ListFindNoCase("edit,delete,get", arguments.mode)>
|
||||
<cfset arguments.payload["szPaymentId"] = getOption(arguments.options, "PaymentId") />
|
||||
<!---
|
||||
NOTE for edit:
|
||||
If this variable is supplied, only the individual transaction within a Recurring Payment record schedule will be edited.
|
||||
If this variable is NOT SUPPLIED, the payment is globally edited for ALL
|
||||
|
||||
NOTE for delete:
|
||||
Including the szTransactionDate variable in the request will ONLY DELETE the individual
|
||||
transaction matching the specified date within this Recurring Payment schedule.
|
||||
|
||||
NOTE for get:
|
||||
If this variable is sent in the request all transactions will be retrieved for the individual Recurring
|
||||
Payment. If this variable is not sent, all Recurring Payments for the Merchant will be returned.
|
||||
--->
|
||||
<cfset arguments.payload["szTransactionDate"] = getOption(arguments.options, "TransactionDate") />
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid Mode Logic in addRecurringFields" type="cfpayment.InvalidParameter" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cfscript>
|
||||
/**
|
||||
* Reverses a list.
|
||||
* Modified by RCamden to use var scope
|
||||
*
|
||||
* @param list List to be modified.
|
||||
* @param delimiter Delimiter for the list. Defaults to a comma.
|
||||
* @return Returns a list.
|
||||
* @author Stephen Milligan (spike@spike.org.uk)
|
||||
* @version 2, July 17, 2001
|
||||
*/
|
||||
function ListReverse(list) {
|
||||
|
||||
var newlist = "";
|
||||
var i = 0;
|
||||
var delims = "";
|
||||
var thisindex = "";
|
||||
var thisitem = "";
|
||||
|
||||
var argc = ArrayLen(arguments);
|
||||
if (argc EQ 1) {
|
||||
ArrayAppend(arguments,',');
|
||||
}
|
||||
delims = arguments[2];
|
||||
while (i LT listlen(list,delims))
|
||||
{
|
||||
thisindex = listlen(list,delims)-i;
|
||||
thisitem = listgetat(list,thisindex,delims);
|
||||
newlist = listappend(newlist,thisitem,delims);
|
||||
i = i +1;
|
||||
}
|
||||
return newlist;
|
||||
}
|
||||
</cfscript>
|
||||
|
||||
</cfcomponent>
|
||||
502
cfpayment/api/gateway/skipjack/tests/skipjacktest.cfc
Normal file
502
cfpayment/api/gateway/skipjack/tests/skipjacktest.cfc
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2008 Mark Mazelin (http://www.mkville.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 name="skipjacktest" extends="mxunit.framework.TestCase" output="false">
|
||||
|
||||
<!--- shared variables --->
|
||||
<cfset svc="">
|
||||
<cfset gw="">
|
||||
<cfset testdata="">
|
||||
<cfset gwParams = "" />
|
||||
|
||||
<cffunction name="setUp" returntype="void" access="public" output="false">
|
||||
<cftry>
|
||||
<!--- create a config that is not in svn --->
|
||||
<cfset gwParams = createObject("component", "cfpayment.localconfig.config").init() />
|
||||
<cfcatch>
|
||||
<!--- if gwParams doesn't exist (or otherwise bombs), create a generic structure with blank values --->
|
||||
<cfset gwParams = StructNew() />
|
||||
<cfset gwParams.Path = "skipjack.skipjack_cc" />
|
||||
<cfset gwParams.MerchantAccount = "" /><!--- skipjack html serial number --->
|
||||
<cfset gwParams.DeveloperSerialNumber = "" /><!--- skipjack-assigned serial number (sign up for a developer account) --->
|
||||
<!--- username and password only used for reporting in SkipJack --->
|
||||
<cfset gwParams.userName = "" />
|
||||
<cfset gwParams.password = "" />
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
<cfset svc = createObject("component", "cfpayment.api.core") />
|
||||
|
||||
<!--- create gw and get reference --->
|
||||
<cfset svc.init(gwParams) />
|
||||
<cfset gw = svc.getGateway() />
|
||||
|
||||
<!--- test data for skipjack development --->
|
||||
<cfset testdata=StructNew() />
|
||||
<cfset testdata.visa_card_number = "4445999922225" />
|
||||
<cfset testdata.visa_cvv2 = "999" />
|
||||
<cfset testdata.mastercard_card_number = "5499990123456781" />
|
||||
<cfset testdata.mastercard_cvv2 = "" />
|
||||
<cfset testdata.discover_card_number = "6011000999314523" />
|
||||
<cfset testdata.discover_cvv2 = "767" /><!--- 11/07, $1, 2500 Main Street, Anywhere, IL 60015 --->
|
||||
</cffunction>
|
||||
|
||||
<!--- <cffunction name="testParseAuthorizeResponse" output="false" access="public" returntype="any" hint="">
|
||||
<cfset var response="">
|
||||
<!--- add a generic result to the response object --->
|
||||
<cfset var result="">
|
||||
|
||||
<!--- these methods are private, so use mxunit to make it public for testing --->
|
||||
<cfset makePublic(gw, "ParseResponse", "ParseResponsePub") />
|
||||
<cfset makePublic(gw, "getMerchantAccount", "getMerchantAccountPub") />
|
||||
<cfset makePublic(gw, "setGatewayAction", "setGatewayActionPub") />
|
||||
|
||||
<!--- "-68" is an empty city error --->
|
||||
<cfset response=svc.createResponse()>
|
||||
<cfsavecontent variable="result"><cfoutput>"AUTHCODE","szSerialNumber","szTransactionAmount","szAuthorizationDeclinedMessage","szAVSResponseCode","szAVSResponseMessage","szOrderNumber","szAuthorizationResponseCode","szIsApproved","szCVV2ResponseCode","szCVV2ResponseMessage","szReturnCode","szTransactionFileName","szCAVVResponseCode"
|
||||
"EMPTY","#gw.getMerchantAccountPub()#","9666","","","","0506543597","","0","","","-68","",""</cfoutput></cfsavecontent>
|
||||
<cfset response.setResult(result)>
|
||||
<cfset gw.setGatewayActionPub("Authorize")>
|
||||
<cfset debug(gw.getMemento())>
|
||||
<cfset gw.ParseResponsePub(response)>
|
||||
<cfset debug(response.getMemento())>
|
||||
<cfset assertEquals(response.getMessage(), "Error empty city", "ParseAuthorizeResponse returned the wrong message for a missing city error.") />
|
||||
|
||||
<!--- "-82" is an empty state error --->
|
||||
<cfset response=svc.createResponse()>
|
||||
<cfsavecontent variable="result"><cfoutput>"AUTHCODE","szSerialNumber","szTransactionAmount","szAuthorizationDeclinedMessage","szAVSResponseCode","szAVSResponseMessage","szOrderNumber","szAuthorizationResponseCode","szIsApproved","szCVV2ResponseCode","szCVV2ResponseMessage","szReturnCode","szTransactionFileName","szCAVVResponseCode"
|
||||
"EMPTY","#gw.getMerchantAccount()#","2026","","","","1154213758","","0","","","-82","",""</cfoutput></cfsavecontent>
|
||||
<cfset response.setResult(result)>
|
||||
<cfset gw.setGatewayAction("Authorize")>
|
||||
<cfset gw.ParseResponse(response)>
|
||||
<cfset debug(response.getMemento())>
|
||||
<cfset assertEquals(response.getMessage(), "Length or value state", "ParseAuthorizeResponse returned the wrong message for a missing state error.") />
|
||||
</cffunction> --->
|
||||
|
||||
|
||||
<cffunction name="testInvalidOptions" access="public" returntype="void" output="false">
|
||||
<cfset var account = getTestCreditCard() />
|
||||
<cfset var money = svc.createMoney(cents = getRandomCents()) />
|
||||
<cfset var response = "" />
|
||||
<cfset var invalidOptions = "" />
|
||||
<cfset var options = getTestRequiredOptions() />
|
||||
|
||||
<!--- missing e-mail address --->
|
||||
<cfset invalidOptions=duplicate(options)>
|
||||
<cfset StructDelete(invalidOptions, "Email")>
|
||||
<cftry>
|
||||
<cfset response = gw.authorize(money = money, account = account, options = invalidOptions) />
|
||||
<cfset fail("The authorize call did not fail with missing e-mail address.") />
|
||||
<cfcatch>
|
||||
<cfset assertEquals(cfcatch.type, "cfpayment.MissingParameter.Option", "The authorize call returned the wrong cfcatch type with missing e-mail address.") />
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<!--- missing phone number --->
|
||||
<cfset invalidOptions=duplicate(options)>
|
||||
<cfset StructDelete(invalidOptions.address, "Phone")>
|
||||
<cfset response = gw.authorize(money = money, account = account, options = invalidOptions) />
|
||||
<cfset assertEquals(response.getMessage(), "length or value shiptophone", "The authorize call did not properly fail with missing phone number.") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testInvalidAuthorizations" access="public" returntype="void" output="false">
|
||||
<cfset var account = getTestCreditCard() />
|
||||
<cfset var money = svc.createMoney(cents = getRandomCents()) />
|
||||
<cfset var response = "" />
|
||||
<cfset var options = getTestRequiredOptions() />
|
||||
|
||||
<!--- try invalid card number --->
|
||||
<cfset account.setAccount(testdata.visa_card_number & "1") />
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento())>
|
||||
<cfset assertEquals(response.getStatus(), "3", "The authorize call did not fail with invalid CC number") />
|
||||
<cfset assertEquals(response.getMessage(), "Invalid credit card number", "The authorize call did not fail with invalid CC number") />
|
||||
|
||||
<!--- set valid test card --->
|
||||
<cfset account.setAccount(testdata.visa_card_number) />
|
||||
|
||||
<!--- the developer system does not fail on invalid month/year on the developer gateway, so these tests are useless --->
|
||||
<!--- try invalid expiration --->
|
||||
<!--- <cfset account.setMonth(13) />
|
||||
<cfset account.setYear(year(now()) + 1) />
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento())>
|
||||
<cfset assertEquals(response.getStatus(), "3", "The authorize call did not fail with invalid expiration month") />
|
||||
<cfset assertEquals(response.getMessage(), "Invalid ??", "The authorize call did not fail with invalid expiration month") /> --->
|
||||
|
||||
<!--- try expired card --->
|
||||
<!--- <cfset account.setMonth(5) />
|
||||
<cfset account.setYear(year(now()) - 1) />
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento())>
|
||||
<cfset assertEquals(response.getStatus(), "3", "The authorize call did not fail with an expired date") />
|
||||
<cfset assertEquals(response.getMessage(), "Invalid ??", "The authorize call did not fail with an expired date") /> --->
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testValidAuthorizations" access="public" returntype="void" output="false">
|
||||
<cfset var account = getTestCreditCard() />
|
||||
<cfset var money = svc.createMoney(cents = getRandomCents()) />
|
||||
<cfset var response = "" />
|
||||
<cfset var options = getTestRequiredOptions() />
|
||||
|
||||
<!--- card should result in success --->
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfif response.GetMessage() EQ "Length or value of HTML Serial Number">
|
||||
<cfset fail("The valid authorize attempt was stopped because you have supplied an invalid SkipJack HTML Serial Number.")>
|
||||
<cfelse>
|
||||
<cfset assertTrue(response.getSuccess(), "The valid authorize did not return successful") />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testValidPurchase" access="public" returntype="void" output="false">
|
||||
<cfset var account = getTestCreditCard() />
|
||||
<cfset var money = svc.createMoney(cents = getRandomCents()) />
|
||||
<cfset var response = "" />
|
||||
<cfset var options = getTestRequiredOptions() />
|
||||
<!--- developer serial number required to settle --->
|
||||
<cfset options.DeveloperSerialNumber=gwParams.DeveloperSerialNumber>
|
||||
<!--- card should result in success --->
|
||||
<cfset response = gw.purchase(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfif response.GetMessage() EQ "Length or value of HTML Serial Number">
|
||||
<cfset fail("The valid purchase attempt was stopped because you have supplied an invalid SkipJack HTML Serial Number.")>
|
||||
<cfelse>
|
||||
<cfset assertTrue(response.getSuccess(), "The valid purchase test did not return successful:" & response.getMessage()) />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testValidAuthorizeCreditCapture" access="public" returntype="void" output="false">
|
||||
<cfset var account = getTestCreditCard() />
|
||||
<cfset var money = svc.createMoney(cents = getRandomCents()) />
|
||||
<cfset var options = getTestRequiredOptions() />
|
||||
<cfset var response = "" />
|
||||
<cfset var transId = "" />
|
||||
|
||||
<!--- authorize should result in success --->
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfif response.GetMessage() EQ "Length or value of HTML Serial Number">
|
||||
<cfset fail("The valid authorize attempt was stopped because you have supplied an invalid SkipJack HTML Serial Number.")>
|
||||
<cfelse>
|
||||
<cfset assertTrue(response.getSuccess(), "The valid authorize test did not return successful") />
|
||||
</cfif>
|
||||
|
||||
<!--- capture the transaction id for further processing --->
|
||||
<cfset transId=response.getTransactionId()>
|
||||
<cfset options.DeveloperSerialNumber=gwParams.DeveloperSerialNumber>
|
||||
|
||||
<!--- let's give them a $5 credit --->
|
||||
<cfif money.getCents() GT 501>
|
||||
<cfset money.setCents(money.getCents()-500)>
|
||||
<cfelse>
|
||||
<cfset money.setCents(money.getCents()-1)>
|
||||
</cfif>
|
||||
<cfset response = gw.credit(money = money, identification = transId, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<!--- <cfset assertTrue(response.getSuccess(), "The valid capture test did not return successful") /> --->
|
||||
<!--- <cfset assertEquals(response.getMessage(), "UNSUCCESSFUL: Status Mismatch", "The valid credit test did not return the proper response.") /> --->
|
||||
<cfset assertEquals(response.getMessage(), "The transaction succeeded, but one or more individual items failed.", "The valid credit test did not return the proper response.") />
|
||||
|
||||
<!--- flag the authorization for settlement into your bank account --->
|
||||
<cfset response = gw.capture(money = money, authorization = transId, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The valid capture test did not return successful") />
|
||||
|
||||
<!--- NOTE: once captured, you cannot void --->
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testCredit" access="public" returntype="void" output="false">
|
||||
<cfset var options = getTestRequiredOptions() />
|
||||
<cfset var response = "" />
|
||||
<cfset var transId = "9802853713244.022" /><!--- find a settled transaction id --->
|
||||
<cfset var money = svc.createMoney(cents = 100) />
|
||||
<cfset options.DeveloperSerialNumber=gwParams.DeveloperSerialNumber>
|
||||
|
||||
<cfset response = gw.credit(money = money, identification = transId, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<!--- <cfset assertTrue(response.getSuccess(), "The valid capture test did not return successful") /> --->
|
||||
<!--- <cfset assertEquals(response.getMessage(), "UNSUCCESSFUL: Status Mismatch", "The valid credit test did not return the proper response.") /> --->
|
||||
<cfset assertEquals(response.getMessage(), "The transaction succeeded, but one or more individual items failed.", "The valid credit test did not return the proper response.") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testValidAuthorizeGetStatus" access="public" returntype="void" output="false">
|
||||
<cfset var account = getTestCreditCard() />
|
||||
<cfset var money = svc.createMoney(cents = getRandomCents()) />
|
||||
<cfset var options = getTestRequiredOptions() />
|
||||
<cfset var response = "" />
|
||||
<cfset var originalOrderNumber = "" />
|
||||
|
||||
<!--- card should result in success --->
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfif response.GetMessage() EQ "Length or value of HTML Serial Number">
|
||||
<cfset fail("The valid authorize attempt was stopped because you have supplied an invalid SkipJack HTML Serial Number.")>
|
||||
<cfelse>
|
||||
<cfset assertTrue(response.getSuccess(), "The valid authorize test did not return successful") />
|
||||
</cfif>
|
||||
|
||||
<!--- attempt to get status of this transaction --->
|
||||
<cfset originalOrderNumber = options.order_id />
|
||||
<cfset options.DeveloperSerialNumber = gwParams.DeveloperSerialNumber />
|
||||
<cfset response = gw.status(transactionId = originalOrderNumber, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The valid Get Transaction Status test did not return successful") />
|
||||
<cfset assertTrue(structKeyExists(response.getParsedResult(), "ResultDataQuery") and isQuery(response.getParsedResult().ResultDataQuery), "The valid Get Transaction Status test did not return a valid ResultDataQuery.") />
|
||||
<cfset assertEquals(response.getParsedResult().ResultDataQuery.TransactionStatusMessage, "Approved", "The valid Get Transaction Status test did not return an approved message in the ResultDataQuery.") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testValidAuthorizeAdditionalChargeVoid" access="public" returntype="void" output="false">
|
||||
<cfset var account = getTestCreditCard() />
|
||||
<cfset var money = svc.createMoney(cents = getRandomCents()) />
|
||||
<cfset var options = getTestRequiredOptions() />
|
||||
<cfset var response = "" />
|
||||
<cfset var transId = "" />
|
||||
|
||||
<!--- card should result in success --->
|
||||
<cfset response = gw.authorize(money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfif response.GetMessage() EQ "Length or value of HTML Serial Number">
|
||||
<cfset fail("The valid authorize attempt was stopped because you have supplied an invalid SkipJack HTML Serial Number.")>
|
||||
<cfelse>
|
||||
<cfset assertTrue(response.getSuccess(), "The valid authorize test did not return successful") />
|
||||
</cfif>
|
||||
|
||||
<!--- capture the transaction id for further processing --->
|
||||
<cfset transId=response.getTransactionId()>
|
||||
<cfset options.DeveloperSerialNumber=gwParams.DeveloperSerialNumber>
|
||||
|
||||
<!--- TODO: add "additional authorization" test --->
|
||||
|
||||
<!--- changed my mind, let's void it --->
|
||||
<cfset response = gw.void(authorization = transId, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The valid void test did not return successful") />
|
||||
</cffunction>
|
||||
|
||||
<!--- <cffunction name="testParseAddRecurringResponse" output="false" access="public" returntype="any" hint="">
|
||||
<cfset var response="">
|
||||
<!--- add a generic result to the response object --->
|
||||
<cfset var result="">
|
||||
|
||||
<!--- "-2" is a missing parameter error --->
|
||||
<cfset response=svc.createResponse()>
|
||||
<cfsavecontent variable="result"><cfoutput>"1234567890","-2","1","","","","","","","","",""
|
||||
Parameter Missing: (rtName)</cfoutput></cfsavecontent>
|
||||
<cfset response.setResult(result)>
|
||||
<cfset gw.setGatewayAction("Recurring")>
|
||||
<cfset gw.ParseResponse(response)>
|
||||
<cfset debug(response.getMemento())>
|
||||
<cfset assertEquals(response.getMessage(), "Parameter Missing: (rtName)", "testParseAddRecurringResponse returned the wrong message for a missing rtName error.") />
|
||||
</cffunction> --->
|
||||
|
||||
<cffunction name="testInvalidRecurring" access="public" returntype="void" output="false">
|
||||
<cfset var account = getTestCreditCard() />
|
||||
<cfset var money = svc.createMoney(cents = getRandomCents()) />
|
||||
<cfset var response = "" />
|
||||
<cfset var invalidOptions = "" />
|
||||
<cfset var options = getTestRequiredOptions() />
|
||||
|
||||
<!--- extra fields for recurring transactions --->
|
||||
<cfset options.DeveloperSerialNumber=gwParams.DeveloperSerialNumber>
|
||||
<cfset options.ItemNumber="12345">
|
||||
<cfset options.ItemDescription="Dark Blue Widget">
|
||||
<cfset options.StartingDate=DateFormat(DateAdd("d", 60, now()), "mm/dd/yyyy")>
|
||||
<cfset options.Periodicity="weekly">
|
||||
<cfset options.TotalTransactions="12">
|
||||
|
||||
<!--- missing DeveloperSerialNumber --->
|
||||
<cfset invalidOptions=duplicate(options)>
|
||||
<cfset StructDelete(invalidOptions, "DeveloperSerialNumber")>
|
||||
<cfset response = gw.recurring(mode = "add", money = money, account = account, options = invalidOptions) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<!--- just check this on the first one in this test --->
|
||||
<cfif response.GetMessage() EQ "Length or value of HTML Serial Number">
|
||||
<cfset fail("The valid add recurring payment test was stopped because you have supplied an invalid SkipJack HTML Serial Number.")>
|
||||
<cfelse>
|
||||
<cfset assertEquals(response.getMessage(), "Parameter Missing: (szDeveloperSerialNumber)", "The missing DeveloperSerialNumber test did not return the correct response message.") />
|
||||
</cfif>
|
||||
|
||||
<!--- missing ItemDescription --->
|
||||
<cfset invalidOptions=duplicate(options)>
|
||||
<cfset StructDelete(invalidOptions, "ItemDescription")>
|
||||
<cfset response = gw.recurring(mode = "add", money = money, account = account, options = invalidOptions) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertEquals(response.getMessage(), "Parameter Missing: (rtItemDescription)", "The missing ItemDescription test did not return the correct response message.") />
|
||||
|
||||
<!--- missing ItemNumber --->
|
||||
<cfset invalidOptions=duplicate(options)>
|
||||
<cfset StructDelete(invalidOptions, "ItemNumber")>
|
||||
<cfset response = gw.recurring(mode = "add", money = money, account = account, options = invalidOptions) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertEquals(response.getMessage(), "Parameter Missing: (rtItemNumber)", "The missing ItemNumber test did not return the correct response message.") />
|
||||
|
||||
<!--- missing StartingDate --->
|
||||
<cfset invalidOptions=duplicate(options)>
|
||||
<cfset StructDelete(invalidOptions, "StartingDate")>
|
||||
<cfset response = gw.recurring(mode = "add", money = money, account = account, options = invalidOptions) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertEquals(response.getMessage(), "Parameter Missing: (rtStartingDate)", "The missing StartingDate test did not return the correct response message.") />
|
||||
|
||||
<!--- missing Frequency --->
|
||||
<cfset invalidOptions=duplicate(options)>
|
||||
<cfset StructDelete(invalidOptions, "Periodicity")>
|
||||
<cfset response = gw.recurring(mode = "add", money = money, account = account, options = invalidOptions) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertEquals(response.getMessage(), "Parameter Missing: (rtFrequency)", "The missing Frequency test did not return the correct response message.") />
|
||||
|
||||
<!--- missing TotalTransactions --->
|
||||
<cfset invalidOptions=duplicate(options)>
|
||||
<cfset StructDelete(invalidOptions, "TotalTransactions")>
|
||||
<cfset response = gw.recurring(mode = "add", money = money, account = account, options = invalidOptions) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertEquals(response.getMessage(), "Parameter Missing: (rtTotalTransactions)", "The missing TotalTransactions test did not return the correct response message.") />
|
||||
|
||||
<!--- starting date too early --->
|
||||
<cfset invalidOptions=duplicate(options)>
|
||||
<cfset invalidOptions.StartingDate=DateFormat(DateAdd("m", -3, now()), "mm/dd/yyyy")>
|
||||
<cfset response = gw.recurring(mode = "add", money = money, account = account, options = invalidOptions) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<!--- check just the first 96 characters, because the error ends with dynamic data (the date passed in) --->
|
||||
<cfset assertEquals(left(response.getMessage(), 96), "invalid starting date entered. date must not be more than 60 days earlier than the current date", "The starting date too early test did not return the correct response message.") />
|
||||
|
||||
<!--- invalid frequency --->
|
||||
<cfset invalidOptions=duplicate(options)>
|
||||
<cfset invalidOptions.Periodicity="daily"><!--- daily is not supported by skipjack --->
|
||||
<cfset response = gw.recurring(mode = "add", money = money, account = account, options = invalidOptions) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertEquals(response.getMessage(), "Parameter Missing: (rtFrequency)", "The invalid frequency test did not return the correct response message.") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="testValidRecurring" access="public" returntype="void" output="false">
|
||||
<cfset var account = getTestCreditCard() />
|
||||
<cfset var money = svc.createMoney(cents = getRandomCents()) />
|
||||
<cfset var options = getTestRequiredOptions() />
|
||||
<cfset var response = "" />
|
||||
<cfset var PaymentId1 = "" />
|
||||
<cfset var PaymentId2 = "" />
|
||||
|
||||
<!--- extra fields for recurring transactions --->
|
||||
<cfset options.DeveloperSerialNumber=gwParams.DeveloperSerialNumber>
|
||||
<cfset options.ItemNumber="12345">
|
||||
<cfset options.ItemDescription="Dark Blue Widget">
|
||||
<cfset options.StartingDate=DateFormat(DateAdd("d", 60, now()), "mm/dd/yyyy")>
|
||||
<cfset options.Periodicity="bimonthly">
|
||||
<cfset options.TotalTransactions="12">
|
||||
|
||||
<!--- ADD RECURRING --->
|
||||
<cfset response = gw.recurring(mode = "add", money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfif response.GetMessage() EQ "Length or value of HTML Serial Number">
|
||||
<cfset fail("The valid authorize attempt was stopped because you have supplied an invalid SkipJack HTML Serial Number.")>
|
||||
<cfelse>
|
||||
<cfset assertTrue(response.getSuccess(), "The valid 'add recurring 1' method did not return successful") />
|
||||
</cfif>
|
||||
<!--- get the payment id to use in further testing --->
|
||||
<cfset PaymentId1=StructFind(response.GetParsedResult(), "RecurringPaymentId")>
|
||||
<cfset options.PaymentId=PaymentId1>
|
||||
|
||||
<!--- EDIT RECURRING --->
|
||||
<!--- change the starting date --->
|
||||
<cfset options.StartingDate=DateFormat(DateAdd("yyyy", 1, options.StartingDate), "mm/dd/yyyy")>
|
||||
<cfset response = gw.recurring(mode = "edit", money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The valid 'edit recurring' method did not return successful") />
|
||||
|
||||
<!--- GET RECURRING BY RecurringPaymentId --->
|
||||
<cfset response = gw.recurring(mode = "get", options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The valid 'get recurring' method did not return successful") />
|
||||
|
||||
<!--- ADD ANOTHER RECURRING --->
|
||||
<cfset options.ItemNumber="54321">
|
||||
<cfset options.ItemDescription="Bright Red Widget">
|
||||
<cfset options.StartingDate=DateFormat(DateAdd("d", 14, now()), "mm/dd/yyyy")>
|
||||
<cfset options.Periodicity="biweekly">
|
||||
<cfset options.TotalTransactions="12">
|
||||
<cfset response = gw.recurring(mode = "add", money = money, account = account, options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The valid 'add recurring 2' method did not return successful") />
|
||||
<cfset PaymentId2=StructFind(response.GetParsedResult(), "RecurringPaymentId")>
|
||||
|
||||
<!--- GET ALL RECURRING TRANSACTIONS --->
|
||||
<cfset StructDelete(options, "paymentid")>
|
||||
<cfset response = gw.recurring(mode = "get", options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The valid 'get recurring' method did not return successful") />
|
||||
|
||||
<!--- DELETE BOTH RECURRING --->
|
||||
<cfset options.PaymentId=PaymentId1>
|
||||
<cfset response = gw.recurring(mode = "delete", options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The valid 'delete recurring 1' method did not return successful") />
|
||||
|
||||
<cfset options.PaymentId=PaymentId2>
|
||||
<cfset response = gw.recurring(mode = "delete", options = options) />
|
||||
<cfset debug(response.getMemento()) />
|
||||
<cfset assertTrue(response.getSuccess(), "The valid 'delete recurring 2' method did not return successful") />
|
||||
</cffunction>
|
||||
|
||||
<!---
|
||||
|
||||
helpers
|
||||
|
||||
--->
|
||||
<cffunction name="getRandomOrderNumber" output="false" access="private" returntype="any" hint="">
|
||||
<cfreturn TimeFormat(now(), "hhmmsslll") & RandRange(0,9)>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getRandomCents" output="false" access="private" returntype="any" hint="">
|
||||
<cfreturn Rand("SHA1PRNG") * 100 * 100><!--- return cents --->
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getTestCreditCard" output="false" access="private" returntype="any" hint="">
|
||||
<cfargument name="cardtype" type="string" default="visa"/><!--- visa or mastercard --->
|
||||
<cfset var account=svc.createCreditCard()>
|
||||
<cfset account.setMonth(12) />
|
||||
<cfset account.setYear(year(now())+1) />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfif arguments.cardtype eq "visa">
|
||||
<cfset account.setAccount(testdata.visa_card_number) />
|
||||
<cfset account.setVerificationValue(testdata.visa_cvv2) />
|
||||
<cfelseif arguments.cardtype eq "mastercard">
|
||||
<cfset account.setAccount(testdata.mastcard_card_number) />
|
||||
<cfset account.setVerificationValue(testdata.mastcard_cvv2) />
|
||||
<cfelse>
|
||||
<cfset account.setAccount(testdata.discover_card_number) />
|
||||
<cfset account.setVerificationValue(testdata.discover_cvv2) />
|
||||
</cfif>
|
||||
<cfreturn account>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getTestRequiredOptions" output="false" access="private" returntype="any" hint="">
|
||||
<cfset var options = StructNew() />
|
||||
<cfset options.Email = "someone@somewhere.org" />
|
||||
<cfset options.order_id = getRandomOrderNumber() />
|
||||
<cfset options.address=StructNew() />
|
||||
<cfset options.address.UserFirstName="John" />
|
||||
<cfset options.address.LaerFirstName="Doe" />
|
||||
<cfset options.address.Address1="123 Some Street" />
|
||||
<cfset options.address.City="Anywhere" />
|
||||
<cfset options.address.State="OH" />
|
||||
<cfset options.address.PostalCode="45314" />
|
||||
<cfset options.address.Phone = "123-123-1234" />
|
||||
<cfreturn duplicate(options) />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
25
cfpayment/api/gateway/stripe/response.cfc
Normal file
25
cfpayment/api/gateway/stripe/response.cfc
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2007 Brian Ghidinelli (http://www.ghidinelli.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 name="response" displayname="Stripe Gateway Response" output="false" hint="Remaps hasErrors() for Stripe" extends="cfpayment.api.model.response">
|
||||
|
||||
<cffunction name="hasError" access="public" output="false" returntype="boolean" hint="An error is determined by the status code; the list of good/bad is in the core API">
|
||||
<cfset var res = getParsedResult() />
|
||||
<cfreturn listFind(getService().getStatusErrors(), getStatus()) OR (isStruct(res) AND structKeyExists(res, "error")) />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
907
cfpayment/api/gateway/stripe/stripe.cfc
Normal file
907
cfpayment/api/gateway/stripe/stripe.cfc
Normal file
|
|
@ -0,0 +1,907 @@
|
|||
<!---
|
||||
Original code from Phil Cruz's Stripe.cfc from https://github.com/philcruz/Stripe.cfc/blob/master/stripe/Stripe.cfc
|
||||
Added Stripe Connect/Marketplace support in 2015 by Chris Mayes & Brian Ghidinelli (http://www.ghidinelli.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="Stripe Gateway" extends="cfpayment.api.gateway.base" hint="Stripe Gateway" output="false">
|
||||
|
||||
<cfset variables.cfpayment.GATEWAY_NAME = "Stripe" />
|
||||
<cfset variables.cfpayment.GATEWAY_VERSION = "1.0.7" />
|
||||
<cfset variables.cfpayment.API_VERSION = "2015-08-19" />
|
||||
<!--- stripe test mode uses different credentials instead of different urls --->
|
||||
<cfset variables.cfpayment.GATEWAY_URL = "https://api.stripe.com/v1" />
|
||||
|
||||
|
||||
<cffunction name="getSecretKey" access="public" output="false" returntype="string">
|
||||
<cfif getTestMode()>
|
||||
<cfreturn variables.cfpayment.TestSecretKey />
|
||||
<cfelse>
|
||||
<cfreturn variables.cfpayment.LiveSecretKey />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
<cffunction name="getLiveSecretKey" access="public" output="false" returntype="string">
|
||||
<cfreturn variables.cfpayment.LiveSecretKey />
|
||||
</cffunction>
|
||||
<cffunction name="setLiveSecretKey" access="public" output="false" returntype="void">
|
||||
<cfargument name="LiveSecretKey" type="string" required="true" />
|
||||
<cfset variables.cfpayment.LiveSecretKey = arguments.LiveSecretKey />
|
||||
</cffunction>
|
||||
<cffunction name="getTestSecretKey" access="public" output="false" returntype="string">
|
||||
<cfreturn variables.cfpayment.TestSecretKey />
|
||||
</cffunction>
|
||||
<cffunction name="setTestSecretKey" access="public" output="false" returntype="void">
|
||||
<cfargument name="TestSecretKey" type="string" required="true" />
|
||||
<cfset variables.cfpayment.TestSecretKey = arguments.TestSecretKey />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getPublishableKey" access="public" output="false" returntype="string">
|
||||
<cfif getTestMode()>
|
||||
<cfreturn variables.cfpayment.TestPublishableKey />
|
||||
<cfelse>
|
||||
<cfreturn variables.cfpayment.LivePublishableKey />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getLivePublishableKey" access="public" output="false" returntype="string">
|
||||
<cfreturn variables.cfpayment.LivePublishableKey />
|
||||
</cffunction>
|
||||
<cffunction name="setLivePublishableKey" access="public" output="false" returntype="void">
|
||||
<cfargument name="LivePublishableKey" type="string" required="true" />
|
||||
<cfset variables.cfpayment.LivePublishableKey = arguments.LivePublishableKey />
|
||||
</cffunction>
|
||||
<cffunction name="getTestPublishableKey" access="public" output="false" returntype="string">
|
||||
<cfreturn variables.cfpayment.TestPublishableKey />
|
||||
</cffunction>
|
||||
<cffunction name="setTestPublishableKey" access="public" output="false" returntype="void">
|
||||
<cfargument name="TestPublishableKey" type="string" required="true" />
|
||||
<cfset variables.cfpayment.TestPublishableKey = arguments.TestPublishableKey />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getApiVersion" access="public" output="false" returntype="string">
|
||||
<cfreturn variables.cfpayment.API_VERSION />
|
||||
</cffunction>
|
||||
<cffunction name="setApiVersion" access="public" output="false" returntype="void">
|
||||
<cfset variables.cfpayment.API_VERSION = arguments[1] />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="authorize" output="false" access="public" returntype="any" hint="Authorize but don't capture a credit card">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset arguments.options["capture"] = false />
|
||||
<cfreturn purchase(argumentCollection = arguments) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="capture" output="false" access="public" returntype="any" hint="Capture a previously authorized charge">
|
||||
<cfargument name="transactionId" type="string" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayUrl("/charges/#arguments.transactionId#/capture"), payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="purchase" output="false" access="public" returntype="any" hint="Authorize + Capture in one step">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="account" type="any" required="false" hint="source to be charged - a credit card, bank account or a tokenized source" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" hint="Key options are customer, ConnectedAccount, destination and application_fee" />
|
||||
|
||||
<cfset var post = {} />
|
||||
<cfset var response = "" />
|
||||
|
||||
<cfset post["amount"] = arguments.money.getCents() />
|
||||
<cfset post["currency"] = lCase(arguments.money.getCurrency()) /><!--- iso currency code must be lower case? --->
|
||||
|
||||
<cfif structKeyExists(arguments, "account")>
|
||||
|
||||
<cfswitch expression="#getService().getAccountType(arguments.account)#">
|
||||
<cfcase value="creditcard">
|
||||
<cfset post = addCreditCard(post = post, account = arguments.account) />
|
||||
</cfcase>
|
||||
<cfcase value="token">
|
||||
<cfset post = addToken(post = post, account = arguments.account) />
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfthrow type="cfpayment.InvalidAccount" message="The account type #getService().getAccountType(arguments.account)# is not supported by this gateway." />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayUrl("/charges"), payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="refund" access="public" output="false" returntype="any" hint="Returns an amount back to the previously charged account. Default is to refund the full amount.">
|
||||
<cfargument name="money" type="any" required="false" hint="The amount to refund, if omitted, defaults to the full amount" />
|
||||
<cfargument name="transactionId" type="any" required="true" />
|
||||
<cfargument name="refund_application_fee" type="boolean" required="false" hint="For a destination or Connect charge, whether to refund the application_fee; defaults to false" />
|
||||
<cfargument name="reverse_transfer" type="boolean" required="false" hint="For destination charges, whether to pull back funds from the connected account; defaults to false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset local.post = structNew() />
|
||||
|
||||
<!--- default is to refund full amount --->
|
||||
<cfif structKeyExists(arguments, "money")>
|
||||
<cfset post["amount"] = abs(arguments.money.getCents()) />
|
||||
</cfif>
|
||||
|
||||
<!--- self-documenting --->
|
||||
<cfif structKeyExists(arguments, "refund_application_fee")>
|
||||
<cfset post["refund_application_fee"] = arguments.refund_application_fee />
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(arguments, "reverse_transfer")>
|
||||
<cfset post["reverse_transfer"] = arguments.reverse_transfer />
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/charges/#arguments.transactionId#/refunds"), payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="search" access="public" output="false" returntype="any" hint="Find transactions using gateway-supported criteria">
|
||||
<cfargument name="options" type="struct" required="true" />
|
||||
|
||||
<cfthrow message="Method not implemented." type="cfpayment.MethodNotImplemented" />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="status" access="public" output="false" returntype="any" hint="Reconstruct a response object for a previously executed transaction">
|
||||
<cfargument name="transactionId" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/charges/#arguments.transactionId#"), payload = structNew(), options = arguments.options, method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="validate" output="false" access="public" returntype="any" hint="Convert payment details to a one-time token for charging once. To store payment details for repeat use, convert to a customer object with store().">
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="money" type="any" required="false" />
|
||||
|
||||
<cfset var post = "" />
|
||||
|
||||
<cfif getService().getAccountType(account) EQ "creditcard">
|
||||
<cfset post = addCreditCard(post = structNew(), account = arguments.account) />
|
||||
<cfelseif getService().getAccountType(account) EQ "eft">
|
||||
<cfset post = addBankAccount(post = structNew(), account = arguments.account) />
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/tokens"), payload = post) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="store" output="false" access="public" returntype="any" hint="Convert a one-time token (from validate() or Stripe.js) into a Customer object for charging one or more times in the future">
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = {} />
|
||||
|
||||
<cfif getService().getAccountType(account) EQ "creditcard">
|
||||
<cfset post = addCreditCard(post = post, account = account) />
|
||||
<cfelseif getService().getAccountType(account) EQ "eft">
|
||||
<cfset post = addBankAccount(post = post, account = account) />
|
||||
<cfelse>
|
||||
<cfset post["source"] = arguments.account.getID() />
|
||||
</cfif>
|
||||
|
||||
<!--- optional things to add --->
|
||||
<cfif structKeyExists(arguments.options, "coupon")>
|
||||
<cfset post["coupon"] = arguments.options.coupon />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "account_balance")>
|
||||
<cfset post["account_balance"] = arguments.options.account_balance />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "plan")>
|
||||
<cfset post["plan"] = arguments.options.plan />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "trial_end")>
|
||||
<cfset post["trial_end"] = dateToUTC(arguments.options.trial_end) />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "quantity")>
|
||||
<cfset post["quantity"] = arguments.options.quantity />
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/customers"), payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="unstore" output="false" access="public" returntype="any">
|
||||
<cfargument name="tokenId" type="string" required="true" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/customers/#arguments.tokenId#"), method = "DELETE") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getCustomer" output="false" access="public" returntype="any">
|
||||
<cfargument name="tokenId" type="string" required="true" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/customers/#arguments.tokenId#"), method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="listCharges" output="false" access="public" returntype="any">
|
||||
<cfargument name="count" type="numeric" required="false" />
|
||||
<cfargument name="offset" type="numeric" required="false" />
|
||||
<cfargument name="tokenId" type="string" required="false" />
|
||||
|
||||
<cfset var payload = {} />
|
||||
|
||||
<cfloop collection="#arguments#" item="key">
|
||||
<cfif structKeyExists(arguments, key)>
|
||||
<cfset payload[lcase(key)] = arguments[key] />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayUrl("/charges"), method = "GET", payload = payload) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="listApplicationFees" output="false" access="public" returntype="any" hint="Retrieve a list of application fees">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" hint="options include: charge, created, ending_before, limit, starting_after" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/application_fees"), payload = {}, options = arguments.options, method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getApplicationFee" output="false" access="public" returntype="any" hint="Retrieve details about an application fee">
|
||||
<cfargument name="id" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/application_fees/#arguments.id#"), payload = {}, options = arguments.options, method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="refundApplicationFee" output="false" access="public" returntype="any" hint="Refund all or part of an application fee">
|
||||
<cfargument name="id" type="any" required="true" />
|
||||
<cfargument name="money" type="any" required="false" hint="The amount to refund, if omitted, defaults to the full amount" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset local.post = {} />
|
||||
|
||||
<!--- default is to refund full amount --->
|
||||
<cfif structKeyExists(arguments, "money")>
|
||||
<cfset post["amount"] = abs(arguments.money.getCents()) />
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/application_fees/#arguments.id#/refunds"), payload = post, options = arguments.options, method = "POST") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getBalance" output="false" access="public" returntype="any" hint="Retrieve current Stripe account balance when automatic transfers are disabled">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/balance"), payload = {}, options = arguments.options, method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getBalanceTransaction" output="false" access="public" returntype="any" hint="Retrieve details about a single balance transfer">
|
||||
<cfargument name="id" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/balance/history/#arguments.id#"), payload = {}, options = arguments.options, method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="listBalanceHistory" output="false" access="public" returntype="any" hint="Retrieve a list of balance transfers">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/balance/history"), payload = {}, options = arguments.options, method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="createToken" output="false" access="public" returntype="any" hint="Convert a credit card or bank account into a one-time Stripe token for charging/attaching to a customer, or disbursing/attaching to a recipient (note, using this rather than Stripe.js means you are responsible for ALL PCI DSS compliance)">
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var post = {} />
|
||||
|
||||
<cfswitch expression="#getService().getAccountType(arguments.account)#">
|
||||
<cfcase value="creditcard">
|
||||
<cfset post = addCreditCard(post = post, account = arguments.account) />
|
||||
</cfcase>
|
||||
<cfcase value="eft">
|
||||
<cfset post = addBankAccount(post = post, account = arguments.account) />
|
||||
</cfcase>
|
||||
<cfdefaultcase>
|
||||
<cfthrow type="cfpayment.InvalidAccount" message="The account type #getService().getAccountType(arguments.account)# is not supported by createToken()" />
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/tokens"), payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="createTokenInConnectedAccount" output="false" access="public" returntype="any" hint="Get a token for an existing customer)">
|
||||
<cfargument name="customer" type="any" required="true" />
|
||||
<cfargument name="ConnectedAccount" type="any" required="true" />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/tokens"), payload = {}, options = {"ConnectedAccount": arguments.ConnectedAccount, "customer": arguments.customer}) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getAccountToken" output="false" access="public" returntype="any" hint="Retrieve details about a one-time use token">
|
||||
<cfargument name="id" type="any" required="true" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/tokens/#arguments.id#"), payload = {}, options = {}, method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="listConnectedAccounts" output="false" access="public" returntype="any" hint="List Connect accounts for a platform">
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/accounts"), payload = structNew(), method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="createConnectedAccount" output="false" access="public" returntype="any" hint="Provisions a marketplace account">
|
||||
<cfargument name="country" type="string" required="true" />
|
||||
<cfargument name="managed" type="boolean" required="true" />
|
||||
<cfargument name="email" type="string" required="false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<!--- two set-only and important fields: country, managed --->
|
||||
<cfset local.post = {} />
|
||||
<cfset post["country"] = arguments.country />
|
||||
<cfset post["managed"] = arguments.managed />
|
||||
|
||||
<cfif NOT arguments.managed AND NOT structKeyExists(arguments, "email")>
|
||||
<cfthrow type="cfpayment.InvalidArguments" message="Stripe requires an email address when creating an unmanaged account" />
|
||||
<cfelseif structKeyExists(arguments, "email")>
|
||||
<cfset post["email"] = arguments.email />
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/accounts"), payload = post, options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getConnectedAccount" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="ConnectedAccount" type="any" required="true" />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/accounts/#arguments.ConnectedAccount.getID()#"), payload = structNew(), method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="updateConnectedAccount" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="ConnectedAccount" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/accounts/#arguments.ConnectedAccount.getID()#"), payload = structNew(), options = options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="deleteConnectedAccount" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="ConnectedAccount" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/accounts/#arguments.ConnectedAccount.getID()#"), payload = structNew(), options = options, method = "DELETE") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="listBankAccounts" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="ConnectedAccount" type="any" required="true" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/accounts/#arguments.ConnectedAccount.getID()#/bank_accounts"), payload = structNew(), method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="deleteBankAccount" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="ConnectedAccount" type="any" required="false" />
|
||||
<cfargument name="bankAccountId" type="any" required="false" />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/accounts/#arguments.ConnectedAccount.getID()#/bank_accounts/#arguments.bankAccountId#"), payload = {}, method = "DELETE") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="createBankAccount" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="ConnectedAccount" type="any" required="false" />
|
||||
<cfargument name="account" type="any" required="false" hint="Either a token or EFT" />
|
||||
<cfargument name="currency" type="string" required="true" hint="A 3-letter ISO currency code" />
|
||||
|
||||
<cfset local.post = structNew() />
|
||||
|
||||
<cfif getService().getAccountType(account) EQ "token">
|
||||
<cfset post["bank_account"] = arguments.account.getID() />
|
||||
<cfelseif getService().getAccountType(account) EQ "eft">
|
||||
<cfset post = addBankAccount(post = post, account = account) />
|
||||
<cfset post["bank_account[currency]"] = lcase(arguments.currency) />
|
||||
<cfelse>
|
||||
<cfthrow type="cfpayment.InvalidAccount" message="The account type #getService().getAccountType(arguments.account)# is not supported by this gateway." />
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/accounts/#arguments.ConnectedAccount.getID()#/bank_accounts"), payload = local.post) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="setDefaultBankAccountForCurrency" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="ConnectedAccount" type="any" required="false" />
|
||||
<cfargument name="bankAccountId" type="any" required="false" />
|
||||
|
||||
<cfset local.post = {"default_for_currency": true} />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/accounts/#arguments.ConnectedAccount.getID()#/bank_accounts/#arguments.bankAccountId#"), payload = local.post) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="uploadFile" output="false" access="public" returntype="any" hint="Stripe allows file uploads for identity verification and chargeback dispute evidence - first upload and then assign the file id to its intended object">
|
||||
<cfargument name="file" type="any" required="false" hint="An absolute path to a file" />
|
||||
<cfargument name="purpose" type="string" required="true" hint="Allowed values - from https://stripe.com/docs/api##create_file_upload" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" hint="Pass a ConnectedAccount if attaching to a Connect account" />
|
||||
|
||||
<cfif NOT listFind("identity_document,dispute_evidence", arguments.purpose)>
|
||||
<cfthrow type="cfpayment.InvalidArguments" message="Purpose must be one of: identity_document, dispute_evidence" />
|
||||
</cfif>
|
||||
|
||||
<cfset local.files = {"file": arguments.file} />
|
||||
<cfset local.post = {"purpose": arguments.purpose} />
|
||||
|
||||
<cfreturn process(gatewayUrl = "https://uploads.stripe.com/v1/files", payload = local.post, files = local.files, options = arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="attachIdentityFile" output="false" access="public" returntype="any" hint="For attaching Connect account identity documents">
|
||||
<cfargument name="ConnectedAccount" type="any" required="true" />
|
||||
<cfargument name="fileId" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" hint="Pass a ConnectedAccount if attaching to a Connect account" />
|
||||
|
||||
<cfset local.post = {"legal_entity[verification][document]": arguments.fileId} />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/accounts/#arguments.ConnectedAccount.getID()#"), payload = local.post, options = arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="updateDispute" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="transactionId" type="any" required="false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" hint="Disputes can include file references generated from uploadFile() for evidence" />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/charges/#arguments.transactionId#/disputes"), payload = structNew(), options = arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getTransfer" output="false" access="public" returntype="any" hint="Retrieve details about a single transfer">
|
||||
<cfargument name="id" type="any" required="true" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/transfers/#arguments.id#"), payload = {}, method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="listTransfers" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/transfers"), payload = {}, options = arguments.options, method = "GET") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="transfer" output="false" access="public" returntype="any" hint="">
|
||||
<cfargument name="money" type="any" required="true" />
|
||||
<cfargument name="destination" type="any" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset local.post = structNew() />
|
||||
<cfset local.post["amount"] = arguments.money.getCents() />
|
||||
<cfset local.post["currency"] = lCase(arguments.money.getCurrency()) />
|
||||
<cfset local.post["destination"] = arguments.destination.getID() />
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/transfers"), payload = local.post, options = arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="transferReverse" output="false" access="public" returntype="any">
|
||||
<cfargument name="transferId" type="string" required="true" hint="The transfer to reverse" />
|
||||
<cfargument name="money" type="any" required="false" hint="Amount to refund, if omitted, the default is the entire amount" />
|
||||
<cfargument name="refund_application_fee" type="boolean" required="false" hint="For a destination or Connect charge, whether to refund the application_fee; defaults to false" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset local.post = structNew() />
|
||||
|
||||
<cfif structKeyExists(arguments, "money")>
|
||||
<cfset post["amount"] = abs(arguments.money.getCents()) />
|
||||
</cfif>
|
||||
|
||||
<!--- self-documenting --->
|
||||
<cfif structKeyExists(arguments, "refund_application_fee")>
|
||||
<cfset post["refund_application_fee"] = arguments.refund_application_fee />
|
||||
</cfif>
|
||||
|
||||
<cfreturn process(gatewayUrl = getGatewayURL("/transfers/#arguments.transferId#/reversals"), payload = post, options = arguments.options) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testTLS12" output="false" access="public" returntype="any" hint="Test for TLS 1.2 support - a 200 OK response means your server is OK. See https://stripe.com/blog/upgrading-tls">
|
||||
<cfreturn process(gatewayUrl = "https://api-tls12.stripe.com/v1/charges", payload = {}) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- determine capability of this gateway --->
|
||||
<cffunction name="getIsCCEnabled" access="public" output="false" returntype="boolean" hint="determine whether or not this gateway can accept credit card transactions">
|
||||
<cfreturn true />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- process wrapper with gateway/transaction error handling --->
|
||||
<cffunction name="process" output="false" access="private" returntype="any">
|
||||
<cfargument name="gatewayUrl" type="string" required="true" />
|
||||
<cfargument name="payload" type="struct" required="true" />
|
||||
<cfargument name="options" type="struct" required="false" default="#structNew()#" />
|
||||
<cfargument name="headers" type="struct" required="false" default="#structNew()#" />
|
||||
<cfargument name="method" type="string" required="false" default="post" />
|
||||
<cfargument name="files" type="struct" required="false" default="#structNew()#" />
|
||||
|
||||
<cfset var results = "" />
|
||||
<cfset var response = "" />
|
||||
<cfset var p = arguments.payload /><!--- shortcut (by reference) --->
|
||||
|
||||
<!--- process standard and common CFPAYMENT mappings into gateway-specific values --->
|
||||
<cfif structKeyExists(arguments.options, "description")>
|
||||
<cfset p["description"] = arguments.options.description />
|
||||
</cfif>
|
||||
<cfif structKeyExists(arguments.options, "tokenId")>
|
||||
<cfset p["customer"] = arguments.options.tokenId />
|
||||
</cfif>
|
||||
|
||||
<!--- add baseline authentication --->
|
||||
<cfset headers["authorization"] = "Bearer #getSecretKey()#" />
|
||||
|
||||
<!--- add connect authentication on behalf of a Connect/Marketplace customer --->
|
||||
<cfif structKeyExists(arguments.options, "ConnectedAccount")>
|
||||
<cfif NOT isObject(arguments.options.ConnectedAccount)>
|
||||
<cfthrow type="cfpayment.InvalidArguments" message="ConnectedAccount must be a cfpayment token object" />
|
||||
</cfif>
|
||||
<cfset headers["Stripe-Account"] = arguments.options.ConnectedAccount.getID() />
|
||||
<cfset structDelete(arguments.options, "ConnectedAccount") />
|
||||
</cfif>
|
||||
|
||||
<!--- if we want to override the stripe API version, we can set it in the config with "ApiVersion". Using 'latest' overrides to current version --->
|
||||
<cfif len(getApiVersion())>
|
||||
<!--- https://groups.google.com/a/lists.stripe.com/forum/#!topic/api-discuss/V4sYRlHwalc --->
|
||||
<cfset headers["Stripe-Version"] = getApiVersion() />
|
||||
</cfif>
|
||||
|
||||
<!--- help track where this request was made from --->
|
||||
<cfset headers["User-Agent"] = "Stripe/v1 cfpayment/#variables.cfpayment.GATEWAY_VERSION#" />
|
||||
|
||||
<!--- add dynamic statement descriptors of up to 22 chars which show up on CC statement alongside merchant name: https://stripe.com/docs/api#create_charge --->
|
||||
<cfif structKeyExists(arguments.options, "statement_descriptor")>
|
||||
<cfset p["statement_descriptor"] = left(reReplace(arguments.options.statement_descriptor, "[<>""']", "", "ALL"), 22) />
|
||||
<cfset structDelete(arguments.options, "statement_descriptor") />
|
||||
</cfif>
|
||||
|
||||
<!--- application_fee is a money object, just like the amount to be charged --->
|
||||
<cfif structKeyExists(arguments.options, "application_fee")>
|
||||
<cfif NOT isObject(arguments.options.application_fee)>
|
||||
<cfthrow type="cfpayment.InvalidArguments" message="application_fee must be a cfpayment money object" />
|
||||
</cfif>
|
||||
<cfset p["application_fee"] = arguments.options.application_fee.getCents() />
|
||||
<cfset structDelete(arguments.options, "application_fee") />
|
||||
</cfif>
|
||||
|
||||
<!--- if a card is converted to a customer, you can optionally pass a customer to many requests to charge their default account instead --->
|
||||
<cfif structKeyExists(arguments.options, "customer")>
|
||||
<cfif NOT isObject(arguments.options.customer)>
|
||||
<cfthrow type="cfpayment.InvalidArguments" message="Customer must be a cfpayment token object" />
|
||||
</cfif>
|
||||
<cfset p = addCustomer(post = p, customer = arguments.options.customer) />
|
||||
<cfset structDelete(arguments.options, "customer") />
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(arguments.options, "destination")>
|
||||
<cfif NOT isObject(arguments.options.destination)>
|
||||
<cfthrow type="cfpayment.InvalidArguments" message="Destination must be a cfpayment token object" />
|
||||
</cfif>
|
||||
<cfset p["destination"] = arguments.options.destination.getID() />
|
||||
<cfset structDelete(arguments.options, "destination") />
|
||||
</cfif>
|
||||
|
||||
|
||||
|
||||
<!--- finally, copy in any additional keys like customer, destination, etc, stripe always wants lower-case --->
|
||||
<cfloop collection="#arguments.options#" item="local.key">
|
||||
<cfset p[lcase(key)] = arguments.options[key] />
|
||||
</cfloop>
|
||||
|
||||
|
||||
<!--- Stripe returns errors with http status like 400,402 or 404 (https://stripe.com/docs/api#errors) --->
|
||||
<cfset response = createResponse(argumentCollection = super.process(url = arguments.gatewayUrl, payload = payload, headers = headers, method = arguments.method, files = files)) />
|
||||
|
||||
|
||||
<cfif isJSON(response.getResult())>
|
||||
|
||||
<cfset results = deserializeJSON(response.getResult()) />
|
||||
<cfset response.setParsedResult(results) />
|
||||
|
||||
<!--- take object-specific IDs like tok_*, ch_*, re_*, etc and always put it as the transaction id --->
|
||||
<cfif structKeyExists(results, "id")>
|
||||
<cfset response.setTransactionID(results.id) />
|
||||
</cfif>
|
||||
|
||||
<!--- the available 'types': list, customer, charge, token, card, bank_account, refund, application_fee, transfer, transfer_reversal, account, file_upload --->
|
||||
<cfif structKeyExists(results, "object")>
|
||||
|
||||
<cfswitch expression="#results.object#">
|
||||
<cfcase value="account">
|
||||
|
||||
<cfset response.setTokenID(results.id) />
|
||||
|
||||
</cfcase>
|
||||
<cfcase value="bank_account">
|
||||
|
||||
<cfset response.setTokenID(results.id) />
|
||||
|
||||
</cfcase>
|
||||
<cfcase value="charge">
|
||||
|
||||
<cfset response.setCVVCode(normalizeCVV(results.source)) />
|
||||
<cfset response.setAVSCode(normalizeAVS(results.source)) />
|
||||
|
||||
<!--- if you authorize without capture, you use the charge id to capture it later, which is the same as the transaction id, but for normality, put it here --->
|
||||
<cfif structKeyExists(results, "captured") AND NOT results.captured AND structKeyExists(results, "id")>
|
||||
<cfset response.setAuthorization(results.id) />
|
||||
</cfif>
|
||||
|
||||
</cfcase>
|
||||
<cfcase value="customer">
|
||||
|
||||
<!--- customers have a "sources" key with, by default, one card on file
|
||||
you can add more cards to a customer using the card api, but otherwise
|
||||
adding a new one actually replaces the previous one on file.
|
||||
we make the assumption today that we only have one until someone needs more
|
||||
--->
|
||||
<cfset response.setCVVCode(normalizeCVV(results.sources.data[1])) />
|
||||
<cfset response.setAVSCode(normalizeAVS(results.sources.data[1])) />
|
||||
|
||||
<cfset response.setTokenID(results.id) />
|
||||
|
||||
</cfcase>
|
||||
<cfcase value="token">
|
||||
|
||||
<!--- stripe does not check AVS/CVV at the token stage - only once converted to a customer or in a charge --->
|
||||
<!--- could be results.source.object EQ card or bank_account --->
|
||||
<cfset response.setTokenID(results.id) />
|
||||
|
||||
</cfcase>
|
||||
</cfswitch>
|
||||
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<!--- now add custom handling of status codes for Stripe which overrides base.cfc --->
|
||||
<cfset handleHttpStatus(response = response) />
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="normalizeCVV" output="false" access="private" returntype="string">
|
||||
<cfargument name="source" type="any" required="true" hint="A structure that contains a cvc_check key" />
|
||||
|
||||
<!--- translate to normalized cfpayment CVV codes --->
|
||||
<cfif structKeyExists(arguments.source, "cvc_check") AND arguments.source.cvc_check EQ "pass">
|
||||
<cfreturn "M" />
|
||||
<cfelseif structKeyExists(arguments.source, "cvc_check") AND arguments.source.cvc_check EQ "fail">
|
||||
<cfreturn "N" />
|
||||
<cfelseif structKeyExists(arguments.source, "cvc_check") AND arguments.source.cvc_check EQ "unchecked">
|
||||
<cfreturn "U" />
|
||||
<cfelseif NOT structKeyExists(arguments.source, "cvc_check")>
|
||||
<!--- indicates it wasn't checked --->
|
||||
<cfreturn "" />
|
||||
<cfelse>
|
||||
<cfreturn "P" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="normalizeAVS" output="false" access="private" returntype="string">
|
||||
<cfargument name="source" type="any" required="true" hint="A structure that contains address_line1_check and address_zip_check keys" />
|
||||
|
||||
<!--- translate to normalized cfpayment AVS codes. Options are pass, fail, unavailable and unchecked. Watch out that either address_line1_check or address_zip_check can be null OR "unchecked"; null throws error trying to access --->
|
||||
<cfif structKeyExists(arguments.source, "address_zip_check") AND arguments.source.address_zip_check EQ "pass"
|
||||
AND structKeyExists(arguments.source, "address_line1_check") AND arguments.source.address_line1_check EQ "pass">
|
||||
<cfreturn "M" />
|
||||
<cfelseif structKeyExists(arguments.source, "address_zip_check") AND arguments.source.address_zip_check EQ "pass">
|
||||
<cfreturn "P" />
|
||||
<cfelseif structKeyExists(arguments.source, "address_line1_check") AND arguments.source.address_line1_check EQ "pass">
|
||||
<cfreturn "B" />
|
||||
<cfelseif (structKeyExists(arguments.source, "address_zip_check") AND arguments.source.address_zip_check EQ "unchecked")
|
||||
OR (structKeyExists(arguments.source, "address_line1_check") AND arguments.source.address_line1_check EQ "unchecked")>
|
||||
<cfif arguments.source.country EQ "US">
|
||||
<cfreturn "S" />
|
||||
<cfelse>
|
||||
<cfreturn "G" />
|
||||
</cfif>
|
||||
<cfelseif NOT structKeyExists(arguments.source, "address_zip_check") AND NOT structKeyExists(arguments.source, "address_line1_check")>
|
||||
<!--- indicates it wasn't checked --->
|
||||
<cfreturn "" />
|
||||
<cfelse>
|
||||
<cfreturn "N" />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!---
|
||||
//Stripe returns errors with http status like 400, 402 or 404 (https://stripe.com/docs/api#errors)
|
||||
//so we need to override http status handling in base.cfc process()
|
||||
--->
|
||||
<cffunction name="handleHttpStatus" access="private" returntype="any" output="false" hint="Override base HTTP status code handling with Stripe-specific results">
|
||||
<cfargument name="response" type="any" required="true" />
|
||||
|
||||
<!---
|
||||
HTTP Status Code Summary
|
||||
200 OK - Everything worked as expected.
|
||||
400 Bad Request - Often missing a required parameter.
|
||||
401 Unauthorized - No valid API key provided.
|
||||
402 Request Failed - Parameters were valid but request failed.
|
||||
404 Not Found - The requested item doesn't exist.
|
||||
500, 502, 503, 504 Server errors - something went wrong on Stripe's end.
|
||||
|
||||
Errors
|
||||
Invalid Request Errors
|
||||
Type: invalid_request_error
|
||||
|
||||
API Errors
|
||||
Type: api_error
|
||||
|
||||
Card Errors
|
||||
Type: card_error
|
||||
|
||||
Code Details
|
||||
incorrect_number The card number is incorrect
|
||||
invalid_number The card number is not a valid credit card number
|
||||
invalid_expiry_month The card's expiration month is invalid
|
||||
invalid_expiry_year The card's expiration year is invalid
|
||||
invalid_cvc The card's security code is invalid
|
||||
expired_card The card has expired
|
||||
incorrect_cvc The card's security code is incorrect
|
||||
card_declined The card was declined.
|
||||
missing There is no card on a customer that is being charged.
|
||||
processing_error An error occurred while processing the card.
|
||||
--->
|
||||
<cfscript>
|
||||
var status = response.getStatusCode();
|
||||
var res = response.getParsedResult();
|
||||
|
||||
switch(status)
|
||||
{
|
||||
case "200": // OK - Everything worked as expected.
|
||||
response.setStatus(getService().getStatusSuccessful());
|
||||
break;
|
||||
|
||||
case "401": // Unauthorized - No valid API key provided.
|
||||
response.setMessage("There is a configuration error preventing the transaction from completing successfully. (Original issue: Invalid API key)");
|
||||
response.setStatus(getService().getStatusFailure());
|
||||
break;
|
||||
|
||||
case "402": // Request Failed - Parameters were valid but request failed. e.g. invalid card, cvc failed, etc.
|
||||
response.setStatus(getService().getStatusDeclined());
|
||||
break;
|
||||
|
||||
case "400": // Bad Request - Often missing a required parameter, includes parameter not allowed or params not lowercase
|
||||
case "404": // Not Found - The requested item doesn't exist. i.e. no charge for that id
|
||||
response.setStatus(getService().getStatusFailure());
|
||||
break;
|
||||
|
||||
case "500": // Server errors - something went wrong on Stripe's end.
|
||||
case "502":
|
||||
case "503":
|
||||
case "504":
|
||||
response.setStatus(getService().getStatusFailure());
|
||||
break;
|
||||
}
|
||||
|
||||
if (response.hasError() AND isStruct(res) AND structKeyExists(res, "error"))
|
||||
{
|
||||
if (structKeyExists(res.error, "message"))
|
||||
response.setMessage(res.error.message);
|
||||
|
||||
if (structKeyExists(res.error, "param"))
|
||||
response.setMessage(response.getMessage() & " (#res.error.param#)");
|
||||
|
||||
if (structKeyExists(res.error, "code"))
|
||||
{
|
||||
switch (res.error.code)
|
||||
{
|
||||
case "incorrect_number":
|
||||
case "invalid_number":
|
||||
case "invalid_expiry_month":
|
||||
case "invalid_expiry_year":
|
||||
case "invalid_cvc":
|
||||
case "expired_card":
|
||||
case "incorrect_cvc":
|
||||
case "card_declined":
|
||||
case "missing":
|
||||
case "processing_error":
|
||||
// can do more involved translation to human-speak here
|
||||
response.setMessage(response.getMessage() & " [#res.error.code#]");
|
||||
break;
|
||||
default:
|
||||
response.setMessage(response.getMessage() & " [#res.error.code#]");
|
||||
}
|
||||
}
|
||||
else if (NOT structKeyExists(res.error, "message"))
|
||||
{
|
||||
response.setMessage("Gateway returned unknown response: #status#");
|
||||
}
|
||||
}
|
||||
</cfscript>
|
||||
|
||||
<cfreturn response />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getGatewayURL" access="public" output="false" returntype="any" hint="Append to Gateway URL to return the appropriate url for the API endpoint">
|
||||
<cfargument name="endpoint" type="string" required="false" default="" />
|
||||
<cfreturn variables.cfpayment.GATEWAY_URL & arguments.endpoint />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- HELPER FUNCTIONS --->
|
||||
<cffunction name="addCreditCard" output="false" access="private" returntype="any" hint="Add payment source fields to the request object">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
|
||||
<cfscript>
|
||||
post["card[number]"] = arguments.account.getAccount();
|
||||
post["card[exp_month]"] = arguments.account.getMonth();
|
||||
post["card[exp_year]"] = arguments.account.getYear();
|
||||
post["card[cvc]"] = arguments.account.getVerificationValue();
|
||||
post["card[name]"] = arguments.account.getName();
|
||||
post["card[address_line1]"] = arguments.account.getAddress();
|
||||
post["card[address_line2]"] = arguments.account.getAddress2();
|
||||
post["card[address_zip]"] = arguments.account.getPostalCode();
|
||||
post["card[address_state]"] = arguments.account.getRegion();
|
||||
post["card[address_country]"] = arguments.account.getCountry();
|
||||
</cfscript>
|
||||
|
||||
<cfreturn post />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="addBankAccount" output="false" access="private" returntype="any" hint="Add payment source fields to the request object">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
|
||||
<cfscript>
|
||||
post["bank_account[country]"] = arguments.account.getCountry();
|
||||
post["bank_account[routing_number]"] = arguments.account.getRoutingNumber();
|
||||
post["bank_account[account_number]"] = arguments.account.getAccount();
|
||||
</cfscript>
|
||||
|
||||
<cfreturn post />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="addToken" output="false" access="private" returntype="any" hint="Add payment source fields to the request object">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="account" type="any" required="true" />
|
||||
|
||||
<cfset arguments.post["source"] = arguments.account.getID() />
|
||||
|
||||
<cfreturn arguments.post />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="addCustomer" output="false" access="private" returntype="any" hint="Add payment source fields to the request object">
|
||||
<cfargument name="post" type="struct" required="true" />
|
||||
<cfargument name="customer" type="any" required="true" />
|
||||
|
||||
<cfset arguments.post["customer"] = arguments.customer.getID() />
|
||||
|
||||
<cfreturn arguments.post />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="dateToUTC" output="false" access="public" returntype="any" hint="Take a date and return the number of seconds since the Unix Epoch">
|
||||
<cfargument name="date" type="any" required="true" />
|
||||
<cfreturn dateDiff("s", dateConvert("utc2Local", "January 1 1970 00:00"), arguments.date) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="UTCToDate" output="false" access="public" returntype="date" hint="Take a UTC timestamp and convert it to a ColdFusion date object">
|
||||
<cfargument name="utcdate" required="true" />
|
||||
<cfreturn dateAdd("s", arguments.utcDate, dateConvert("utc2Local", "January 1 1970 00:00")) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- stripe createResponse() overrides the getSuccess/hasError() responses --->
|
||||
<cffunction name="createResponse" access="public" output="false" returntype="any" hint="Create a Stripe response object with status set to unprocessed">
|
||||
<cfreturn createObject("component", "response").init(argumentCollection = arguments, service = getService()) />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
2
cfpayment/api/gateway/stripe/tests/.gitignore
vendored
Normal file
2
cfpayment/api/gateway/stripe/tests/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# where we can store local credentials
|
||||
credentials.cfm
|
||||
133
cfpayment/api/gateway/stripe/tests/BaseStripeTest.cfc
Normal file
133
cfpayment/api/gateway/stripe/tests/BaseStripeTest.cfc
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
<cfcomponent name="BaseStripeTest" extends="mxunit.framework.TestCase" output="false">
|
||||
|
||||
|
||||
<cffunction name="setUp" returntype="void" access="public">
|
||||
|
||||
<cfif fileExists(getDirectoryFromPath(getCurrentTemplatePath()) & "credentials.cfm")>
|
||||
<cfinclude template="credentials.cfm" />
|
||||
<cfelse>
|
||||
<cfset variables.credentials = { "CAD": {"TestSecretKey": "sk_test_Zx4885WE43JGqPjqGzaWap8a", "TestPublishableKey": ""}
|
||||
,"USD": {"TestSecretKey": "tGN0bIwXnHdwOa85VABjPdSn8nWY7G7I", "TestPublishableKey": ""}
|
||||
} />
|
||||
</cfif>
|
||||
|
||||
<cfscript>
|
||||
// $CAD credentials (provided by support@stripe.com)
|
||||
local.gw = {"path": "stripe.stripe", "GatewayID": 2, "TestMode": true};
|
||||
local.gw.TestSecretKey = credentials.cad.TestSecretKey;
|
||||
local.gw.TestPublishableKey = credentials.cad.TestPublishableKey;
|
||||
|
||||
variables.svc = createObject("component", "cfpayment.api.core").init(local.gw);
|
||||
variables.cad = variables.svc.getGateway();
|
||||
variables.cad.currency = "cad"; // ONLY FOR UNIT TEST
|
||||
variables.cad.country = "CA"; // ONLY FOR UNIT TEST
|
||||
|
||||
|
||||
// $USD credentials - from PHP unit tests on github
|
||||
local.gw = {"path": "stripe.stripe", "GatewayID": 2, "TestMode": true};
|
||||
local.gw.TestSecretKey = credentials.usd.TestSecretKey;
|
||||
local.gw.TestPublishableKey = credentials.usd.TestPublishableKey;
|
||||
|
||||
variables.svc = createObject("component", "cfpayment.api.core").init(local.gw);
|
||||
variables.usd = variables.svc.getGateway();
|
||||
variables.usd.currency = "usd"; // ONLY FOR UNIT TEST
|
||||
variables.usd.country = "US"; // ONLY FOR UNIT TEST
|
||||
|
||||
// create default
|
||||
variables.gw = variables.usd;
|
||||
|
||||
// for dataprovider testing
|
||||
variables.gateways = [cad, usd];
|
||||
</cfscript>
|
||||
|
||||
<!--- if set to false, will try to connect to remote service to check these all out --->
|
||||
<cfset variables.localMode = true />
|
||||
<cfset variables.debugMode = true />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="offlineInjector" access="private">
|
||||
<cfif variables.localMode>
|
||||
<cfset injectMethod(argumentCollection = arguments) />
|
||||
</cfif>
|
||||
<!--- if not local mode, don't do any mock substitution so the service connects to the remote service! --->
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="standardResponseTests" access="private">
|
||||
<cfargument name="response" type="any" required="true" />
|
||||
<cfargument name="expectedObjectName" type="any" required="true" />
|
||||
<cfargument name="expectedIdPrefix" type="any" required="true" />
|
||||
|
||||
<cfif variables.debugMode>
|
||||
<cfset debug(arguments.expectedObjectName)>
|
||||
<cfset debug(arguments.response.getParsedResult())>
|
||||
<cfset debug(arguments.response.getResult())>
|
||||
</cfif>
|
||||
|
||||
<cfif isSimpleValue(arguments.response)>
|
||||
<cfset assertTrue(false, "Response returned a simple value: '#arguments.response#'") />
|
||||
</cfif>
|
||||
<cfif NOT isObject(arguments.response)>
|
||||
<cfset assertTrue(false, "Invalid: response is not an object") />
|
||||
<cfelseif isStruct(arguments.response.getParsedResult()) AND structIsEmpty(arguments.response.getParsedResult())>
|
||||
<cfset assertTrue(false, "Response structure returned is empty") />
|
||||
<cfelseif isSimpleValue(arguments.response.getParsedResult())>
|
||||
<cfset assertTrue(false, "Response is a string, expected a structure. Returned string = '#arguments.response.getParsedResult()#'") />
|
||||
<cfelseif arguments.response.getStatusCode() neq 200>
|
||||
<!--- Test status code and remote error messages --->
|
||||
<cfif structKeyExists(arguments.response.getParsedResult(), "error")>
|
||||
<cfset assertTrue(false, "Error From Stripe: (Type=#arguments.response.getParsedResult().error.type#) #arguments.response.getParsedResult().error.message#") />
|
||||
</cfif>
|
||||
<cfset assertTrue(false, "Status code should be 200, was: #arguments.response.getStatusCode()#") />
|
||||
<cfelse>
|
||||
<!--- Test returned data (for object and valid id) --->
|
||||
<cfset assertTrue(arguments.response.getSuccess(), "Response not successful") />
|
||||
<cfif arguments.expectedObjectName neq "">
|
||||
<cfset assertTrue(structKeyExists(arguments.response.getParsedResult(), "object") AND arguments.response.getParsedResult().object eq arguments.expectedObjectName, "Invalid #expectedObjectName# object returned") />
|
||||
</cfif>
|
||||
<cfif arguments.expectedIdPrefix neq "">
|
||||
<cfset assertTrue(len(arguments.response.getParsedResult().id) gt len(arguments.expectedIdPrefix) AND left(arguments.response.getParsedResult().id, len(arguments.expectedIdPrefix)) eq arguments.expectedIdPrefix, "Invalid account ID prefix returned, expected: '#arguments.expectedIdPrefix#...', received: '#response.getParsedResult().id#'") />
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="standardErrorResponseTests" access="private">
|
||||
<cfargument name="response" type="any" required="true" />
|
||||
<cfargument name="expectedErrorType" type="any" required="true" />
|
||||
<cfargument name="expectedStatusCode" type="any" required="true" />
|
||||
|
||||
<cfif variables.debugMode>
|
||||
<cfset debug(arguments.expectedErrorType)>
|
||||
<cfset debug(arguments.expectedStatusCode)>
|
||||
<cfset debug(arguments.response.getParsedResult())>
|
||||
<cfset debug(arguments.response.getResult())>
|
||||
</cfif>
|
||||
|
||||
<cfif isSimpleValue(arguments.response)>
|
||||
<cfset assertTrue(false, "Response returned a simple value: '#arguments.response#'") />
|
||||
</cfif>
|
||||
<cfif NOT isObject(arguments.response)>
|
||||
<cfset assertTrue(false, "Invalid: response is not an object") />
|
||||
<cfelseif isStruct(arguments.response.getParsedResult()) AND structIsEmpty(arguments.response.getParsedResult())>
|
||||
<cfset assertTrue(false, "Response structure returned is empty") />
|
||||
<cfelseif isSimpleValue(arguments.response.getParsedResult())>
|
||||
<cfset assertTrue(false, "Response is a string, expected a structure. Returned string = '#arguments.response.getParsedResult()#'") />
|
||||
<cfelseif arguments.response.getStatusCode() neq arguments.expectedStatusCode>
|
||||
<cfset assertTrue(false, "Status code should be #arguments.expectedStatusCode#, was: #arguments.response.getStatusCode()#") />
|
||||
<cfelse>
|
||||
<cfif structKeyExists(arguments.response.getParsedResult(), "error")>
|
||||
<cfif structKeyExists(arguments.response.getParsedResult().error, "message") AND structKeyExists(arguments.response.getParsedResult().error, "type")>
|
||||
<cfset assertTrue(arguments.response.getParsedResult().error.type eq arguments.expectedErrorType, "Received error type (#arguments.response.getParsedResult().error.type#), expected error type (#arguments.expectedErrorType#) from API") />
|
||||
<cfelse>
|
||||
<cfset assertTrue(false, "Error message from API missing details") />
|
||||
</cfif>
|
||||
<cfelse>
|
||||
<cfset assertTrue(false, "Object returned did not have an error") />
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
</cfcomponent>
|
||||
|
|
@ -0,0 +1,738 @@
|
|||
<cfcomponent name="StripeMarketplaceAccountTest" extends="BaseStripeTest" output="false">
|
||||
|
||||
<!---
|
||||
|
||||
From https://stripe.com/docs/testing#cards :
|
||||
In test mode, you can use these test cards to simulate a successful transaction:
|
||||
|
||||
Number Card type
|
||||
4242424242424242 Visa
|
||||
4012888888881881 Visa
|
||||
5555555555554444 MasterCard
|
||||
5105105105105100 MasterCard
|
||||
378282246310005 American Express
|
||||
371449635398431 American Express
|
||||
6011111111111117 Discover
|
||||
6011000990139424 Discover
|
||||
30569309025904 Diner's Club
|
||||
38520000023237 Diner's Club
|
||||
3530111333300000 JCB
|
||||
3566002020360505 JCB
|
||||
In addition, these cards will produce specific responses that are useful for testing different scenarios:
|
||||
|
||||
Number Description
|
||||
4000000000000010 address_line1_check and address_zip_check will both fail.
|
||||
4000000000000028 address_line1_check will fail.
|
||||
4000000000000036 address_zip_check will fail.
|
||||
4000000000000101 cvc_check will fail.
|
||||
4000000000000341 Attaching this card to a Customer object will succeed, but attempts to charge the customer will fail.
|
||||
4000000000000002 Charges with this card will always be declined with a card_declined code.
|
||||
4000000000000069 Will be declined with an expired_card code.
|
||||
4000000000000119 Will be declined with a processing_error code.
|
||||
Additional test mode validation: By default, passing address or CVC data with the card number will cause the address and CVC checks to succeed. If not specified, the value of the checks will be null. Any expiration date in the future will be considered valid.
|
||||
|
||||
How do I test specific error codes?
|
||||
|
||||
Some suggestions:
|
||||
|
||||
card_declined: Use this special card number - 4000000000000002.
|
||||
incorrect_number: Use a number that fails the Luhn check, e.g. 4242424242424241.
|
||||
invalid_expiry_month: Use an invalid month e.g. 13.
|
||||
invalid_expiry_year: Use a year in the past e.g. 1970.
|
||||
invalid_cvc: Use a two digit number e.g. 99.
|
||||
|
||||
--->
|
||||
<cffunction name="setUp" returntype="void" access="public">
|
||||
|
||||
<cfset super.setup() />
|
||||
|
||||
<cfscript>
|
||||
// local resources
|
||||
variables.filePathToSampleLicence = getDirectoryFromPath(getCurrentTemplatePath()) & 'sample_driving_license_usa.jpg';
|
||||
</cfscript>
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testCreateConnectedAccountFailurePopulatesGetMessage" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_update_account_failed", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = arguments.gw.country, options = {"transfer_schedule[interval]": "invalid"}) />
|
||||
<cfset standardErrorResponseTests(response = local.connectedAccount, expectedStatusCode = "400", expectedErrorType = "invalid_request_error") />
|
||||
|
||||
<cfset assertTrue(connectedAccount.getMessage() EQ "Must be one of daily, weekly, monthly, manual. (transfer_schedule[interval])", "Error message didn't match, was: #connectedAccount.getMessage()#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testCreateAndUpdateConnectedAccount" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset local.origEmail = "test20150406173055@test.tst" />
|
||||
<cfset local.newEmail = "test1234@testing123.tst" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = arguments.gw.country, email = local.origEmail) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
<cfset assertTrue(local.connectedAccount.getParsedResult().managed, "Account is not managed") />
|
||||
<cfset assertTrue(local.connectedAccount.getParsedResult().email EQ "test20150406173055@test.tst", "Email did not match") />
|
||||
|
||||
<!--- Update Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_update_account_ok", "doHttpCall") />
|
||||
<cfset local.options = {"legal_entity[first_name]": "John", "legal_entity[last_name]": "Smith", "email": local.newEmail, "decline_charge_on[cvc_failure]": true} />
|
||||
<cfset local.update = arguments.gw.updateConnectedAccount(connectedAccount = connectedAccountToken, options = options) />
|
||||
<cfset standardResponseTests(response = local.update, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset assertTrue(local.update.getParsedResult().legal_entity.first_name EQ "John", "Legal entity update did not take, first name was not John") />
|
||||
<cfset assertTrue(local.update.getParsedResult().decline_charge_on.cvc_failure, "Decline on cvc failure should be on after update") />
|
||||
<cfset assertTrue(local.update.getParsedResult().email EQ local.newEmail, "Email did not match") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testListConnectedAccounts" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<!--- List Connected Accounts --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_account_list_ok", "doHttpCall") />
|
||||
<cfset local.list = arguments.gw.listConnectedAccounts() />
|
||||
<cfset standardResponseTests(response = local.list, expectedObjectName = "list", expectedIdPrefix="") />
|
||||
<cfset assertTrue(structKeyExists(local.list.getParsedResult(), "data") AND isArray(local.list.getParsedResult().data), "Invalid account list") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testUpdatingConnectedAccountWithInvalidFieldsThrowsError" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = arguments.gw.country) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
|
||||
<!--- Update Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_update_account_failed", "doHttpCall") />
|
||||
<cfset local.update = arguments.gw.updateConnectedAccount(connectedAccount = local.connectedAccountToken, options = {"legal_entity[invalid_field]": "fail"}) />
|
||||
<cfset standardErrorResponseTests(response = local.update, expectedStatusCode = "400", expectedErrorType = "invalid_request_error") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testCanadaIndividualConnectedAccountLegalEntityFields" access="public" returntype="void" output="false">
|
||||
<cfargument name="gw" type="any" required="false" default="#variables.cad#" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = "CA", options = {"legal_entity[type]": "individual"}) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.connectedAccount.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.connectedAccount.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.connectedAccount.getParsedResult().verification["fields_needed"]) GT 0, "Fields_Needed array is empty") />
|
||||
<cfloop list="legal_entity.first_name,legal_entity.last_name,legal_entity.dob.day,legal_entity.dob.month,legal_entity.dob.year,legal_entity.address.line1,legal_entity.address.city,legal_entity.address.state,legal_entity.address.postal_code,bank_account,tos_acceptance.ip,tos_acceptance.date" index="local.fieldNeeded">
|
||||
<cfset assertTrue(listFindNoCase(arrayToList(local.connectedAccount.getParsedResult().verification["fields_needed"]), local.fieldNeeded), "Missing Fields_needed value: #local.fieldNeeded#") />
|
||||
</cfloop>
|
||||
|
||||
|
||||
<!--- now update the account and check it no longer requests anything --->
|
||||
|
||||
<!--- Create Bank Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.bankAccount = arguments.gw.createBankAccount(connectedAccount = local.connectedAccountToken, account = createBankAccountHelper(arguments.gw.country), currency = "cad") />
|
||||
<cfset standardResponseTests(response = local.bankAccount, expectedObjectName = "bank_account", expectedIdPrefix="ba_") />
|
||||
|
||||
<!--- Update Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_update_account_validation_passes_ok", "doHttpCall") />
|
||||
<cfset local.fieldsNeeded = {
|
||||
"legal_entity[first_name]": "John",
|
||||
"legal_entity[last_name]": "Smith",
|
||||
"legal_entity[dob][day]": "20",
|
||||
"legal_entity[dob][month]": "5",
|
||||
"legal_entity[dob][year]": "1990",
|
||||
"legal_entity[type]": "company",
|
||||
"legal_entity[address][line1]": "123 Another Street",
|
||||
"legal_entity[address][city]": "Some City",
|
||||
"legal_entity[address][state]": "BC",
|
||||
"legal_entity[address][postal_code]": "123ABC",
|
||||
"tos_acceptance[date]": "1428338336",
|
||||
"tos_acceptance[ip]": "127.0.0.1"
|
||||
} />
|
||||
<cfset local.update = arguments.gw.updateConnectedAccount(connectedAccount = local.connectedAccountToken, options = local.fieldsNeeded) />
|
||||
<cfset standardResponseTests(response = local.update, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.update.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.update.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.update.getParsedResult().verification["fields_needed"]) EQ 0, "Fields_Needed array should be empty") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testCanadaCompanyConnectedAccountLegalEntityFields" access="public" returntype="void" output="false">
|
||||
<cfargument name="gw" type="any" required="false" default="#variables.cad#" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = "CA", options = {"legal_entity[type]": "company", "business_name": "ACME, Inc."}) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.connectedAccount.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.connectedAccount.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.connectedAccount.getParsedResult().verification["fields_needed"]) GT 0, "Fields_Needed array is empty") />
|
||||
<cfloop list="legal_entity.first_name,legal_entity.last_name,legal_entity.dob.day,legal_entity.dob.month,legal_entity.dob.year,legal_entity.address.line1,legal_entity.address.city,legal_entity.address.state,legal_entity.address.postal_code,bank_account,tos_acceptance.ip,tos_acceptance.date" index="local.fieldNeeded">
|
||||
<cfset assertTrue(listFindNoCase(arrayToList(local.connectedAccount.getParsedResult().verification["fields_needed"]), local.fieldNeeded), "Missing Fields_needed value: #local.fieldNeeded#") />
|
||||
</cfloop>
|
||||
|
||||
|
||||
<!--- now update the account and check it no longer requests anything --->
|
||||
|
||||
<!--- Create Bank Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.bankAccount = arguments.gw.createBankAccount(connectedAccount = local.connectedAccountToken, account = createBankAccountHelper(arguments.gw.country), currency = "cad") />
|
||||
<cfset standardResponseTests(response = local.bankAccount, expectedObjectName = "bank_account", expectedIdPrefix="ba_") />
|
||||
|
||||
<!--- Update Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_update_account_validation_passes_ok", "doHttpCall") />
|
||||
<cfset local.fieldsNeeded = {
|
||||
"legal_entity[first_name]": "John",
|
||||
"legal_entity[last_name]": "Smith",
|
||||
"legal_entity[dob][day]": "20",
|
||||
"legal_entity[dob][month]": "5",
|
||||
"legal_entity[dob][year]": "1990",
|
||||
"legal_entity[type]": "company",
|
||||
"legal_entity[address][line1]": "123 Another Street",
|
||||
"legal_entity[address][city]": "Some City",
|
||||
"legal_entity[address][state]": "BC",
|
||||
"legal_entity[address][postal_code]": "123ABC",
|
||||
"tos_acceptance[date]": "1428338336",
|
||||
"tos_acceptance[ip]": "127.0.0.1"
|
||||
} />
|
||||
<cfset local.update = arguments.gw.updateConnectedAccount(connectedAccount = local.connectedAccountToken, options = local.fieldsNeeded) />
|
||||
<cfset standardResponseTests(response = local.update, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.update.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.update.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.update.getParsedResult().verification["fields_needed"]) EQ 0, "Fields_Needed array should be empty") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testUSIndividualConnectedAccountLegalEntityFields" access="public" returntype="void" output="false">
|
||||
<cfargument name="gw" type="any" required="false" default="#variables.usd#" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = "US", options = {"legal_entity[type]": "individual"}) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.connectedAccount.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.connectedAccount.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.connectedAccount.getParsedResult().verification["fields_needed"]) GT 0, "Fields_Needed array is empty") />
|
||||
<cfloop list="legal_entity.first_name,legal_entity.last_name,legal_entity.dob.day,legal_entity.dob.month,legal_entity.dob.year,bank_account,tos_acceptance.ip,tos_acceptance.date" index="local.fieldNeeded">
|
||||
<cfset assertTrue(listFindNoCase(arrayToList(local.connectedAccount.getParsedResult().verification["fields_needed"]), local.fieldNeeded), "Missing Fields_needed value: #local.fieldNeeded#") />
|
||||
</cfloop>
|
||||
|
||||
|
||||
<!--- now update the account and check it no longer requests anything --->
|
||||
|
||||
<!--- Create Bank Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.bankAccount = arguments.gw.createBankAccount(connectedAccount = local.connectedAccountToken, account = createBankAccountHelper(arguments.gw.country), currency = "usd") />
|
||||
<cfset standardResponseTests(response = local.bankAccount, expectedObjectName = "bank_account", expectedIdPrefix="ba_") />
|
||||
|
||||
<!--- Update Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_update_account_validation_passes_ok", "doHttpCall") />
|
||||
<cfset local.fieldsNeeded = {
|
||||
"legal_entity[first_name]": "John",
|
||||
"legal_entity[last_name]": "Smith",
|
||||
"legal_entity[dob][day]": "20",
|
||||
"legal_entity[dob][month]": "5",
|
||||
"legal_entity[dob][year]": "1990",
|
||||
"legal_entity[type]": "company",
|
||||
"legal_entity[address][line1]": "123 Another Street",
|
||||
"legal_entity[address][city]": "Some City",
|
||||
"legal_entity[address][state]": "CA",
|
||||
"legal_entity[address][postal_code]": "94903",
|
||||
"tos_acceptance[date]": "1428338336",
|
||||
"tos_acceptance[ip]": "127.0.0.1"
|
||||
} />
|
||||
<cfset local.update = arguments.gw.updateConnectedAccount(connectedAccount = local.connectedAccountToken, options = local.fieldsNeeded) />
|
||||
<cfset standardResponseTests(response = local.update, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.update.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.update.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.update.getParsedResult().verification["fields_needed"]) EQ 0, "Fields_Needed array should be empty") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testUSCompanyConnectedAccountLegalEntityFields" access="public" returntype="void" output="false">
|
||||
<cfargument name="gw" type="any" required="false" default="#variables.usd#" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = "US", options = {"legal_entity[type]": "company", "business_name": "ACME, Inc."}) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.connectedAccount.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.connectedAccount.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.connectedAccount.getParsedResult().verification["fields_needed"]) GT 0, "Fields_Needed array is empty") />
|
||||
<cfloop list="legal_entity.first_name,legal_entity.last_name,legal_entity.dob.day,legal_entity.dob.month,legal_entity.dob.year,bank_account,tos_acceptance.ip,tos_acceptance.date" index="local.fieldNeeded">
|
||||
<cfset assertTrue(listFindNoCase(arrayToList(local.connectedAccount.getParsedResult().verification["fields_needed"]), local.fieldNeeded), "Missing Fields_needed value: #local.fieldNeeded#") />
|
||||
</cfloop>
|
||||
|
||||
|
||||
<!--- now update the account and check it no longer requests anything --->
|
||||
|
||||
<!--- Create Bank Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.bankAccount = arguments.gw.createBankAccount(connectedAccount = local.connectedAccountToken, account = createBankAccountHelper(arguments.gw.country), currency = "usd") />
|
||||
<cfset standardResponseTests(response = local.bankAccount, expectedObjectName = "bank_account", expectedIdPrefix="ba_") />
|
||||
|
||||
<!--- Update Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_update_account_validation_passes_ok", "doHttpCall") />
|
||||
<cfset local.fieldsNeeded = {
|
||||
"legal_entity[first_name]": "John",
|
||||
"legal_entity[last_name]": "Smith",
|
||||
"legal_entity[dob][day]": "20",
|
||||
"legal_entity[dob][month]": "5",
|
||||
"legal_entity[dob][year]": "1990",
|
||||
"legal_entity[type]": "company",
|
||||
"legal_entity[address][line1]": "123 Another Street",
|
||||
"legal_entity[address][city]": "Some City",
|
||||
"legal_entity[address][state]": "CA",
|
||||
"legal_entity[address][postal_code]": "94903",
|
||||
"tos_acceptance[date]": "1428338336",
|
||||
"tos_acceptance[ip]": "127.0.0.1"
|
||||
} />
|
||||
<cfset local.update = arguments.gw.updateConnectedAccount(connectedAccount = local.connectedAccountToken, options = local.fieldsNeeded) />
|
||||
<cfset standardResponseTests(response = local.update, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.update.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.update.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.update.getParsedResult().verification["fields_needed"]) EQ 0, "Fields_Needed array should be empty") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testAUCompanyConnectedAccountLegalEntityFields" access="public" returntype="void" output="false">
|
||||
<cfargument name="gw" type="any" required="false" default="#variables.usd#" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = "AU", options = {"legal_entity[type]": "company", "business_name": "ACME, Inc."}) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.connectedAccount.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.connectedAccount.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.connectedAccount.getParsedResult().verification["fields_needed"]) GT 0, "Fields_Needed array is empty") />
|
||||
<cfloop list="legal_entity.first_name,legal_entity.last_name,legal_entity.dob.day,legal_entity.dob.month,legal_entity.dob.year,bank_account,tos_acceptance.ip,tos_acceptance.date" index="local.fieldNeeded">
|
||||
<cfset assertTrue(listFindNoCase(arrayToList(local.connectedAccount.getParsedResult().verification["fields_needed"]), local.fieldNeeded), "Missing Fields_needed value: #local.fieldNeeded#") />
|
||||
</cfloop>
|
||||
|
||||
|
||||
<!--- now update the account and check it no longer requests anything --->
|
||||
|
||||
<!--- Create Bank Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.bankAccount = arguments.gw.createBankAccount(connectedAccount = local.connectedAccountToken, account = createBankAccountHelper("au"), currency = "aud") />
|
||||
<cfset standardResponseTests(response = local.bankAccount, expectedObjectName = "bank_account", expectedIdPrefix="ba_") />
|
||||
|
||||
<!--- Update Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_update_account_validation_passes_ok", "doHttpCall") />
|
||||
<cfset local.fieldsNeeded = {
|
||||
"legal_entity[first_name]": "John",
|
||||
"legal_entity[last_name]": "Smith",
|
||||
"legal_entity[dob][day]": "20",
|
||||
"legal_entity[dob][month]": "5",
|
||||
"legal_entity[dob][year]": "1990",
|
||||
"legal_entity[type]": "company",
|
||||
"legal_entity[address][line1]": "123 Another Street",
|
||||
"legal_entity[address][city]": "Cairns",
|
||||
"legal_entity[address][state]": "QLD",
|
||||
"legal_entity[address][postal_code]": "4870",
|
||||
"legal_entity[business_name]": "ACME, Pvt.",
|
||||
"legal_entity[business_tax_id]": "000000000",
|
||||
"tos_acceptance[date]": "1428338336",
|
||||
"tos_acceptance[ip]": "127.0.0.1"
|
||||
} />
|
||||
<cfset local.update = arguments.gw.updateConnectedAccount(connectedAccount = local.connectedAccountToken, options = local.fieldsNeeded) />
|
||||
<cfset standardResponseTests(response = local.update, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.update.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.update.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.update.getParsedResult().verification["fields_needed"]) EQ 0, "Fields_Needed array should be empty") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testUKCompanyConnectedAccountLegalEntityFields" access="public" returntype="void" output="false">
|
||||
<cfargument name="gw" type="any" required="false" default="#variables.usd#" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = "GB", options = {"legal_entity[type]": "company", "business_name": "ACME, Ltd."}) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.connectedAccount.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.connectedAccount.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.connectedAccount.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.connectedAccount.getParsedResult().verification["fields_needed"]) GT 0, "Fields_Needed array is empty") />
|
||||
<cfloop list="legal_entity.additional_owners,legal_entity.first_name,legal_entity.last_name,legal_entity.dob.day,legal_entity.dob.month,legal_entity.dob.year,bank_account,tos_acceptance.ip,tos_acceptance.date" index="local.fieldNeeded">
|
||||
<cfset assertTrue(listFindNoCase(arrayToList(local.connectedAccount.getParsedResult().verification["fields_needed"]), local.fieldNeeded), "Missing Fields_needed value: #local.fieldNeeded#") />
|
||||
</cfloop>
|
||||
|
||||
|
||||
|
||||
<!--- now update the account and check it no longer requests anything --->
|
||||
|
||||
<!--- Create Bank Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.bankAccount = arguments.gw.createBankAccount(connectedAccount = local.connectedAccountToken, account = createBankAccountHelper("GB"), currency = "gbp") />
|
||||
<cfset standardResponseTests(response = local.bankAccount, expectedObjectName = "bank_account", expectedIdPrefix="ba_") />
|
||||
|
||||
<!--- Update Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_update_account_validation_passes_ok", "doHttpCall") />
|
||||
<cfset local.fieldsNeeded = {
|
||||
"legal_entity[first_name]": "John",
|
||||
"legal_entity[last_name]": "Smith",
|
||||
"legal_entity[dob][day]": "20",
|
||||
"legal_entity[dob][month]": "5",
|
||||
"legal_entity[dob][year]": "1990",
|
||||
"legal_entity[type]": "company",
|
||||
"legal_entity[address][line1]": "123 Another Street",
|
||||
"legal_entity[address][city]": "London",
|
||||
"legal_entity[address][postal_code]": "WC2N 5DU",
|
||||
"legal_entity[additional_owners]": "",
|
||||
"legal_entity[personal_address][line1]": "123 Another Street",
|
||||
"legal_entity[personal_address][city]": "London",
|
||||
"legal_entity[personal_address][postal_code]": "WC2N 5DU",
|
||||
"tos_acceptance[date]": "1428338336",
|
||||
"tos_acceptance[ip]": "127.0.0.1",
|
||||
"legal_entity[business_name]": "ACME, Ltd.",
|
||||
"legal_entity[business_tax_id]": "000000000",
|
||||
"transfer_schedule[delay_days]": 4,
|
||||
"transfer_schedule[interval]": "weekly",
|
||||
"transfer_schedule[weekly_anchor]": "monday",
|
||||
"legal_entity[personal_id_number]": "000000000"
|
||||
} />
|
||||
|
||||
// 000000001 = validate ok as non-profit
|
||||
// 111111111 = unsuccessful validation
|
||||
|
||||
<cfset local.update = arguments.gw.updateConnectedAccount(connectedAccount = local.connectedAccountToken, options = local.fieldsNeeded) />
|
||||
<cfset standardResponseTests(response = local.update, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult(), "verification"), "Verification missing in return data") />
|
||||
<cfset assertTrue(isStruct(local.update.getParsedResult().verification), "Verification data is not a struct") />
|
||||
<cfset assertTrue(structKeyExists(local.update.getParsedResult().verification, "fields_needed"), "Fields_Needed missing in return data") />
|
||||
<cfset assertTrue(isArray(local.update.getParsedResult().verification["fields_needed"]), "Fields_Needed data is not an array") />
|
||||
<cfset assertTrue(arrayLen(local.update.getParsedResult().verification["fields_needed"]) EQ 0, "Fields_Needed array should be empty") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- Bank Account Tests --->
|
||||
<cffunction name="testListBankAccounts" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = "US") />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
|
||||
<!--- Fetch Attached Bank Accounts --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_fetch_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.bankAccounts = arguments.gw.listBankAccounts(connectedAccount = local.connectedAccountToken) />
|
||||
<cfset standardResponseTests(response = local.bankAccounts, expectedObjectName = "list", expectedIdPrefix="") />
|
||||
<cfset assertTrue(structKeyExists(local.bankAccounts.getParsedResult(), "data") AND isArray(local.bankAccounts.getParsedResult().data), "Invalid bank account list") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testCreateBankAccount" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset local.account = createBankAccountHelper(arguments.gw.country) />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = arguments.gw.country) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
|
||||
<!--- Create Bank Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.bankAccount = arguments.gw.createBankAccount(connectedAccount = local.connectedAccountToken, account = account, currency = arguments.gw.currency) />
|
||||
<cfset standardResponseTests(response = local.bankAccount, expectedObjectName = "bank_account", expectedIdPrefix="ba_") />
|
||||
|
||||
<cfset assertTrue(bankAccount.getParsedResult().object EQ "bank_account", "Object type wasn't bank_account") />
|
||||
<cfset assertTrue(bankAccount.getParsedResult().last4 EQ "6789", "last4 didn't match") />
|
||||
<cfset assertTrue(bankAccount.getTransactionId() EQ bankAccount.getTokenID(), "The token ID should be put into the token field when created, was: #bankAccount.getTokenID()#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testUpdateBankAccountDefaultForCurrencyAndDelete" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = arguments.gw.country) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
|
||||
<!--- Create Bank Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.bankAccount = arguments.gw.createBankAccount(connectedAccount = local.connectedAccountToken, account = createBankAccountHelper(arguments.gw.country), currency = arguments.gw.currency) />
|
||||
<cfset standardResponseTests(response = local.bankAccount, expectedObjectName = "bank_account", expectedIdPrefix="ba_") />
|
||||
|
||||
<!--- Create Another Bank Account; Creating two bank account because you can't delete the account that is 'default for currency' --->
|
||||
<cfset local.second = createBankAccountHelper(arguments.gw.country) />
|
||||
<cfset second.setFirstName("Jane") />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_second_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.bankAccount2 = arguments.gw.createBankAccount(connectedAccount = local.connectedAccountToken, account = second, currency = arguments.gw.currency) />
|
||||
<cfset standardResponseTests(response = local.bankAccount2, expectedObjectName = "bank_account", expectedIdPrefix="ba_") />
|
||||
<cfset assertTrue(local.bankAccount2.getTransactionId() NEQ local.bankaccount.getTransactionId(), "Second account wasn't created separately from the first") />
|
||||
|
||||
<!--- try to Delete default Bank Account, should fail --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_delete_bank_accounts_fail", "doHttpCall") />
|
||||
<cfset local.delete = arguments.gw.deleteBankAccount(connectedAccount = local.connectedAccountToken, bankAccountId = local.bankAccount.getTransactionId()) />
|
||||
<cfset standardErrorResponseTests(response = local.delete, expectedStatusCode="400", expectedErrorType = "invalid_request_error") />
|
||||
|
||||
<!--- Make second Bank Account Default For Currency --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_update_bank_account_default_for_currency_ok", "doHttpCall") />
|
||||
<cfset local.update = arguments.gw.setDefaultBankAccountForCurrency(connectedAccount = local.connectedAccountToken, bankAccountId = local.bankAccount2.getTransactionId()) />
|
||||
<cfset standardResponseTests(response = local.update, expectedObjectName = "bank_account", expectedIdPrefix="ba_") />
|
||||
<cfset assertTrue(local.update.getSuccess(), "Request didn't succeed") />
|
||||
<cfset assertTrue(local.update.getParsedResult().default_for_currency EQ true, "Default for currency not set to true") />
|
||||
|
||||
<!--- Now Delete Original Bank Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_delete_bank_accounts_ok", "doHttpCall") />
|
||||
<cfset local.delete = arguments.gw.deleteBankAccount(connectedAccount = local.connectedAccountToken, bankAccountId = local.bankAccount.getTransactionId()) />
|
||||
<cfset standardResponseTests(response = local.delete, expectedObjectName = "", expectedIdPrefix="ba_") />
|
||||
<cfset assertTrue(local.delete.getSuccess(), "Delete did not succeed") />
|
||||
<cfset assertTrue(local.delete.getParsedResult().deleted EQ true, "Failed to delete the original (not default for currency) bank account") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- Identity Verification Tests --->
|
||||
<cffunction name="testUploadIdentityFile" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_upload_identity_file_ok", "doHttpCall") />
|
||||
<cfset local.uploadFile = arguments.gw.uploadFile(file = variables.filePathToSampleLicence, purpose = "identity_document") />
|
||||
<cfset standardResponseTests(response = local.uploadFile, expectedObjectName = "file_upload", expectedIdPrefix="file_") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testUploadFileWithoutPurposeThrowsError" access="public" returntype="void" output="false" mxunit:dataprovider="gateways" mxunit:expectedexception="cfpayment.invalidarguments">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_upload_identity_file_ok", "doHttpCall") />
|
||||
<cfset local.uploadFile = arguments.gw.uploadFile(file = variables.filePathToSampleLicence, purpose = "bogus") />
|
||||
<cfset assertTrue(false, "Should have thrown an exception") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testUploadAndAttachIdentityFileToAccount" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<!--- Create Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_create_account_ok", "doHttpCall") />
|
||||
<cfset local.connectedAccount = arguments.gw.createConnectedAccount(managed = true, country = arguments.gw.country) />
|
||||
<cfset standardResponseTests(response = local.connectedAccount, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset local.connectedAccountToken = variables.svc.createToken().setID(local.connectedAccount.getTransactionId()) />
|
||||
|
||||
<!--- Upload Identity File --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_upload_identity_file_ok", "doHttpCall") />
|
||||
<cfset local.uploadFile = arguments.gw.uploadFile(file = variables.filePathToSampleLicence, purpose = "identity_document") />
|
||||
<cfset standardResponseTests(response = local.uploadFile, expectedObjectName = "file_upload", expectedIdPrefix="file_") />
|
||||
|
||||
<!--- Attach Identity File to Connected Account --->
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_attach_file_to_account_ok", "doHttpCall") />
|
||||
<cfset local.attachFile = arguments.gw.attachIdentityFile(ConnectedAccount = local.connectedAccountToken, fileId = local.uploadFile.getTransactionId()) />
|
||||
<cfset standardResponseTests(response = local.attachFile, expectedObjectName = "account", expectedIdPrefix="acct_") />
|
||||
<cfset assertTrue(local.uploadFile.getTransactionId() EQ local.attachFile.getParsedResult()["legal_entity"]["verification"]["document"], "Identity file not attached to account") />
|
||||
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<!--- HELPERS --->
|
||||
<cffunction name="createBankAccountHelper" access="private" returntype="any" output="false">
|
||||
<cfargument name="country" type="string" required="true" />
|
||||
|
||||
<cfset local.account = variables.svc.createEFT() />
|
||||
<cfset local.account.setFirstName("John") />
|
||||
<cfset local.account.setLastName("Doe") />
|
||||
<cfset local.account.setAddress("123 Comox Street") />
|
||||
<cfset local.account.setPhoneNumber("0123456789") />
|
||||
<cfset local.account.setAccount(000123456789) />
|
||||
<cfset local.account.setRoutingNumber(110000000) />
|
||||
|
||||
<cfif lcase(arguments.country) EQ "ca">
|
||||
<cfset local.account.setAddress2("West End") />
|
||||
<cfset local.account.setCity("Vancouver") />
|
||||
<cfset local.account.setRegion("BC") />
|
||||
<cfset local.account.setPostalCode("V6G1S2") />
|
||||
<cfset local.account.setCountry("CA") />
|
||||
<cfelseif lcase(arguments.country) EQ "gb">
|
||||
<cfset local.account.setAddress2("") />
|
||||
<cfset local.account.setCity("London") />
|
||||
<cfset local.account.setPostalCode("WC2N 5DU") />
|
||||
<cfset local.account.setCountry("GB") />
|
||||
<cfset local.account.setAccount("00012345") />
|
||||
<cfset local.account.setRoutingNumber(108800) />
|
||||
<cfelseif lcase(arguments.country) EQ "au">
|
||||
<cfset local.account.setAddress2("") />
|
||||
<cfset local.account.setCity("Sydney") />
|
||||
<cfset local.account.setPostalCode("4870") />
|
||||
<cfset local.account.setCountry("AU") />
|
||||
<cfset local.account.setAccount("000123456") />
|
||||
<cfset local.account.setRoutingNumber(110000) />
|
||||
<cfelseif lcase(arguments.country) EQ "us">
|
||||
<cfset local.account.setAddress2("") />
|
||||
<cfset local.account.setCity("San Francisco") />
|
||||
<cfset local.account.setRegion("CA") />
|
||||
<cfset local.account.setPostalCode("94107") />
|
||||
<cfset local.account.setCountry("US") />
|
||||
</cfif>
|
||||
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<cffunction name="createCardHelper" access="private" returntype="any" output="false">
|
||||
<!--- these values simulate a valid card with matching avs/cvv --->
|
||||
<cfset local.account = variables.svc.createCreditCard() />
|
||||
<cfset local.account.setAccount(4000000000000077) />
|
||||
<cfset local.account.setMonth(10) />
|
||||
<cfset local.account.setYear(year(now())+1) />
|
||||
<cfset local.account.setVerificationValue(999) />
|
||||
<cfset local.account.setFirstName("John") />
|
||||
<cfset local.account.setLastName("Doe") />
|
||||
<cfset local.account.setAddress("888") />
|
||||
<cfset local.account.setPostalCode("77777") />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<!--- MOCKS --->
|
||||
<cffunction name="mock_create_account_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "acct_15oe3nHQ9U3jyomi", "email": "test20150406173055@test.tst", "statement_descriptor": null, "display_name": null, "timezone": "Etc/UTC", "details_submitted": false, "charges_enabled": true, "transfers_enabled": false, "currencies_supported": [ "cad", "usd" ], "default_currency": "cad", "country": "CA", "object": "account", "business_name": null, "business_url": null, "support_phone": null, "metadata": {}, "managed": true, "product_description": null, "debit_negative_balances": false, "bank_accounts": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/accounts/acct_15oe3nHQ9U3jyomi/bank_accounts", "data": [] }, "verification": { "fields_needed": [ "legal_entity.first_name", "legal_entity.last_name", "legal_entity.dob.day", "legal_entity.dob.month", "legal_entity.dob.year", "legal_entity.type", "legal_entity.address.line1", "legal_entity.address.city", "legal_entity.address.state", "legal_entity.address.postal_code", "bank_account", "tos_acceptance.ip", "tos_acceptance.date" ], "due_by": null, "contacted": false }, "transfer_schedule": { "delay_days": 7, "interval": "daily" }, "tos_acceptance": { "ip": null, "date": null, "user_agent": null }, "legal_entity": { "type": null, "business_name": null, "address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": "CA" }, "first_name": null, "last_name": null, "personal_address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": null }, "dob": { "day": null, "month": null, "year": null }, "additional_owners": null, "verification": { "status": "unchecked", "document": null, "details": null } }, "decline_charge_on": { "cvc_failure": false, "avs_failure": false }, "keys": { "secret": "sk_test_kSx0VSZW6TvnoHCfBoVMFXpq", "publishable": "pk_test_MjuNj3ynAShrhv2OgvHoi46X" } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_update_account_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "acct_167t3LFmyHUsZLgr", "email": "test1234@testing123.tst", "statement_descriptor": null, "display_name": null, "timezone": "Etc/UTC", "details_submitted": false, "charges_enabled": true, "transfers_enabled": false, "currencies_supported": [ "usd", "aed", "afn", "all", "amd", "ang", "aoa", "ars", "aud", "awg", "azn", "bam", "bbd", "bdt", "bgn", "bif", "bmd", "bnd", "bob", "brl", "bsd", "bwp", "bzd", "cad", "cdf", "chf", "clp", "cny", "cop", "crc", "cve", "czk", "djf", "dkk", "dop", "dzd", "eek", "egp", "etb", "eur", "fjd", "fkp", "gbp", "gel", "gip", "gmd", "gnf", "gtq", "gyd", "hkd", "hnl", "hrk", "htg", "huf", "idr", "ils", "inr", "isk", "jmd", "jpy", "kes", "kgs", "khr", "kmf", "krw", "kyd", "kzt", "lak", "lbp", "lkr", "lrd", "lsl", "ltl", "lvl", "mad", "mdl", "mga", "mkd", "mnt", "mop", "mro", "mur", "mvr", "mwk", "mxn", "myr", "mzn", "nad", "ngn", "nio", "nok", "npr", "nzd", "pab", "pen", "pgk", "php", "pkr", "pln", "pyg", "qar", "ron", "rsd", "rub", "rwf", "sar", "sbd", "scr", "sek", "sgd", "shp", "sll", "sos", "srd", "std", "svc", "szl", "thb", "tjs", "top", "try", "ttd", "twd", "tzs", "uah", "ugx", "uyu", "uzs", "vnd", "vuv", "wst", "xaf", "xcd", "xof", "xpf", "yer", "zar", "zmw" ], "default_currency": "usd", "country": "US", "object": "account", "business_name": null, "business_url": null, "support_phone": null, "metadata": {}, "managed": true, "product_description": null, "debit_negative_balances": false, "bank_accounts": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/accounts/acct_167t3LFmyHUsZLgr/bank_accounts", "data": [] }, "verification": { "fields_needed": [ "legal_entity.dob.day", "legal_entity.dob.month", "legal_entity.dob.year", "legal_entity.type", "bank_account", "tos_acceptance.ip", "tos_acceptance.date" ], "due_by": null, "contacted": false }, "transfer_schedule": { "delay_days": 2, "interval": "daily" }, "decline_charge_on": { "cvc_failure": true, "avs_failure": false }, "tos_acceptance": { "ip": null, "date": null, "user_agent": null }, "legal_entity": { "type": null, "business_name": null, "address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": "US" }, "first_name": "John", "last_name": "Smith", "personal_address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": null }, "dob": { "day": null, "month": null, "year": null }, "additional_owners": null, "verification": { "status": "unverified", "document": null, "details": null } } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_account_list_ok" access="private">
|
||||
<cfsavecontent variable="local.response">
|
||||
{ "object": "list", "has_more": false, "url": "/v1/accounts", "data": [ { "id": "acct_15c27zIZh3r4vhIW", "email": null, "statement_descriptor": null, "display_name": null, "timezone": "Etc/UTC", "details_submitted": false, "charges_enabled": true, "transfers_enabled": false, "currencies_supported": [ "cad", "usd" ], "default_currency": "cad", "country": "CA", "object": "account", "business_name": null, "managed": true, "product_description": null, "legal_entity": { "type": null, "business_name": null, "address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": "CA" }, "first_name": null, "last_name": null, "personal_address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": null }, "dob": { "day": null, "month": null, "year": null }, "additional_owners": null, "verification": { "status": "unchecked", "document": null, "details": null } }, "bank_accounts": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/accounts/acct_15c27zIZh3r4vhIW/bank_accounts", "data": [] }, "verification": { "fields_needed": [ "legal_entity.type", "tos_acceptance.ip", "tos_acceptance.date" ], "due_by": null, "contacted": false }, "transfer_schedule": { "delay_days": 7, "interval": "daily" }, "tos_acceptance": { "date": null, "ip": null, "user_agent": null }, "decline_charge_on": { "cvc_failure": false, "avs_failure": false } }, { "id": "acct_15c25oAiIdhH6A9Z", "email": null, "statement_descriptor": null, "display_name": null, "timezone": "Etc/UTC", "details_submitted": false, "charges_enabled": true, "transfers_enabled": false, "currencies_supported": [ "cad", "usd" ], "default_currency": "cad", "country": "CA", "object": "account", "business_name": null, "managed": true, "product_description": null, "legal_entity": { "type": null, "business_name": null
|
||||
, "address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": "CA" }, "first_name": null, "last_name": null, "personal_address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": null }, "dob": { "day": null, "month": null, "year": null }, "additional_owners": null
|
||||
, "verification": { "status": "unchecked", "document": null, "details": null } }, "bank_accounts": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/accounts/acct_15c25oAiIdhH6A9Z/bank_accounts", "data": [] }, "verification": { "fields_needed": [ "legal_entity.type", "tos_acceptance.ip", "tos_acceptance.date" ], "due_by": null, "contacted": false }, "transfer_schedule": { "delay_days": 7, "interval": "daily" }, "tos_acceptance": { "date": null, "ip": null, "user_agent": null }, "decline_charge_on": { "cvc_failure": false, "avs_failure": false } }, { "id": "acct_15c1qTLoeW7UuY75", "email": null, "statement_descriptor": null, "display_name": null, "timezone": "Etc/UTC", "details_submitted": false, "charges_enabled": true, "transfers_enabled": false, "currencies_supported": [ "cad", "usd" ], "default_currency": "cad", "country": "CA", "object": "account", "business_name": null, "managed": true, "product_description": null, "legal_entity": { "type": null, "business_name": null, "address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": "CA" }, "first_name": null, "last_name": null, "personal_address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": null }, "dob": { "day": null, "month": null, "year": null }, "additional_owners": null, "verification": { "status": "unchecked", "document": null, "details": null } }, "bank_accounts": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/accounts/acct_15c1qTLoeW7UuY75/bank_accounts", "data": [] }, "verification": { "fields_needed": [ "legal_entity.type", "tos_acceptance.ip", "tos_acceptance.date" ], "due_by": null, "contacted": false }, "transfer_schedule": { "delay_days": 7, "interval": "daily" }, "tos_acceptance": { "date": null, "ip": null, "user_agent": null }, "decline_charge_on": { "cvc_failure": false, "avs_failure": false } } ]
|
||||
}
|
||||
</cfsavecontent>
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = response } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_update_account_failed" access="private">
|
||||
<cfreturn { StatusCode = '400', FileContent = '{ "error": { "type": "invalid_request_error", "message": "Received unknown parameter: invalid_field", "param": "legal_entity[invalid_field]" } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_fetch_bank_accounts_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "object": "list", "has_more": false, "url": "/v1/accounts/acct_15evLLHaSSWBs4PJ/bank_accounts", "data": [] }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_create_bank_accounts_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "object": "bank_account", "id": "ba_15evN2HEZw7xP8G6coTn3y2U", "last4": "6789", "country": "CA", "currency": "cad", "status": "new", "fingerprint": "e98PVX2dQLLJ1Bw9", "routing_number": "11000-000", "bank_name": null, "default_for_currency": true }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_create_second_bank_accounts_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "object": "bank_account", "id": "ba_9999N2HEZw7xP8G6coTn3y2U", "last4": "6789", "country": "CA", "currency": "cad", "status": "new", "fingerprint": "e98PVX2dQLLJ1Bw9", "routing_number": "11000-000", "bank_name": null, "default_for_currency": true }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_update_bank_account_default_for_currency_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "object": "bank_account", "id": "ba_15evOMFGW0X7HhxV2gbtrn5V", "last4": "6789", "country": "CA", "currency": "cad", "status": "new", "fingerprint": "EUxpUGhRCfb41TLf", "routing_number": "11000-000", "bank_name": null, "default_for_currency": true }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_delete_bank_accounts_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "deleted": true, "id": "ba_15evOqJNkvLfahU0w4cHM6jU", "currency": "cad" }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_delete_bank_accounts_fail" access="private">
|
||||
<cfreturn { StatusCode = '400 OK', FileContent = '{ "error": { "type": "invalid_request_error", "message": "You cannot delete the default bank account for your default currency. Please make another bank account the default using the `default_for_currency` param, and then delete this one." } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_upload_identity_file_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "file_15iCG7D8ot0g87U6Wxb15c1r", "created": 1426024967, "size": 65264, "purpose": "identity_document", "object": "file_upload", "url": null, "type": "jpg" }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_attach_file_to_account_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "acct_15i6p8KgBEwCAJe8", "email": "test20150319094848@test.tst", "statement_descriptor": null, "display_name": null, "timezone": "Etc/UTC", "details_submitted": false, "charges_enabled": true, "transfers_enabled": false, "currencies_supported": [ "cad", "usd" ], "default_currency": "cad", "country": "CA", "object": "account", "business_name": null, "business_url": null, "support_phone": null, "managed": true, "product_description": null, "debit_negative_balances": false, "bank_accounts": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/accounts/acct_15i6p8KgBEwCAJe8/bank_accounts", "data": [] }, "verification": { "fields_needed": [ "legal_entity.first_name", "legal_entity.last_name", "legal_entity.dob.day", "legal_entity.dob.month", "legal_entity.dob.year", "legal_entity.type", "legal_entity.address.line1", "legal_entity.address.city", "legal_entity.address.state", "legal_entity.address.postal_code", "bank_account", "tos_acceptance.ip", "tos_acceptance.date" ], "due_by": null, "contacted": false }, "transfer_schedule": { "delay_days": 7, "interval": "daily" }, "tos_acceptance": { "ip": null, "date": null, "user_agent": null }, "legal_entity": { "type": null, "business_name": null, "address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": "CA" }, "first_name": null, "last_name": null, "personal_address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": null }, "dob": { "day": null, "month": null, "year": null }, "additional_owners": null, "verification": { "status": "unchecked", "document": "file_15iCG7D8ot0g87U6Wxb15c1r", "details": null } }, "decline_charge_on": { "cvc_failure": false, "avs_failure": false } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_create_card_token_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "tok_5qdFdkEadGlyLE", "livemode": false, "created": 1426027056, "used": false, "object": "token", "type": "card", "card": { "id": "card_5qdFxMBYbFKN4K", "object": "card", "last4": "0077", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "NZ56hJ5g3nSG1X1f", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "unchecked", "address_line1_check": "unchecked", "address_zip_check": "unchecked", "dynamic_last4": null }, "client_ip": "184.66.107.116" }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_create_customer_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "object": "customer", "created": 1426783987, "id": "cus_5tui4CxfSIMCPh", "livemode": false, "description": null, "email": null, "delinquent": false, "metadata": {}, "subscriptions": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/customers/cus_5tui4CxfSIMCPh/subscriptions", "data": [] }, "discount": null, "account_balance": 0, "currency": null, "sources": { "object": "list", "total_count": 1, "has_more": false, "url": "/v1/customers/cus_5tui4CxfSIMCPh/sources", "data": [ { "id": "card_5tuiNbFo56IX17", "object": "card", "last4": "0077", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "NZ56hJ5g3nSG1X1f", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass", "dynamic_last4": null, "metadata": {}, "customer": "cus_5tui4CxfSIMCPh" } ] }, "default_source": "card_5tuiNbFo56IX17" }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_get_token_for_customer_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "tok_15i6vOBzXo04pSHuixVMHcTl", "livemode": false, "created": 1426784114, "used": false, "object": "token", "type": "card", "card": { "id": "card_15i6vOBzXo04pSHuW1cb74Cy", "object": "card", "last4": "0077", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "l8rbA7VqfygKBhfJ", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "unchecked", "address_line1_check": "unchecked", "address_zip_check": "unchecked", "dynamic_last4": null }, "client_ip": "184.66.107.116" }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_charge_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "ch_5qdkfZcTB6Z29E", "object": "charge", "created": 1426028918, "livemode": false, "paid": true, "status": "succeeded", "amount": 1000, "currency": "cad", "refunded": false, "source": { "id": "card_5qdkgctPOLlZi3", "object": "card", "last4": "0077", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "NZ56hJ5g3nSG1X1f", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass", "dynamic_last4": null, "metadata": {}, "customer": null }, "captured": true, "balance_transaction": "txn_5qdkXWc0zYCeP9", "failure_message": null, "failure_code": null, "amount_refunded": 0, "customer": null, "invoice": null, "description": "unit-test charge", "dispute": null, "metadata": {}, "statement_descriptor": null, "fraud_details": {}, "receipt_email": null, "receipt_number": null, "shipping": null, "application_fee": null, "refunds": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/charges/ch_5qdkfZcTB6Z29E/refunds", "data": [] } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_direct_charge_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "ch_5m7WiasFMFf5A5", "object": "charge", "created": 1424986511, "livemode": false, "paid": true, "status": "succeeded", "amount": 5000, "currency": "cad", "refunded": false, "source": { "id": "card_5m7WAou95fVC5b", "object": "card", "last4": "4242", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "sBxTyx7XVdjznwyt", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass", "dynamic_last4": null, "metadata": { }, "customer": null }, "captured": true, "balance_transaction": "txn_1IeEOass2YWqgM", "failure_message": null, "failure_code": null, "amount_refunded": 0, "customer": null, "invoice": null, "description": null, "dispute": null, "metadata": { }, "statement_descriptor": null, "fraud_details": { }, "receipt_email": null, "receipt_number": null, "shipping": null, "application_fee": null, "refunds": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/charges/ch_5m7WiasFMFf5A5/refunds", "data": [ ] } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_destination_charge_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "ch_5m7WiasFMFf5A5", "object": "charge", "created": 1424986511, "livemode": false, "paid": true, "status": "succeeded", "amount": 5000, "currency": "cad", "refunded": false, "source": { "id": "card_5m7WAou95fVC5b", "object": "card", "last4": "4242", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "sBxTyx7XVdjznwyt", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass", "dynamic_last4": null, "metadata": { }, "customer": null }, "captured": true, "balance_transaction": "txn_1IeEOass2YWqgM", "failure_message": null, "failure_code": null, "amount_refunded": 0, "customer": null, "invoice": null, "description": null, "dispute": null, "metadata": { }, "statement_descriptor": null, "fraud_details": { }, "receipt_email": null, "receipt_number": null, "shipping": null, "application_fee": null, "refunds": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/charges/ch_5m7WiasFMFf5A5/refunds", "data": [ ] } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_refund_charge_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "re_1hd2eEhc0a2gF2", "amount": 46000, "currency": "cad", "created": 1366751825, "object": "refund", "balance_transaction": "txn_1hd2bCSoaEP0e5", "metadata": { }, "charge": "ch_1hCcxjT1gTWGWz", "receipt_number": null, "reason": null }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_refund_charge_to_connected_account_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "re_1hd2eEhc0a2gF2", "amount": 46000, "currency": "cad", "created": 1366751825, "object": "refund", "balance_transaction": "txn_1hd2bCSoaEP0e5", "metadata": { }, "charge": "ch_1hCcxjT1gTWGWz", "receipt_number": null, "reason": null }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_refund_to_account_pulling_back_funds_from_connected_account_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "re_1hd2eEhc0a2gF2", "amount": 46000, "currency": "cad", "created": 1366751825, "object": "refund", "balance_transaction": "txn_1hd2bCSoaEP0e5", "metadata": { }, "charge": "ch_1hCcxjT1gTWGWz", "receipt_number": null, "reason": null }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_transfer_from_platform_stripe_account_to_connected_stripe_account_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "tr_5tush9wjXsddbe", "object": "transfer", "created": 1426784550, "date": 1426784550, "livemode": false, "amount": 500, "currency": "cad", "reversed": false, "status": "pending", "type": "stripe_account", "reversals": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/transfers/tr_5tush9wjXsddbe/reversals", "data": [] }, "balance_transaction": "txn_5tusPLMfovpTbD", "destination": "acct_15i72LBYaeaZycDD", "destination_payment": "py_15i72QBYaeaZycDDmMwTmIJB", "description": null, "failure_message": null, "failure_code": null, "amount_reversed": 0, "metadata": {}, "statement_descriptor": null, "recipient": null, "source_transaction": null, "application_fee": null }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_transfer_with_application_fee_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "tr_5tv0QCDmEcYE7R", "object": "transfer", "created": 1426785025, "date": 1426785025, "livemode": false, "amount": 500, "currency": "cad", "reversed": false, "status": "pending", "type": "stripe_account", "reversals": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/transfers/tr_5tv0QCDmEcYE7R/reversals", "data": [] }, "balance_transaction": "txn_5tv0uxCGuEPTa6", "destination": "acct_15i7A0GTR51tuS9z", "destination_payment": "py_15i7A5GTR51tuS9z12wPQbnF", "description": null, "failure_message": null, "failure_code": null, "amount_reversed": 0, "metadata": {}, "statement_descriptor": null, "recipient": null, "source_transaction": null, "application_fee": "fee_5tv0IlPjoHmF8M" }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_reversing_transfer_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "pyr_15i77sFzV7U7txffAAvDxyqa", "amount": 400, "currency": "cad", "created": 1426784888, "object": "refund", "balance_transaction": "txn_15i77sFzV7U7txffQ6nxf0Hp", "metadata": {}, "charge": "py_15i77rFzV7U7txffRp9gEQaF", "receipt_number": null, "reason": null }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_update_account_validation_passes_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "acct_15odyvFUmKIEYcf3", "email": "test20150406172553@test.tst", "statement_descriptor": null, "display_name": null, "timezone": "Etc/UTC", "details_submitted": false, "charges_enabled": true, "transfers_enabled": true, "currencies_supported": [ "cad", "usd" ], "default_currency": "cad", "country": "CA", "object": "account", "business_name": null, "business_url": null, "support_phone": null, "metadata": {}, "managed": true, "product_description": null, "debit_negative_balances": false, "bank_accounts": { "object": "list", "total_count": 1, "has_more": false, "url": "/v1/accounts/acct_15odyvFUmKIEYcf3/bank_accounts", "data": [ { "object": "bank_account", "id": "ba_15odywFUmKIEYcf3q2ZDAw0L", "last4": "6789", "country": "CA", "currency": "cad", "status": "new", "fingerprint": "Z3T7RQTuRWxBOKav", "routing_number": "11000-000", "bank_name": null, "default_for_currency": true } ] }, "verification": { "fields_needed": [], "due_by": null, "contacted": false }, "transfer_schedule": { "delay_days": 7, "interval": "daily" }, "tos_acceptance": { "ip": "184.66.107.116", "date": 1428338336, "user_agent": null }, "legal_entity": { "type": "company", "business_name": null, "address": { "line1": "123 Another Street", "line2": null, "city": "Some City", "state": "A State", "postal_code": "123ABC", "country": "CA" }, "first_name": "John", "last_name": "Smith", "personal_address": { "line1": null, "line2": null, "city": null, "state": null, "postal_code": null, "country": null }, "dob": { "day": 20, "month": 5, "year": 1990 }, "additional_owners": null, "verification": { "status": "unchecked", "document": null, "details": null } }, "decline_charge_on": { "cvc_failure": false, "avs_failure": false } }' } />
|
||||
</cffunction>
|
||||
</cfcomponent>
|
||||
File diff suppressed because it is too large
Load diff
682
cfpayment/api/gateway/stripe/tests/StripeTest.cfc
Normal file
682
cfpayment/api/gateway/stripe/tests/StripeTest.cfc
Normal file
|
|
@ -0,0 +1,682 @@
|
|||
<cfcomponent name="StripeTest" extends="BaseStripeTest" output="false">
|
||||
|
||||
<!---
|
||||
|
||||
From https://stripe.com/docs/testing#cards :
|
||||
In test mode, you can use these test cards to simulate a successful transaction:
|
||||
|
||||
Number Card type
|
||||
4242424242424242 Visa
|
||||
4012888888881881 Visa
|
||||
5555555555554444 MasterCard
|
||||
5105105105105100 MasterCard
|
||||
378282246310005 American Express
|
||||
371449635398431 American Express
|
||||
6011111111111117 Discover
|
||||
6011000990139424 Discover
|
||||
30569309025904 Diner's Club
|
||||
38520000023237 Diner's Club
|
||||
3530111333300000 JCB
|
||||
3566002020360505 JCB
|
||||
In addition, these cards will produce specific responses that are useful for testing different scenarios:
|
||||
|
||||
Number Description
|
||||
4000000000000010 address_line1_check and address_zip_check will both fail.
|
||||
4000000000000028 address_line1_check will fail.
|
||||
4000000000000036 address_zip_check will fail.
|
||||
4000000000000101 cvc_check will fail.
|
||||
4000000000000341 Attaching this card to a Customer object will succeed, but attempts to charge the customer will fail.
|
||||
4000000000000002 Charges with this card will always be declined with a card_declined code.
|
||||
4000000000000069 Will be declined with an expired_card code.
|
||||
4000000000000119 Will be declined with a processing_error code.
|
||||
Additional test mode validation: By default, passing address or CVC data with the card number will cause the address and CVC checks to succeed. If not specified, the value of the checks will be null. Any expiration date in the future will be considered valid.
|
||||
|
||||
How do I test specific error codes?
|
||||
|
||||
Some suggestions:
|
||||
|
||||
card_declined: Use this special card number - 4000000000000002.
|
||||
incorrect_number: Use a number that fails the Luhn check, e.g. 4242424242424241.
|
||||
invalid_expiry_month: Use an invalid month e.g. 13.
|
||||
invalid_expiry_year: Use a year in the past e.g. 1970.
|
||||
invalid_cvc: Use a two digit number e.g. 99.
|
||||
|
||||
--->
|
||||
|
||||
<cffunction name="testGatewayURL" output="false" access="public" returntype="any" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset assertTrue(arguments.gw.getGatewayURL() EQ 'https://api.stripe.com/v1', "The gateway URL was unexpected, was: #arguments.gw.getGatewayURL()#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testValidateSuccess" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_token_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.validate(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCard()) />
|
||||
<cfset assertTrue(local.response.getSuccess() AND structKeyExists(local.response.getParsedResult(), "created"), "The validation did not succeed") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT local.response.hasError(), "Validation should not have errors but did") />
|
||||
<cfset assertTrue(local.response.getTransactionId() EQ local.response.getTokenID(), "The token ID should be put into the token field when created, was: #local.response.getTokenID()#") />
|
||||
<cfset assertTrue(local.response.getAVSCode() EQ "", "AVS isn't checked on validate, was: #local.response.getAVSCode()#") />
|
||||
<cfset assertTrue(local.response.getCVVCode() EQ "", "CVV isn't checked on validate, was: #local.response.getCVVCode()#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testValidateDeclineWillSucceed" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_token_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.validate(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createCardThatWillBeDeclined()) />
|
||||
<cfset assertTrue(local.response.getSuccess(), "Validation did succeed but should have failed without errors") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT local.response.hasError(), "Validation will not actually test card until it's converted to a customer so will not be declined") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testValidateInvalidCVV" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_invalid_cvc", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.validate(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createInvalidCVCError()) />
|
||||
<cfset assertTrue(NOT local.response.getSuccess(), "Validation did succeed but should have failed") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 402, "Status code should be 402, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(local.response.hasError(), "Validation should have errors but did not") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testValidateInvalidExpirationDate" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_invalid_expiry", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.validate(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createInvalidYearCardError()) />
|
||||
<cfset assertTrue(NOT local.response.getSuccess(), "Validation did succeed but should have failed") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 402, "Status code should be 402, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(local.response.hasError(), "Validation should have errors but did not") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseWithStripeJSToken" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset local.token = variables.svc.createToken() />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_token_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.validate(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCard()) />
|
||||
<cfset local.token.setID(local.response.getTransactionId()) />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_purchase_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), account = token) />
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #arguments.gw.currency# purchase failed but should have succeeded") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT local.response.hasError(), "Purchase should not have errors but did") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseWithCustomerAccount" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_token_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.validate(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCard()) />
|
||||
<cfset local.token = variables.svc.createToken().setID(local.response.getTransactionId()) />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_store_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.store(account = token) />
|
||||
<cfset assertTrue(local.response.getAVSCode() EQ "M", "AVS wasn't matched, was: #local.response.getAVSCode()#") />
|
||||
<cfset assertTrue(local.response.getCVVCode() EQ "M", "CVV wasn't matched, was: #local.response.getCVVCode()#") />
|
||||
<cfset assertTrue(local.response.getTransactionId() EQ local.response.getTokenID(), "The customer ID should be put into the token field when stored, was: #local.response.getTokenID()#") />
|
||||
<cfset local.customer = variables.svc.createToken().setId(local.response.getTransactionId()) />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_purchase_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), options = {customer: local.customer}) />
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #arguments.gw.currency# purchase failed but should have succeeded") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT local.response.hasError(), "Purchase should not have errors but did") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseWithCardSuccess" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_purchase_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCard()) />
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #arguments.gw.currency# purchase failed but should have succeeded") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT local.response.hasError(), "Purchase should not have errors but did") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseAuthorizeWithoutCapture" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_purchase_no_capture", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCard(), options = {"capture": false}) />
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #arguments.gw.currency# purchase failed but should have succeeded") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT local.response.hasError(), "Purchase should not have errors but did") />
|
||||
<cfset assertTrue(NOT local.response.getParsedResult().captured, "Charge should be auth only, not captured") />
|
||||
<cfset assertTrue(local.response.getAVSCode() EQ "M", "Full match should be M, was: #local.response.getAVSCode()#") />
|
||||
<cfset assertTrue(local.response.getCVVCode() EQ "M", "CVV match should be M, was: #local.response.getCVVCode()#") />
|
||||
<cfset assertTrue(len(local.response.getAuthorization()), "For capture only, authorization should have a value") />
|
||||
<cfset assertTrue(local.response.getAuthorization() EQ local.response.getTransactionID(), "For capture only, authorization should = transaction id") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseWithStatementDescriptor" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_purchase_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCard(), options = {"statement_descriptor": "Test <Descriptor>"}) />
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #arguments.gw.currency# purchase failed but should have succeeded") />
|
||||
<cfset assertTrue(structKeyExists(local.response.getParsedResult(), 'statement_descriptor'), 'statement_descriptor key doesnt exist') />
|
||||
<cfset assertTrue(local.response.getParsedResult().statement_descriptor EQ "Test Descriptor", "The statement descriptior should have returned 'Test Descriptor' (with invalid chars stripped), was: #local.response.getParsedResult().statement_descriptor#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseDecline" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_incorrect_number", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createInvalidCard()) />
|
||||
<cfset assertTrue(NOT local.response.getSuccess(), "The #arguments.gw.currency# purchase succeeded but should have failed") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 402, "Status code should be 402, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(local.response.getParsedResult().error.code EQ "incorrect_number", "Should have been an invalid card, was: #local.response.getParsedResult().error.code#") />
|
||||
<cfset assertTrue(NOT len(local.response.getAVSCode()), "AVS should be blank, was: #local.response.getAVSCode()#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseInvalidCVV" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_invalid_cvc", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createInvalidCVCError()) />
|
||||
<cfset assertTrue(NOT local.response.getSuccess(), "The #arguments.gw.currency# purchase succeeded but should have failed") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 402, "Status code should be 402, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(local.response.getParsedResult().error.code EQ "invalid_cvc", "Should have been an invalid cvc, was: #local.response.getParsedResult().error.code#") />
|
||||
<cfset assertTrue(NOT len(local.response.getCVVCode()), "CVV should be blank, was: #local.response.getCVVCode()#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseNoMatchStreetAddress" access="public" returntype="void" output="false">
|
||||
<cfset local.gw = variables.cad />
|
||||
<cfset offlineInjector(local.gw, this, "mock_invalid_address1", "doHttpCall") />
|
||||
<cfset local.response = local.gw.purchase(money = variables.svc.createMoney(5000, local.gw.currency), account = createValidCardWithoutStreetMatch()) />
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #local.gw.currency# purchase succeeded but should have failed") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(local.response.getParsedResult().source.address_line1_check EQ "fail", "Should have been an invalid address1, was: #local.response.getParsedResult().source.address_line1_check#") />
|
||||
<cfset assertTrue(local.response.getAVSCode() EQ "P", "Address1 match should be P, was: #local.response.getAVSCode()#") />
|
||||
<cfset assertTrue(local.response.getCVVCode() EQ "M", "CVV match should be M, was: #local.response.getCVVCode()#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseProcessingError" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_processing_error", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createCardThatWillBeProcessingError()) />
|
||||
<cfset assertTrue(NOT local.response.getSuccess(), "Purchase did succeed but should have failed") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 402, "Status code should be 402, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(local.response.getParsedResult().error.code EQ "processing_error", "Should have been an processing_error, was: #local.response.getParsedResult().error.code#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseWithoutCVV" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_invalid_cvc", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCardWithoutCVV()) />
|
||||
|
||||
<cfset assertTrue(local.response.getCVVCode() EQ "", "No CVV was passed so no answer should be provided but was: '#local.response.getCVVCode()#'") />
|
||||
<cfset assertTrue(NOT local.response.getSuccess(), "The #arguments.gw.currency# purchase succeeded but should have failed") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 402, "Status code for #arguments.gw.currency# should be 402, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(local.response.getParsedResult().error.code EQ "invalid_cvc", "Should have been an invalid cvc, was: #local.response.getParsedResult().error.code#") />
|
||||
|
||||
<cfset assertTrue(local.response.isValidCVV(), "Blank CVV should be valid") />
|
||||
<cfset assertTrue(NOT local.response.isValidCVV(AllowBlankCode = false), "CVV should not be valid") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testListChargesWithoutCount" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_list_charges_count_10", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.listCharges() />
|
||||
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #arguments.gw.currency# list did not succeed but should have") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code for #arguments.gw.currency# should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(arrayLen(local.response.getParsedResult().data) GT 2, "#arguments.gw.currency# list without count should have returned more than 2 results, was: #arrayLen(local.response.getParsedResult().data)#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testListChargesWithCountOf2" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_list_charges_count_2", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.listCharges(count = 2) />
|
||||
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #arguments.gw.currency# list did not succeed but should have") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code for #arguments.gw.currency# should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(arrayLen(local.response.getParsedResult().data) EQ 2, "#arguments.gw.currency# list without count should have returned 2 results, was: #arrayLen(local.response.getParsedResult().data)#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testStoreTokenSuccess" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset local.token = variables.svc.createToken() />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_token_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.validate(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCard()) />
|
||||
<cfset local.token.setID(local.response.getTransactionId()) />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_store_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.store(account = local.token) />
|
||||
|
||||
<cfset assertTrue(local.response.getSuccess() AND structKeyExists(local.response.getParsedResult(), "created"), "The store did not succeed") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT local.response.hasError(), "Store should not have errors but did") />
|
||||
<cfset assertTrue(structKeyExists(local.response.getParsedResult(), "object") AND local.response.getParsedResult().object EQ "customer", "Should be a customer response") />
|
||||
<cfset assertTrue(structKeyExists(local.response.getParsedResult(), "default_source"), "Should have default_source value") />
|
||||
<cfset assertTrue(structKeyExists(local.response.getParsedResult(), "sources"), "Should have sources key") />
|
||||
<cfset assertTrue(structKeyExists(local.response.getParsedResult().sources, "data"), "Should have data key") />
|
||||
<cfset assertTrue(arrayLen(local.response.getParsedResult().sources.data), "Data key should be an array with a length") />
|
||||
<cfset assertTrue(local.response.getParsedResult().sources.data[1].last4 EQ "4242", "Last4 should have been 4242") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testTokenizeCardAndFetchResult" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset var response = "" />
|
||||
<cfset var token = variables.svc.createToken() />
|
||||
|
||||
<cfset offlineInjector(gw, this, "mock_token_ok", "doHttpCall") />
|
||||
<cfset response = gw.validate(money = variables.svc.createMoney(5000, gw.currency), account = createValidCard()) />
|
||||
<cfset response = gw.getAccountToken(id = response.getTransactionID()) />
|
||||
|
||||
<cfset assertTrue(response.getSuccess() AND structKeyExists(response.getParsedResult(), "created"), "The validate did not succeed") />
|
||||
<cfset assertTrue(left(response.getTransactionID(), 3) EQ "tok", "We did not get back a token ID begining with tok_") />
|
||||
<cfset assertTrue(response.getParsedResult().used EQ false, "The token should be new and unused") />
|
||||
<cfset assertTrue(response.getStatusCode() EQ 200, "Status code should be 200, was: #response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT response.hasError(), "Store should not have errors but did") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testTokenizeWithUndefinedAddressCheckIssue19" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_token_ok_unchecked_avs", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.validate(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCardWithoutAddress()) />
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #arguments.gw.currency# tokenization failed but should have succeeded even if address is unchecked") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT local.response.hasError(), "Validate should not have errors but did") />
|
||||
<cfset assertTrue(local.response.getAVSCode() EQ "", "AVS should have been blank because AVS isn't checked for tokens, was: #local.response.getAVSCode()#") />
|
||||
<cfset assertTrue(local.response.getCVVCode() EQ "", "CVV should have been blank because CVV isn't checked for tokens, was: #local.response.getCVVCode()#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testTokenizeWithNullChecks" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_token_ok_null_checks", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.validate(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCardWithoutAddress()) />
|
||||
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #arguments.gw.currency# tokenization failed but should have succeeded even if address is unchecked") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT local.response.hasError(), "Validate should not have errors but did") />
|
||||
<cfset assertTrue(local.response.getAVSCode() EQ "", "AVS should have been blank because AVS isn't checked for tokens, was: #local.response.getAVSCode()#") />
|
||||
<cfset assertTrue(local.response.getCVVCode() EQ "", "CVV should have been blank because CVV isn't checked for tokens, was: #local.response.getCVVCode()#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseWithNullChecks" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_purchase_ok_null_checks", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCardWithoutAVSMatch()) />
|
||||
|
||||
<cfset assertTrue(local.response.getSuccess(), "The #arguments.gw.currency# tokenization failed but should have succeeded even if address is unchecked") />
|
||||
<cfset assertTrue(local.response.getStatusCode() EQ 200, "Status code should be 200, was: #local.response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT local.response.hasError(), "Validate should not have errors but did") />
|
||||
<cfset assertTrue(local.response.getAVSCode() EQ "", "AVS should have been blank because AVS isn't checked for tokens, was: #local.response.getAVSCode()#") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testTokenizeBankAccountAndFetchResult" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
<cfset var response = "" />
|
||||
<cfset var token = variables.svc.createToken() />
|
||||
|
||||
<cfset offlineInjector(gw, this, "mock_banktoken_ok", "doHttpCall") />
|
||||
<cfset response = gw.validate(money = variables.svc.createMoney(5000, gw.currency), account = createValidBankAccount()) />
|
||||
<cfset response = gw.getAccountToken(id = response.getTransactionID()) />
|
||||
|
||||
<cfset assertTrue(response.getSuccess() AND structKeyExists(response.getParsedResult(), "created"), "The validate did not succeed") />
|
||||
<cfset assertTrue(left(response.getTransactionID(), 4) EQ "btok", "We did not get back a token ID begining with btok_") />
|
||||
<cfset assertTrue(response.getParsedResult().used EQ false, "The token should be new and unused") />
|
||||
<cfset assertTrue(response.getStatusCode() EQ 200, "Status code should be 200, was: #response.getStatusCode()#") />
|
||||
<cfset assertTrue(NOT response.hasError(), "Store should not have errors but did") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testMissingArgumentsThrowsException" access="public" returntype="void" output="false" mxunit:expectedException="any">
|
||||
<cfset local.money = variables.svc.createMoney(5000) /><!--- in cents, $50.00 --->
|
||||
<cfset local.options = structNew() />
|
||||
|
||||
<cfset local.response = variables.gw.purchase(options = local.options) />
|
||||
<cfset assertTrue(false, "No error was thrown") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseThenRefundFull" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_purchase_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.purchase(money = variables.svc.createMoney(5000, arguments.gw.currency), account = createValidCard()) />
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_refund_full_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.refund(transactionid = local.response.getTransactionID()) />
|
||||
|
||||
<cfset assertTrue(local.response.getParsedResult().object EQ "refund", "It was not a refund object") />
|
||||
<cfset assertTrue(local.response.getSuccess(), "You can refund a purchase in full") />
|
||||
<cfset assertTrue(local.response.getParsedResult().amount EQ 5000, "The full refund should be for $50.00") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testPurchaseThenRefundPartialMultiple" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_purchase_ok", "doHttpCall") />
|
||||
<cfset local.charge = arguments.gw.purchase(money = variables.svc.createMoney(6000, arguments.gw.currency), account = createValidCard()) />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_refund_partial_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.refund(transactionid = local.charge.getTransactionID(), money = variables.svc.createMoney(2500, arguments.gw.currency)) />
|
||||
<cfset assertTrue(local.response.getSuccess(), "You can refund a purchase partially") />
|
||||
<cfset assertTrue(local.response.getParsedResult().object EQ "refund", "It was not a refund object") />
|
||||
<cfset assertTrue(local.response.getParsedResult().amount EQ 2500, "The partial refund should be for $25.00") />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_refund_partial_ok", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.refund(transactionid = local.charge.getTransactionID(), money = variables.svc.createMoney(2500, arguments.gw.currency)) />
|
||||
<cfset assertTrue(local.response.getSuccess(), "You can refund a purchase partially more than once if it adds up less than the total") />
|
||||
<cfset assertTrue(local.response.getParsedResult().object EQ "refund", "It was not a refund object") />
|
||||
<cfset assertTrue(local.response.getParsedResult().amount EQ 2500, "The partial refund should be for $25.00") />
|
||||
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_refund_partial_exceed_total", "doHttpCall") />
|
||||
<cfset local.response = arguments.gw.refund(transactionid = local.charge.getTransactionID(), money = variables.svc.createMoney(2500, arguments.gw.currency)) />
|
||||
<cfset assertTrue(NOT local.response.getSuccess(), "You can't refund more than the original amount") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testConvertDateToStripe" output="false" access="public" returntype="void">
|
||||
<cfset local.dte = createDateTime(2009, 12, 7, 16, 0, 0) />
|
||||
<cfset local.dteNow = now() />
|
||||
|
||||
<cfset assertTrue(variables.gw.utcToDate(variables.gw.dateToUTC(local.dte)) EQ local.dte, "A round trip should return the original value") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testConvertStripeToDate" output="false" access="public" returntype="void">
|
||||
<!--- create a timestamp in GMT as though it came from Stripe in epoch offset "created" --->
|
||||
<cfset local.dteKnownStripeEquivalent = "2013-02-16 05:20:46" />
|
||||
<cfset local.stripeUTC = 1360992046 />
|
||||
|
||||
<!--- first convert the stripe epoch value into a local time value --->
|
||||
<cfset local.dteLocalTime = variables.gw.utcToDate(local.stripeUTC) />
|
||||
|
||||
<!--- if the coldfusion server is running in UTC, the utcTotalOffset = 0, otherwise we need to add the UTC offset for comparison so this test can run on any CF install anywhere --->
|
||||
<cfset local.dteGMT = castToUTC(local.dteLocalTime) />
|
||||
|
||||
<!--- now they should be identical --->
|
||||
<cfset assertTrue(local.dteKnownStripeEquivalent EQ local.dteGMT, "Stripe date should convert to local time: (#local.dteKnownStripeEquivalent# != #local.dteGMT# / #local.stripeUTC#)") />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testBalance" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset offlineInjector(arguments.gw, this, "mock_balance_ok", "doHttpCall") />
|
||||
<cfset local.balance = arguments.gw.getBalance() />
|
||||
<cfset assertTrue(balance.getParsedResult().object EQ "balance", "A balance object wasn't returned") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="testNormalizeAVSCVV" access="public" returntype="void" output="false" mxunit:dataprovider="gateways">
|
||||
<cfargument name="gw" type="any" required="true" />
|
||||
|
||||
<cfset makePublic(arguments.gw, "normalizeAVS") />
|
||||
<cfset makePublic(arguments.gw, "normalizeCVV") />
|
||||
|
||||
<cfset local.response = {"object": "card", "country": arguments.gw.country, "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass" } />
|
||||
<cfset assertTrue(gw.normalizeAVS(response) EQ "M", "AVS should have passed, was #gw.normalizeAVS(response)#") />
|
||||
<cfset assertTrue(gw.normalizeCVV(response) EQ "M", "CVV should have passed, was #gw.normalizeCVV(response)#") />
|
||||
|
||||
<cfset local.response = {"object": "card", "country": arguments.gw.country, "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "fail" } />
|
||||
<cfset assertTrue(gw.normalizeAVS(response) EQ "B", "AVS should have passed, was #gw.normalizeAVS(response)#") />
|
||||
|
||||
<cfset local.response = {"object": "card", "country": arguments.gw.country, "cvc_check": "pass", "address_line1_check": "fail", "address_zip_check": "pass" } />
|
||||
<cfset assertTrue(gw.normalizeAVS(response) EQ "P", "AVS should have passed, was #gw.normalizeAVS(response)#") />
|
||||
|
||||
<cfset local.response = {"object": "card", "country": arguments.gw.country, "cvc_check": "unchecked", "address_line1_check": "unchecked", "address_zip_check": "unchecked" } />
|
||||
<cfif gw.country EQ "US">
|
||||
<cfset assertTrue(gw.normalizeAVS(response) EQ "S", "AVS should be marked as unsupported (US), was #gw.normalizeAVS(response)#") />
|
||||
<cfelse>
|
||||
<cfset assertTrue(gw.normalizeAVS(response) EQ "G", "AVS should be marked as unsupported (Foreign), was #gw.normalizeAVS(response)#") />
|
||||
</cfif>
|
||||
<cfset assertTrue(gw.normalizeCVV(response) EQ "U", "CVV should be marked as unsupported, was #gw.normalizeCVV(response)#") />
|
||||
|
||||
|
||||
<cfset local.response = {"object": "card", "country": arguments.gw.country, "cvc_check": "fail", "address_line1_check": "fail", "address_zip_check": "fail" } />
|
||||
<cfset assertTrue(gw.normalizeAVS(response) EQ "N", "AVS should have failed, was #gw.normalizeAVS(response)#") />
|
||||
<cfset assertTrue(gw.normalizeCVV(response) EQ "N", "CVV should have failed, was #gw.normalizeCVV(response)#") />
|
||||
|
||||
<cfset local.response = {"object": "card", "country": arguments.gw.country } />
|
||||
<cfset assertTrue(gw.normalizeAVS(response) EQ "", "AVS should have failed, was #gw.normalizeAVS(response)#") />
|
||||
<cfset assertTrue(gw.normalizeCVV(response) EQ "", "CVV should have failed, was #gw.normalizeCVV(response)#") />
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--- PRIVATE HELPERS, MOCKS, ETC --->
|
||||
<cffunction name="castToUTC" output="false" access="private" returntype="any">
|
||||
<cfargument name="dtm" required="yes" type="any" />
|
||||
|
||||
<cfset local.jTimeZone = createObject("java","java.util.TimeZone") />
|
||||
<cfset local.timezone = local.jTimeZone.getDefault() />
|
||||
|
||||
<cfscript>
|
||||
local.tYear = javacast("int", Year(arguments.dtm));
|
||||
local.tMonth = javacast("int", Month(arguments.dtm)-1); //java months are 0 based
|
||||
local.tDay = javacast("int", Day(arguments.dtm));
|
||||
local.tDOW = javacast("int", DayOfWeek(arguments.dtm)); //day of week
|
||||
local.thisOffset = (timezone.getOffset(1, local.tYear, local.tMonth, local.tDay, local.tDOW, 0) / 1000) * -1.00;
|
||||
return dateAdd("s", local.thisOffset, arguments.dtm);
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCard" access="private" returntype="any" output="false">
|
||||
<!--- these values simulate a valid card with matching avs/cvv --->
|
||||
<cfset local.account = variables.svc.createCreditCard() />
|
||||
<cfset local.account.setAccount(4242424242424242) />
|
||||
<cfset local.account.setMonth(10) />
|
||||
<cfset local.account.setYear(year(now())+1) />
|
||||
<cfset local.account.setVerificationValue(999) />
|
||||
<cfset local.account.setFirstName("John") />
|
||||
<cfset local.account.setLastName("Doe") />
|
||||
<cfset local.account.setAddress("888 Anywhere Lane") />
|
||||
<cfset local.account.setPostalCode("77777") />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createInvalidCard" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setAccount(4242424242424241) />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCardWithoutCVV" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setAccount(4111111111111111) />
|
||||
<cfset local.account.setVerificationValue() />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCardWithFailedCVV" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setAccount(4000000000000101) />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCardWithoutAddress" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setAddress("") />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCardWithoutStreetMatch" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setAccount(4000000000000028) />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCardWithoutZipMatch" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setAccount(4000000000000036) />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidCardWithoutAVSMatch" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setAccount(4000000000000010) />
|
||||
<cfset local.account.setAddress("") />
|
||||
<cfset local.account.setPostalCode("") />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createCardThatWillBeDeclined" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setAccount(4000000000000002) />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createCardThatWillBeExpired" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setAccount(4000000000000069) />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createCardThatWillBeProcessingError" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setAccount(4000000000000119) />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createInvalidMonthCardError" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setMonth(13) />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createInvalidYearCardError" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setYear(1970) />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createInvalidCVCError" access="private" returntype="any" output="false">
|
||||
<cfset local.account = createValidCard() />
|
||||
<cfset local.account.setVerificationValue(99) />
|
||||
<cfreturn local.account />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="createValidBankAccount" access="private" returntype="any" output="false">
|
||||
<cfset var account = variables.svc.createEFT() />
|
||||
<cfset account.setAccount("000123456789") />
|
||||
<cfset account.setRoutingNumber("110000000") />
|
||||
<cfset account.setAccountType("checking") />
|
||||
<cfset account.setSEC("CCD") />
|
||||
<cfset account.setFirstName("John") />
|
||||
<cfset account.setLastName("Doe") />
|
||||
<cfset account.setAddress("123 Business Lane") />
|
||||
<cfset account.setPostalCode("77777") />
|
||||
<cfset account.setCountry("US") />
|
||||
|
||||
<cfreturn account />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="mock_token_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "tok_6Lc9jlTa7yU2ky", "livemode": false, "created": 1433172850, "used": false, "object": "token", "type": "card", "card": { "id": "card_6Lc90vCQf7EDwh", "object": "card", "last4": "4242", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "sBxTyx7XVdjznwyt", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "unchecked", "address_line1_check": "unchecked", "address_zip_check": "unchecked", "dynamic_last4": null, "metadata": {} }, "client_ip": "127.0.0.1" }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_token_ok_unchecked_avs" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "tok_65NT77fCo4cCEO", "livemode": true, "created": 1429428006, "used": false, "object": "token", "type": "card", "card": { "id": "card_65NT1zXyit19Gk", "object": "card", "last4": "4001", "brand": "American Express", "funding": "unknown", "exp_month": 1, "exp_year": 2018, "fingerprint": "m4KxtLGciUBrRaMk", "country": null, "name": "Joe Blow", "address_line1": "123 Some Way", "address_line2": null, "address_city": "Calgary", "address_state": "AB ", "address_zip": "T3H2W6", "address_country": "CA", "cvc_check": "unchecked", "address_line1_check": "unchecked", "address_zip_check": "unchecked", "dynamic_last4": null }, "client_ip": "224.14.138.168" }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_token_ok_null_checks" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "tok_65NT77fCo4cCEO", "livemode": true, "created": 1429428006, "used": false, "object": "token", "type": "card", "card": { "id": "card_65NT1zXyit19Gk", "object": "card", "last4": "4001", "brand": "American Express", "funding": "unknown", "exp_month": 1, "exp_year": 2018, "fingerprint": "m4KxtLGciUBrRaMk", "country": null, "name": "Joe Blow", "address_line1": "123 Some Way", "address_line2": null, "address_city": "Calgary", "address_state": "AB ", "address_zip": "T3H2W6", "address_country": "CA", "cvc_check": null, "address_line1_check": null, "address_zip_check": null, "dynamic_last4": null }, "client_ip": "224.14.138.168" }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_purchase_ok_null_checks" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "ch_6LecnZjGNp3pHH", "object": "charge", "created": 1433182020, "livemode": false, "paid": true, "status": "succeeded", "amount": 5000, "currency": "cad", "refunded": false, "source": { "id": "card_6LecB3TU5xmZEt", "object": "card", "last4": "4242", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "sBxTyx7XVdjznwyt", "country": "US", "name": "John Doe", "address_line1": "888 Anywhere Lane", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": null, "address_line1_check": null, "address_zip_check": null, "dynamic_last4": null, "metadata": {}, "customer": "cus_6LecAtEEFyvRtx" }, "captured": true, "balance_transaction": "txn_6Lecqn02qYxb83", "failure_message": null, "failure_code": null, "amount_refunded": 0, "customer": "cus_6LecAtEEFyvRtx", "invoice": null, "description": null, "dispute": null, "metadata": {}, "statement_descriptor": "TEST DESCRIPTOR", "fraud_details": {}, "receipt_email": null, "receipt_number": null, "shipping": null, "destination": null, "application_fee": null, "refunds": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/charges/ch_6LecnZjGNp3pHH/refunds", "data": [] } }' } />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="mock_banktoken_ok" access="private">
|
||||
<cfset var http = { StatusCode = '200 OK', FileContent = '{ "id": "btok_6LcgqhP4t39mYj", "livemode": false, "created": 1433174792, "used": false, "object": "token", "type": "bank_account", "bank_account": { "object": "bank_account", "id": "ba_6LcgvRGvZtugSp", "last4": "6789", "country": "US", "currency": "usd", "status": "new", "fingerprint": "MYme1jP2GEKoZ0xi", "routing_number": "110000000", "bank_name": "STRIPE TEST BANK" }, "client_ip": null } ' } />
|
||||
<cfreturn http />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_store_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "object": "customer", "created": 1433173085, "id": "cus_6LcD0oto8ndYMz", "livemode": false, "description": null, "email": null, "delinquent": false, "metadata": {}, "subscriptions": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/customers/cus_6LcD0oto8ndYMz/subscriptions", "data": [] }, "discount": null, "account_balance": 0, "currency": null, "sources": { "object": "list", "total_count": 1, "has_more": false, "url": "/v1/customers/cus_6LcD0oto8ndYMz/sources", "data": [ { "id": "card_6LcDpYvajJeulk", "object": "card", "last4": "4242", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "sBxTyx7XVdjznwyt", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass", "dynamic_last4": null, "metadata": {}, "customer": "cus_6LcD0oto8ndYMz" } ] }, "default_source": "card_6LcDpYvajJeulk" }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_purchase_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "ch_6LecnZjGNp3pHH", "object": "charge", "created": 1433182020, "livemode": false, "paid": true, "status": "succeeded", "amount": 5000, "currency": "cad", "refunded": false, "source": { "id": "card_6LecB3TU5xmZEt", "object": "card", "last4": "4242", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "sBxTyx7XVdjznwyt", "country": "US", "name": "John Doe", "address_line1": "888 Anywhere Lane", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass", "dynamic_last4": null, "metadata": {}, "customer": "cus_6LecAtEEFyvRtx" }, "captured": true, "balance_transaction": "txn_6Lecqn02qYxb83", "failure_message": null, "failure_code": null, "amount_refunded": 0, "customer": "cus_6LecAtEEFyvRtx", "invoice": null, "description": null, "dispute": null, "metadata": {}, "statement_descriptor": "TEST DESCRIPTOR", "fraud_details": {}, "receipt_email": null, "receipt_number": null, "shipping": null, "destination": null, "application_fee": null, "refunds": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/charges/ch_6LecnZjGNp3pHH/refunds", "data": [] } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_purchase_no_capture" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "ch_6LeebvuUK9psRD", "object": "charge", "created": 1433182109, "livemode": false, "paid": true, "status": "succeeded", "amount": 5000, "currency": "cad", "refunded": false, "source": { "id": "card_6LeeNzLM92Plhm", "object": "card", "last4": "4242", "brand": "Visa", "funding": "credit", "exp_month": 10, "exp_year": 2016, "fingerprint": "sBxTyx7XVdjznwyt", "country": "US", "name": "John Doe", "address_line1": "888 Anywhere Lane", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass", "dynamic_last4": null, "metadata": {}, "customer": null }, "captured": false, "balance_transaction": null, "failure_message": null, "failure_code": null, "amount_refunded": 0, "customer": null, "invoice": null, "description": null, "dispute": null, "metadata": {}, "statement_descriptor": null, "fraud_details": {}, "receipt_email": null, "receipt_number": null, "shipping": null, "destination": null, "application_fee": null, "refunds": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/charges/ch_6LeebvuUK9psRD/refunds", "data": [] } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_refund_full_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "re_6KvatBzwQDGk5H", "amount": 5000, "currency": "usd", "created": 1433014494, "object": "refund", "balance_transaction": "txn_6KvaD6WPm0mCFs", "metadata": {}, "charge": "ch_6KvaiViAHtNFQI", "receipt_number": null, "reason": null }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_refund_partial_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "re_6KvcMiHdQozrMG", "amount": 2500, "currency": "usd", "created": 1433014617, "object": "refund", "balance_transaction": "txn_6Kvcbog0NEvfHR", "metadata": {}, "charge": "ch_6KvcKBRM9QcQJk", "receipt_number": null, "reason": null }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_refund_partial_exceed_total" access="private">
|
||||
<cfreturn { StatusCode = '400', FileContent = '{ "error": { "type": "invalid_request_error", "message": "Refund amount ($25.00) is greater than unrefunded amount on charge ($10.00)", "param": "amount" } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_invalid_cvc" access="private">
|
||||
<cfreturn { StatusCode = '402', FileContent = '{ "error": { "message": "Your card''s security code is invalid", "type": "card_error", "param": "cvc", "code": "invalid_cvc" } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_invalid_expiry" access="private">
|
||||
<cfreturn { StatusCode = '402', FileContent = '{ "error": { "message": "Your card''s expiration year is invalid", "type": "card_error", "param": "exp_year", "code": "invalid_expiry_year" } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_incorrect_number" access="private">
|
||||
<cfreturn { StatusCode = '402', FileContent = '{ "error": { "message": "Your card number is incorrect", "type": "card_error", "param": "number", "code": "incorrect_number" } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_processing_error" access="private">
|
||||
<cfreturn { StatusCode = '402', FileContent = '{ "error": { "message": "An error occurred while processing your card", "type": "card_error", "code": "processing_error", "charge": "ch_1Ie7BA4vAb8ZaF" } }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_invalid_address1" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "id": "ch_1IeAMjrHpnj7dV", "object": "charge", "created": 1360990030, "livemode": false, "paid": true, "amount": 5000, "currency": "usd", "refunded": false, "fee": 175, "fee_details": [ { "amount": 175, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 0 } ], "source": { "object": "card", "last4": "0028", "type": "Visa", "exp_month": 10, "exp_year": 2014, "fingerprint": "1YqKn8Y7DbGMP8a1", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "fail", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 0, "customer": null, "invoice": null, "description": null, "dispute": null }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_list_charges_count_10" access="private">
|
||||
<cfsavecontent variable="local.response">
|
||||
{ "object": "list", "count": 31800, "url": "/v1/charges", "data": [ { "id": "ch_1IxL1nrwUu7kmF", "object": "charge", "created": 1361061326, "livemode": false, "paid": true, "amount": 5000, "currency": "usd", "refunded": false, "fee": 175, "fee_details": [ { "amount": 175, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 0 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 10, "exp_year": 2014, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 0, "customer": null, "invoice": null, "description": null, "dispute": null }, { "id": "ch_1IxLLW6cPV1kIK", "object": "charge", "created": 1361061323, "livemode": false, "paid": true, "amount": 5000, "currency": "usd", "refunded": false, "fee": 102, "fee_details": [ { "amount": 175, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 73 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 10, "exp_year": 2014, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 2500, "customer": null, "invoice": null, "description": null, "dispute": null }, { "id": "ch_1IxL31sObDzpCv", "object": "charge", "created": 1361061320, "livemode": false, "paid": true, "amount": 5000, "currency": "usd", "refunded": true, "fee": 0
|
||||
, "fee_details": [ { "amount": 175, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 175 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 10, "exp_year": 2014, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 5000, "customer": null, "invoice": null, "description": null, "dispute": null }, { "id": "ch_1IxK3Xh6I2xrNE", "object": "charge", "created": 1361061317, "livemode": false, "paid": false, "amount": 5000, "currency": "usd", "refunded": false, "fee": 0, "fee_details": [], "card": { "object": "card", "last4": "0119", "type": "Visa", "exp_month": 10, "exp_year": 2014, "fingerprint": "YggjdcH7yERT93CL", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": "An error occurred while processing your card", "amount_refunded": 0, "customer": null, "invoice": null, "description": null, "dispute": null }, { "id": "ch_1Iuelcm8fpWb5v", "object": "charge", "created": 1361051359, "livemode": false, "paid": true, "amount": 100, "currency": "usd", "refunded": false, "fee": 33, "fee_details": [ { "amount": 33, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 0 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 12, "exp_year": 2015, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "Java Bindings Cardholder"
|
||||
, "address_line1": "522 Ramona St", "address_line2": "Palo Alto", "address_city": null, "address_state": "CA", "address_zip": "94301", "address_country": "USA", "cvc_check": null, "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 0, "customer": "cus_0By77C9AgMAIw2", "invoice": "in_1ItfkkOrk99sat", "description": null, "dispute": null }, { "id": "ch_1IueK7L83dUFhK", "object": "charge", "created": 1361051358, "livemode": false, "paid": true, "amount": 100, "currency": "usd", "refunded": false, "fee": 33, "fee_details": [ { "amount": 33, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 0 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 12, "exp_year": 2015, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "Java Bindings Cardholder", "address_line1": "522 Ramona St", "address_line2": "Palo Alto", "address_city": null, "address_state": "CA", "address_zip": "94301", "address_country": "USA", "cvc_check": null, "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 0, "customer": "cus_0By7tRmEv8zcqW", "invoice": "in_1Itf8IT0wEG9R8", "description": null, "dispute": null }, { "id": "ch_1IueGPyiGOsISV", "object": "charge", "created": 1361051356, "livemode": false, "paid": true, "amount": 100, "currency": "usd", "refunded": false, "fee": 33, "fee_details": [ { "amount": 33, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 0 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 12, "exp_year": 2015, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "Java Bindings Cardholder", "address_line1": "522 Ramona St", "address_line2": "Palo Alto", "address_city": null, "address_state": "CA", "address_zip": "94301", "address_country": "USA"
|
||||
, "cvc_check": null, "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 0, "customer": "cus_0By6oVFxh4j0OR", "invoice": "in_1ItfCmqahj5CLg", "description": null, "dispute": null }, { "id": "ch_1Iuee3zxbf6Eez", "object": "charge", "created": 1361051355, "livemode": false, "paid": true, "amount": 100, "currency": "usd", "refunded": false, "fee": 33, "fee_details": [ { "amount": 33, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 0 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 12, "exp_year": 2015, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "Java Bindings Cardholder", "address_line1": "522 Ramona St", "address_line2": "Palo Alto", "address_city": null, "address_state": "CA", "address_zip": "94301", "address_country": "USA", "cvc_check": null, "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 0, "customer": "cus_0By6rD5aPmULnT", "invoice": "in_1ItfDCc2kbn7XF", "description": null, "dispute": null }, { "id": "ch_1IucE7qqbtaXng", "object": "charge", "created": 1361051232, "livemode": false, "paid": true, "amount": 100, "currency": "usd", "refunded": false, "fee": 33, "fee_details": [ { "amount": 33, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 0 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 12, "exp_year": 2015, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "Java Bindings Cardholder", "address_line1": "522 Ramona St", "address_line2": "Palo Alto", "address_city": null, "address_state": "CA", "address_zip": "94301", "address_country": "USA", "cvc_check": null, "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 0
|
||||
, "customer": "cus_0By5i2kAbTsaX3", "invoice": "in_1Iteod2vndXuD7", "description": null, "dispute": null }, { "id": "ch_1Iuc0z4PmscDT4", "object": "charge", "created": 1361051232, "livemode": false, "paid": true, "amount": 100, "currency": "usd", "refunded": false, "fee": 33, "fee_details": [ { "amount": 33, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 0 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 12, "exp_year": 2015, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "Java Bindings Cardholder", "address_line1": "522 Ramona St", "address_line2": "Palo Alto", "address_city": null, "address_state": "CA", "address_zip": "94301", "address_country": "USA", "cvc_check": null, "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 0, "customer": "cus_0By5b0y9bDVB7U", "invoice": "in_1IteiR0nvAU7ta", "description": null, "dispute": null } ] }
|
||||
</cfsavecontent>
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = response } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_list_charges_count_2" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "object": "list", "count": 31800, "url": "/v1/charges", "data": [ { "id": "ch_1IxL1nrwUu7kmF", "object": "charge", "created": 1361061326, "livemode": false, "paid": true, "amount": 5000, "currency": "usd", "refunded": false, "fee": 175, "fee_details": [ { "amount": 175, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 0 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 10, "exp_year": 2014, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 0, "customer": null, "invoice": null, "description": null, "dispute": null }, { "id": "ch_1IxLLW6cPV1kIK", "object": "charge", "created": 1361061323, "livemode": false, "paid": true, "amount": 5000, "currency": "usd", "refunded": false, "fee": 102, "fee_details": [ { "amount": 175, "currency": "usd", "type": "stripe_fee", "description": "Stripe processing fees", "application": null, "amount_refunded": 73 } ], "card": { "object": "card", "last4": "4242", "type": "Visa", "exp_month": 10, "exp_year": 2014, "fingerprint": "Z0VUjeIIj0HObMhK", "country": "US", "name": "John Doe", "address_line1": "888", "address_line2": "", "address_city": null, "address_state": "", "address_zip": "77777", "address_country": "", "cvc_check": "pass", "address_line1_check": "pass", "address_zip_check": "pass" }, "failure_message": null, "amount_refunded": 2500, "customer": null, "invoice": null, "description": null, "dispute": null } ] }' } />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="mock_balance_ok" access="private">
|
||||
<cfreturn { StatusCode = '200 OK', FileContent = '{ "pending": [ { "amount": -3090, "currency": "cad" } ], "available": [ { "amount": 13412, "currency": "cad" } ], "livemode": false, "object": "balance" }' } />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
455
cfpayment/api/model/creditcard.cfc
Normal file
455
cfpayment/api/model/creditcard.cfc
Normal file
|
|
@ -0,0 +1,455 @@
|
|||
<!---.UserFirstName.UserFirstName.UserFirstName
|
||||
$Id$
|
||||
|
||||
Copyright 2007 Brian Ghidinelli (http://www.ghidinelli.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 name="creditcard" output="false" hint="Object for holding credit card data">
|
||||
<cfproperty name="firstName" type="string" default="" />
|
||||
<cfproperty name="lastName" type="string" default="" />
|
||||
<cfproperty name="company" type="string" default="" />
|
||||
<cfproperty name="address" type="string" default="" />
|
||||
<cfproperty name="address2" type="string" default="" />
|
||||
<cfproperty name="city" type="string" default="" />
|
||||
<cfproperty name="region" type="string" default="" />
|
||||
<cfproperty name="postalCode" type="string" default="" />
|
||||
<cfproperty name="country" type="string" default="" />
|
||||
<cfproperty name="phoneNumber" type="string" default="" />
|
||||
<cfproperty name="expMonth" type="numeric" default="" />
|
||||
<cfproperty name="expYear" type="numeric" default="" />
|
||||
<cfproperty name="account" type="numeric" default="" />
|
||||
<cfproperty name="verificationValue" type="numeric" default="" />
|
||||
<!--- for Switch / Solo; not supported yet --->
|
||||
<cfproperty name="issueNumber" type="numeric" default="" />
|
||||
<cfproperty name="startMonth" type="numeric" default="" />
|
||||
<cfproperty name="startYear" type="numeric" default="" />
|
||||
|
||||
<!---
|
||||
PROPERTIES
|
||||
--->
|
||||
<cfset variables.instance = structNew() />
|
||||
<cfset variables.instance.firstName = "" />
|
||||
<cfset variables.instance.LaerFirstName = "" />
|
||||
<cfset variables.instance.company = "" />
|
||||
<cfset variables.instance.address = "" />
|
||||
<cfset variables.instance.address2 = "" />
|
||||
<cfset variables.instance.city = "" />
|
||||
<cfset variables.instance.region = "" />
|
||||
<cfset variables.instance.postalCode = "" />
|
||||
<cfset variables.instance.country = "" />
|
||||
<cfset variables.instance.phoneNumber = "" />
|
||||
<cfset variables.instance.expMonth = "" />
|
||||
<cfset variables.instance.expYear = "" />
|
||||
<cfset variables.instance.account = "" />
|
||||
<cfset variables.instance.verificationValue = "" />
|
||||
<!--- for Switch/Solo; not supported yet --->
|
||||
<cfset variables.instance.issueNumber = "" />
|
||||
<cfset variables.instance.startMonth = "" />
|
||||
<cfset variables.instance.startYear = "" />
|
||||
|
||||
<!--- expose global variables --->
|
||||
<cfset this.CREDITCARD_MIN_EXP_YEAR = Year(now()) />
|
||||
<cfset this.CREDITCARD_MAX_EXP_YEAR = Year(now())+10 />
|
||||
<cfset this.CREDITCARD_EXP_MONTH_DISPLAY_LIST = "01 - JAN,02 - FEB,03 - MAR,04 - APR,05 - MAY,06 - JUN,07 - JUL,08 - AUG,09 - SEP,10 - OCT,11 - NOV,12 - DEC" />
|
||||
<cfset this.CREDITCARD_EXP_MONTH_VALUES_LIST = "1,2,3,4,5,6,7,8,9,10,11,12" />
|
||||
<cfset this.CREDITCARD_EXP_YEAR_LIST = "" /><!--- set during init() --->
|
||||
|
||||
<!---
|
||||
INITIALIZATION / CONFIGURATION
|
||||
--->
|
||||
<cffunction name="init" access="public" returntype="creditcard" output="false">
|
||||
<cfset var ctr = 0 />
|
||||
<cfset this.CREDITCARD_EXP_YEAR_LIST = "" />
|
||||
<cfloop from="#this.CREDITCARD_MIN_EXP_YEAR#" to="#this.CREDITCARD_MAX_EXP_YEAR#" index="ctr">
|
||||
<cfset this.CREDITCARD_EXP_YEAR_LIST = ListAppend(this.CREDITCARD_EXP_YEAR_LIST, ctr) />
|
||||
</cfloop>
|
||||
<cfreturn this />
|
||||
</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
|
||||
--->
|
||||
|
||||
<!--- Various helper "is*" checks to assist merchants with selectively accepting card types
|
||||
Checks BIN numbers and acceptable lengths
|
||||
Does not prevent processing: validate() with Luhn algorithm (mod10) and other checks does that.
|
||||
--->
|
||||
<cffunction name="getIsAmex" access="public" returntype="any" output="false">
|
||||
<cfif (left(getAccount(), 2) EQ 34 OR left(getAccount(), 2) EQ 37) AND len(getAccount()) EQ 15>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getIsDiscover" access="public" returntype="any" output="false">
|
||||
<cfif (left(getAccount(), 4) EQ 6011 OR left(getAccount(), 2) EQ 65) AND len(getAccount()) EQ 16>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getIsMasterCard" access="public" returntype="any" output="false">
|
||||
<cfif (left(getAccount(), 2) GTE 51 AND left(getAccount(), 2) LTE 55) AND len(getAccount()) EQ 16>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getIsVisa" access="public" returntype="any" output="false">
|
||||
<cfif left(getAccount(), 1) EQ 4 AND (len(getAccount()) EQ 13 OR len(getAccount()) EQ 16)>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- Expiration date must not only be numeric but must be in the future (valid until the end of current month) --->
|
||||
<cffunction name="getIsExpirationValid" access="public" returntype="any" output="false">
|
||||
<cfif getExpirationDate() GTE now()>
|
||||
<cfreturn true />
|
||||
<cfelse>
|
||||
<cfreturn false />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- convenience boolean wrapper around validate() --->
|
||||
<cffunction name="getIsValid" access="public" returntype="boolean" output="false" hint="True/false the credit card is valid">
|
||||
<cfreturn arrayLen(validate()) EQ 0 />
|
||||
</cffunction>
|
||||
|
||||
<!--- if we pass this successfully, we should be able to send it to the gateway safely --->
|
||||
<cffunction name="validate" access="public" returntype="any" output="false" hint="Verify the account is valid">
|
||||
<cfargument name="requireAVS" type="boolean" default="true" />
|
||||
<cfargument name="requireVerificationValue" type="boolean" default="true" />
|
||||
|
||||
<cfset var errors = arrayNew(1) />
|
||||
<cfset var thisError = structNew() />
|
||||
|
||||
<!--- First Name --->
|
||||
<cfif (NOT len(trim(getFirstName())))>
|
||||
<cfset thisError.field = "firstName" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "First name is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- Last Name --->
|
||||
<cfif NOT len(trim(getLastName()))>
|
||||
<cfset thisError.field = "lastName" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Last name is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<cfif arguments.requireAVS>
|
||||
|
||||
<!--- Address --->
|
||||
<cfif NOT len(trim(getAddress()))>
|
||||
<cfset thisError.field = "address" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Street address is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- Postal Code --->
|
||||
<cfif NOT len(trim(getPostalCode()))>
|
||||
<cfset thisError.field = "postalCode" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Postal code is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<!--- AVS really only cares about the numbers at the beginning of the address line so verify there is one --->
|
||||
<!--- NOTE: This check doesn't work with PO Box lines, e.g. "P. O. Box 1234" would return as an error --->
|
||||
<!--- <cfif len(getAddress()) AND NOT isNumeric(left(trim(getAddress()), 1))>
|
||||
<cfset thisError.field = "address" />
|
||||
<cfset thisError.type = "invalidValue" />
|
||||
<cfset thisError.message = "Address must contain the street number" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif> --->
|
||||
<!--- TODO: validate postal code length/format? For common countries like US/Canada? --->
|
||||
|
||||
|
||||
<!--- Verification Code --->
|
||||
<cfif arguments.requireVerificationValue>
|
||||
|
||||
<cfif NOT len(getVerificationValue())>
|
||||
<cfset thisError.field = "verificationValue" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Security code is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
</cfif>
|
||||
|
||||
<cfif len(getVerificationValue()) AND NOT isNumeric(getVerificationValue())>
|
||||
<cfset thisError.field = "verificationValue" />
|
||||
<cfset thisError.type = "invalidType" />
|
||||
<cfset thisError.message = "Security code is not numeric" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
<cfif len(getVerificationValue()) AND (len(getVerificationValue()) LT 3 OR len(getVerificationValue()) GT 4)>
|
||||
<cfset thisError.field = "verificationValue" />
|
||||
<cfset thisError.type = "invalidValue" />
|
||||
<!--- reflect the position of the CVV value --->
|
||||
<cfif getIsAmex()>
|
||||
<cfset thisError.message = "Security code must be four digits and is found on the front of the credit card" />
|
||||
<cfelse>
|
||||
<cfset thisError.message = "Security code must be three digits and is found on the back of the credit card near the signature strip" />
|
||||
</cfif>
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
|
||||
<!--- Expiration Month --->
|
||||
<cfif NOT len(getMonth())>
|
||||
<cfset thisError.field = "month" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Expiration month is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
<cfif len(getMonth()) AND NOT isNumeric(getMonth())>
|
||||
<cfset thisError.field = "month" />
|
||||
<cfset thisError.type = "invalidType" />
|
||||
<cfset thisError.message = "Expiration month is not numeric" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
<cfif len(getMonth()) AND NOT (getMonth() GTE 1 AND getMonth() LTE 12)>
|
||||
<cfset thisError.field = "month" />
|
||||
<cfset thisError.type = "invalidValue" />
|
||||
<cfset thisError.message = "Expiration month must be between 1 and 12" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- Expiration Year --->
|
||||
<cfif NOT len(getYear())>
|
||||
<cfset thisError.field = "Year" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Expiration year is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
<cfif len(getYear()) AND NOT isNumeric(getYear())>
|
||||
<cfset thisError.field = "Year" />
|
||||
<cfset thisError.type = "invalidType" />
|
||||
<cfset thisError.message = "Expiration year is not numeric" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
<!--- expiration year must be later than today and less than 10 years in the future --->
|
||||
<cfif len(getYear()) AND NOT (getYear() GTE this.CREDITCARD_MIN_EXP_YEAR AND getYear() LTE this.CREDITCARD_MAX_EXP_YEAR)>
|
||||
<cfset thisError.field = "Year" />
|
||||
<cfset thisError.type = "invalidValue" />
|
||||
<cfset thisError.message = "Expiration year must be between #year(now())# and #year(now()) + 10#" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- Expiration date must be in the future--->
|
||||
<cfif NOT getIsExpirationValid()>
|
||||
<cfset thisError.field = "expiration" />
|
||||
<cfset thisError.type = "invalidValue" />
|
||||
<cfset thisError.message = "Expiration date must be in the future" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- Account Number (13-16 digits), only the digits are stored via setAccount() --->
|
||||
<cfif NOT len(getAccount())>
|
||||
<cfset thisError.field = "account" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Account number is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
<!--- allow special cases for testing: 1 and 2 --->
|
||||
<cfif not ListFind("1,2", getAccount())>
|
||||
<cfif len(getAccount()) AND (len(getAccount()) LT 13 OR len(getAccount()) GT 16)>
|
||||
<cfset thisError.field = "account" />
|
||||
<cfset thisError.type = "invalidValue" />
|
||||
<cfset thisError.message = "Account number must be between 13 and 16 digits" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
<cfif len(getAccount()) AND NOT getIsMod10(getAccount())>
|
||||
<cfset thisError.field = "account" />
|
||||
<cfset thisError.type = "invalidValue" />
|
||||
<cfset thisError.message = "Account number is invalid - please check the number carefully" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<cfreturn errors />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!---
|
||||
ACCESSORS
|
||||
--->
|
||||
<cffunction name="setFirstName" access="public" returntype="any" output="false"><cfset variables.instance.firstName = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getFirstName" access="public" returntype="any" output="false"><cfreturn variables.instance.firstName /></cffunction>
|
||||
|
||||
<cffunction name="setLastName" access="public" returntype="any" output="false"><cfset variables.instance.LaerFirstName = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getLastName" access="public" returntype="any" output="false"><cfreturn variables.instance.LaerFirstName /></cffunction>
|
||||
<cffunction name="getName" access="public" returntype="any" hint="I return the firstname and last name as one string." output="false">
|
||||
<cfset var ret = getFirstName() />
|
||||
<cfif len(ret) and len(getLastName())>
|
||||
<cfset ret = ret & " " />
|
||||
</cfif>
|
||||
<cfset ret = ret & getLastName() />
|
||||
<cfreturn ret />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="setcompany" access="public" returntype="any" output="false"><cfset variables.instance.company = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getcompany" access="public" returntype="any" output="false"><cfreturn variables.instance.company /></cffunction>
|
||||
|
||||
|
||||
|
||||
<cffunction name="setAddress" access="public" returntype="any" output="false"><cfset variables.instance.address = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getAddress" access="public" returntype="any" output="false"><cfreturn variables.instance.address /></cffunction>
|
||||
|
||||
<cffunction name="setAddress2" access="public" returntype="any" output="false"><cfset variables.instance.address2 = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getAddress2" access="public" returntype="any" output="false"><cfreturn variables.instance.address2 /></cffunction>
|
||||
|
||||
<cffunction name="setCity" access="public" returntype="any" output="false"><cfset variables.instance.city = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getCity" access="public" returntype="any" output="false"><cfreturn variables.instance.city /></cffunction>
|
||||
|
||||
<cffunction name="setRegion" access="public" returntype="any" hint="Region is synonym for State or Province" output="false"><cfset variables.instance.region = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getRegion" access="public" returntype="any" output="false"><cfreturn variables.instance.region /></cffunction>
|
||||
|
||||
<cffunction name="setPostalCode" access="public" returntype="any" output="false"><cfset variables.instance.postalCode = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getPostalCode" access="public" returntype="any" output="false"><cfreturn variables.instance.postalCode /></cffunction>
|
||||
|
||||
<cffunction name="setCountry" access="public" returntype="any" output="false"><cfset variables.instance.country = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getCountry" access="public" returntype="any" output="false"><cfreturn variables.instance.country /></cffunction>
|
||||
|
||||
<cffunction name="setPhoneNumber" access="public" returntype="any" output="false"><cfset variables.instance.PhoneNumber = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getPhoneNumber" access="public" returntype="any" output="false"><cfreturn variables.instance.PhoneNumber /></cffunction>
|
||||
|
||||
<cffunction name="setMonth" access="public" returntype="any" output="false"><cfset variables.instance.expMonth = numbersOnly(arguments[1]) /><cfreturn this /></cffunction>
|
||||
<cffunction name="getMonth" access="public" returntype="any" output="false"><cfreturn variables.instance.expMonth /></cffunction>
|
||||
|
||||
<cffunction name="setYear" access="public" returntype="any" output="false"><cfset variables.instance.expYear = numbersOnly(arguments[1]) /><cfreturn this /></cffunction>
|
||||
<cffunction name="getYear" access="public" returntype="any" output="false"><cfreturn variables.instance.expYear /></cffunction>
|
||||
<cffunction name="getExpirationDate" access="public" returntype="date" output="false">
|
||||
<cftry>
|
||||
<cfreturn dateAdd('d', -1, dateAdd('m', 1, createDate(val(getYear()), val(getMonth()), 1))) />
|
||||
<cfcatch type="any">
|
||||
<!--- if we can't add the dates, the month/year are invalid, so send back an obviously invalid date --->
|
||||
<cfreturn createDate(1969, 1, 1) />
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="setAccount" access="public" returntype="any" output="false"><cfset variables.instance.account = numbersOnly(arguments[1]) /><cfreturn this /></cffunction>
|
||||
<cffunction name="getAccount" access="public" returntype="any" output="false"><cfreturn variables.instance.account /></cffunction>
|
||||
<cffunction name="getAccountMasked" access="public" returntype="any" hint="Display the account number masked according to PCI DSS requirements" output="false">
|
||||
<cfset var num = getAccount() />
|
||||
<cfif len(num) EQ 16>
|
||||
<cfreturn "#left(num, 4)#-XXXX-XXXX-#right(num, 4)#" />
|
||||
<cfelse>
|
||||
<cfreturn left(num, 4) & "-" & repeatString("X", len(num) - 8) & "-" & right(num, 4) />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="setVerificationValue" access="public" returntype="any" output="false"><cfset variables.instance.verificationValue = numbersOnly(arguments[1]) /><cfreturn this /></cffunction>
|
||||
<cffunction name="getVerificationValue" access="public" returntype="any" output="false"><cfreturn variables.instance.verificationValue /></cffunction>
|
||||
|
||||
<!--- for Switch/Solo; not supported yet --->
|
||||
<cffunction name="setIssueNumber" access="public" returntype="any" output="false"><cfset variables.instance.issueNumber = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getIssueNumber" access="public" returntype="any" output="false"><cfreturn variables.instance.issueNumber /></cffunction>
|
||||
|
||||
<cffunction name="setStartMonth" access="public" returntype="any" output="false"><cfset variables.instance.startMonth = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getStartMonth" access="public" returntype="any" output="false"><cfreturn variables.instance.startMonth /></cffunction>
|
||||
|
||||
<cffunction name="setStartYear" access="public" returntype="any" output="false"><cfset variables.instance.startYear = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getStartYear" access="public" returntype="any" output="false"><cfreturn variables.instance.startYear /></cffunction>
|
||||
|
||||
|
||||
|
||||
<!--- private workers for validation / etc --->
|
||||
<cffunction name="numbersOnly" access="private" returntype="any" output="false"><cfreturn reReplace(arguments[1], "[^[:digit:]]", "", "ALL") /></cffunction>
|
||||
|
||||
<cffunction name="getIsMod10" access="private" returntype="any" output="false">
|
||||
<cfscript>
|
||||
/**
|
||||
* Checks to see whether a string passed to it passes the Luhn algorithm (also known as the Mod10 algorithm)
|
||||
*
|
||||
* @param card_number String to check. (Required)
|
||||
* @return Returns a boolean.
|
||||
* @author Scott Glassbrook (scott@phydiux.com)
|
||||
* @version 1, April 22, 2003
|
||||
*/
|
||||
var rebmun_drac = Reverse(ReReplaceNoCase(getAccount(), "[^0-9]", "", "All"));
|
||||
var length = len(rebmun_drac);
|
||||
var even_list = "";
|
||||
var even_numbers = "0";
|
||||
var odd_numbers = "0";
|
||||
var loop1 = "1";
|
||||
var loop2 = "1";
|
||||
|
||||
while (loop1 LTE length)
|
||||
{
|
||||
if ((loop1 mod 2) eq "0")
|
||||
even_list = even_list & (mid(rebmun_drac, loop1, 1) * 2);
|
||||
else
|
||||
odd_numbers = (odd_numbers + mid(rebmun_drac, loop1, 1));
|
||||
loop1 = loop1 + 1;
|
||||
}
|
||||
|
||||
while (loop2 LTE len(even_list))
|
||||
{
|
||||
even_numbers = (even_numbers + mid(even_list, loop2, 1));
|
||||
loop2 = loop2 + 1;
|
||||
}
|
||||
|
||||
if ((even_numbers + odd_numbers) mod 10 eq "0")
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!---
|
||||
DUMP
|
||||
--->
|
||||
<cffunction name="dump" access="public" output="true" return="void">
|
||||
<cfargument name="abort" type="boolean" default="false" />
|
||||
<cfdump var="#variables.instance#" />
|
||||
<cfif arguments.abort>
|
||||
<cfabort />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- Date: 7/6/2008 Usage: return a copy of the internal values --->
|
||||
<cffunction name="getMemento" output="false" access="public" returntype="any" hint="return a copy of the internal values">
|
||||
<cfreturn duplicate(variables.instance) />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
307
cfpayment/api/model/eft.cfc
Normal file
307
cfpayment/api/model/eft.cfc
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
<!---.UserFirstName.UserFirstName.UserFirstName
|
||||
$Id$
|
||||
|
||||
Copyright 2007 Brian Ghidinelli (http://www.ghidinelli.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 name="eft" output="false" hint="Object for holding EFT account data">
|
||||
<cfproperty name="firstName" type="string" default="" />
|
||||
<cfproperty name="lastName" type="string" default="" />
|
||||
<cfproperty name="address" type="string" default="" />
|
||||
<cfproperty name="address2" type="string" default="" />
|
||||
<cfproperty name="city" type="string" default="" />
|
||||
<cfproperty name="region" type="string" default="" />
|
||||
<cfproperty name="postalCode" type="string" default="" />
|
||||
<cfproperty name="country" type="string" default="" />
|
||||
<cfproperty name="phoneNumber" type="string" default="" />
|
||||
<cfproperty name="account" type="numeric" default="" />
|
||||
<cfproperty name="routingNumber" type="numeric" default="" />
|
||||
<cfproperty name="checkNumber" type="numeric" default="" />
|
||||
<cfproperty name="accountType" type="string" default="" />
|
||||
<cfproperty name="SEC" type="string" default="" />
|
||||
|
||||
|
||||
<!---
|
||||
PROPERTIES
|
||||
--->
|
||||
<cfset variables.instance = structNew() />
|
||||
<cfset variables.instance.firstName = "" />
|
||||
<cfset variables.instance.LaerFirstName = "" />
|
||||
<cfset variables.instance.address = "" />
|
||||
<cfset variables.instance.address2 = "" />
|
||||
<cfset variables.instance.city = "" />
|
||||
<cfset variables.instance.region = "" />
|
||||
<cfset variables.instance.postalCode = "" />
|
||||
<cfset variables.instance.country = "" />
|
||||
<cfset variables.instance.phoneNumber = "" />
|
||||
<cfset variables.instance.account = "" />
|
||||
<cfset variables.instance.routingNumber = "" />
|
||||
<!--- check numbers can have arbitrary values --->
|
||||
<cfset variables.instance.checkNumber = "" />
|
||||
<!--- account type is typically "checking", "savings", etc. Used by some ACH transactions if not implied. --->
|
||||
<cfset variables.instance.accountType = "" />
|
||||
<!--- Standard Entry Class or SEC Code: http://en.wikipedia.org/wiki/Automated_Clearing_House#Standard_entry_class_code --->
|
||||
<cfset variables.instance.SEC = "WEB" /><!--- WEB is implicit in e-check transactions but is required for all EFTs by NACHA regulations --->
|
||||
|
||||
<!---
|
||||
INITIALIZATION / CONFIGURATION
|
||||
--->
|
||||
<cffunction name="init" access="public" returntype="eft" output="false">
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<!--- convenience boolean wrapper around validate() --->
|
||||
<cffunction name="getIsValid" access="public" returntype="boolean" output="false" hint="True/false the bank account is valid">
|
||||
<cfreturn arrayLen(validate()) EQ 0 />
|
||||
</cffunction>
|
||||
|
||||
<!--- if we pass this successfully, we should be able to send it to the gateway safely --->
|
||||
<cffunction name="validate" access="public" returntype="any" output="false">
|
||||
<cfset var errors = arrayNew(1) />
|
||||
<cfset var thisError = structNew() />
|
||||
|
||||
<!--- EFT data requiresments based on iTransact/PaymentClearing.com:
|
||||
|
||||
Field Name Required
|
||||
FirstName Yes
|
||||
LastName Yes
|
||||
PhoneNumber Yes
|
||||
Address1 No
|
||||
Address2 No
|
||||
BirthDate No
|
||||
City No
|
||||
CustomerEmail No
|
||||
CheckNumber No
|
||||
DriversLicenseNumber No
|
||||
DriversLicenseState No
|
||||
PostalCode No
|
||||
State No
|
||||
SSN No
|
||||
|
||||
--->
|
||||
|
||||
<!--- First Name --->
|
||||
<cfif (NOT len(trim(getFirstName())))>
|
||||
<cfset thisError.field = "firstName" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "First name is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- Last Name --->
|
||||
<cfif NOT len(trim(getLastName()))>
|
||||
<cfset thisError.field = "lastName" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Last name is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- Last Name --->
|
||||
<cfif NOT len(trim(getPhoneNumber()))>
|
||||
<cfset thisError.field = "phoneNumber" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Phone number is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- Account Number (length/formatting greatly varies from bank to bank) --->
|
||||
<cfif NOT len(getAccount())>
|
||||
<cfset thisError.field = "account" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Account number is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
<cfif len(getAccount()) AND NOT isNumeric(getAccount())>
|
||||
<cfset thisError.field = "account" />
|
||||
<cfset thisError.type = "invalidType" />
|
||||
<cfset thisError.message = "Account number is not numeric" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- ABA Routing Number --->
|
||||
<cfif NOT len(getRoutingNumber())>
|
||||
<cfset thisError.field = "routingNumber" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "Routing number is required" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
<cfif len(getRoutingNumber()) AND NOT isNumeric(getRoutingNumber())>
|
||||
<cfset thisError.field = "routingNumber" />
|
||||
<cfset thisError.type = "invalidType" />
|
||||
<cfset thisError.message = "Routing number is not numeric" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
<cfif len(getAccount()) AND NOT isABA(getRoutingNumber())>
|
||||
<cfset thisError.field = "routingNumber" />
|
||||
<cfset thisError.type = "invalidValue" />
|
||||
<cfset thisError.message = "Routing number is invalid" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- Check Number --->
|
||||
<cfif len(getCheckNumber()) AND NOT isNumeric(getCheckNumber())>
|
||||
<cfset thisError.field = "checkNumber" />
|
||||
<cfset thisError.type = "invalidType" />
|
||||
<cfset thisError.message = "Check number is not numeric" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<!--- Check Number --->
|
||||
<cfif NOT len(getSEC())>
|
||||
<cfset thisError.field = "SEC" />
|
||||
<cfset thisError.type = "required" />
|
||||
<cfset thisError.message = "SEC code is required by NACHA regulations" />
|
||||
<cfset arrayAppend(errors, duplicate(thisError)) />
|
||||
</cfif>
|
||||
|
||||
<cfreturn errors />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!---
|
||||
ACCESSORS
|
||||
--->
|
||||
<cffunction name="setFirstName" access="public" returntype="any" output="false"><cfset variables.instance.firstName = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getFirstName" access="public" returntype="any" output="false"><cfreturn variables.instance.firstName /></cffunction>
|
||||
|
||||
<cffunction name="setLastName" access="public" returntype="any" output="false"><cfset variables.instance.LaerFirstName = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getLastName" access="public" returntype="any" output="false"><cfreturn variables.instance.LaerFirstName /></cffunction>
|
||||
<cffunction name="getName" access="public" returntype="any" hint="I return the firstname and last name as one string." output="false">
|
||||
<cfset var ret = getFirstName() />
|
||||
<cfif len(ret) and len(getLastName())>
|
||||
<cfset ret = ret & " " />
|
||||
</cfif>
|
||||
<cfset ret = ret & getLastName() />
|
||||
<cfreturn ret />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="setAddress" access="public" returntype="any" output="false"><cfset variables.instance.address = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getAddress" access="public" returntype="any" output="false"><cfreturn variables.instance.address /></cffunction>
|
||||
|
||||
<cffunction name="setAddress2" access="public" returntype="any" output="false"><cfset variables.instance.address2 = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getAddress2" access="public" returntype="any" output="false"><cfreturn variables.instance.address2 /></cffunction>
|
||||
|
||||
<cffunction name="setCity" access="public" returntype="any" output="false"><cfset variables.instance.city = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getCity" access="public" returntype="any" output="false"><cfreturn variables.instance.city /></cffunction>
|
||||
|
||||
<cffunction name="setRegion" access="public" returntype="any" hint="Region is synonym for State or Province" output="false"><cfset variables.instance.region = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getRegion" access="public" returntype="any" output="false"><cfreturn variables.instance.region /></cffunction>
|
||||
|
||||
<cffunction name="setPostalCode" access="public" returntype="any" output="false"><cfset variables.instance.postalCode = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getPostalCode" access="public" returntype="any" output="false"><cfreturn variables.instance.postalCode /></cffunction>
|
||||
|
||||
<cffunction name="setCountry" access="public" returntype="any" output="false"><cfset variables.instance.country = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getCountry" access="public" returntype="any" output="false"><cfreturn variables.instance.country /></cffunction>
|
||||
|
||||
<cffunction name="setPhoneNumber" access="public" returntype="any" output="false"><cfset variables.instance.PhoneNumber = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getPhoneNumber" access="public" returntype="any" output="false"><cfreturn variables.instance.PhoneNumber /></cffunction>
|
||||
|
||||
<cffunction name="setAccount" access="public" returntype="any" output="false"><cfset variables.instance.account = numbersOnly(arguments[1]) /><cfreturn this /></cffunction>
|
||||
<cffunction name="getAccount" access="public" returntype="any" output="false"><cfreturn variables.instance.account /></cffunction>
|
||||
<cffunction name="getAccountMasked" access="public" returntype="any" hint="Display the account number masked for security purposes" output="false">
|
||||
<cfset var num = getAccount() />
|
||||
<cfif len(num) GT 5>
|
||||
<cfreturn repeatString("X", len(num) - 5) & right(num, 5) />
|
||||
<cfelse>
|
||||
<!--- this is a weak ass account number --->
|
||||
<cfreturn num />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="setRoutingNumber" access="public" returntype="any" output="false"><cfset variables.instance.routingNumber = numbersOnly(arguments[1]) /><cfreturn this /></cffunction>
|
||||
<cffunction name="getRoutingNumber" access="public" returntype="any" output="false"><cfreturn variables.instance.routingNumber /></cffunction>
|
||||
|
||||
<cffunction name="setCheckNumber" access="public" returntype="any" output="false"><cfset variables.instance.checkNumber = numbersOnly(arguments[1]) /><cfreturn this /></cffunction>
|
||||
<cffunction name="getCheckNumber" access="public" returntype="any" output="false"><cfreturn variables.instance.checkNumber /></cffunction>
|
||||
|
||||
<cffunction name="setAccountType" access="public" returntype="any" output="false"><cfset variables.instance.AccountType = arguments[1] /><cfreturn this /></cffunction>
|
||||
<cffunction name="getAccountType" access="public" returntype="any" output="false"><cfreturn variables.instance.AccountType /></cffunction>
|
||||
|
||||
<cffunction name="setSEC" access="public" returntype="any" output="false"><cfset variables.instance.SEC = ucase(arguments[1]) /><cfreturn this /></cffunction>
|
||||
<cffunction name="getSEC" access="public" returntype="any" output="false"><cfreturn variables.instance.SEC /></cffunction>
|
||||
|
||||
|
||||
<!--- private workers for validation / etc --->
|
||||
<cffunction name="numbersOnly" access="private" returntype="any" output="false"><cfreturn reReplace(arguments[1], "[^[:digit:]]", "", "ALL") /></cffunction>
|
||||
|
||||
<cffunction name="isABA" access="private" returntype="any" output="false">
|
||||
<cfscript>
|
||||
/**
|
||||
* Checks that a number is a valid ABA routing number.
|
||||
*
|
||||
* @param number Number you want to validate as an ABA routing number.
|
||||
* @return Returns a Boolean.
|
||||
* @author Michael Osterman (mosterman@highspeed.com)
|
||||
* @version 1, March 21, 2002
|
||||
*/
|
||||
var j = 0;
|
||||
var cd = 0; //check-digit value
|
||||
var result = false;
|
||||
var modVal = 0; //compared to check-digit
|
||||
var weights = ArrayNew(1);
|
||||
var number = getRoutingNumber();
|
||||
|
||||
// verify it's worth looking at
|
||||
if (NOT isNumeric(number)) return false;
|
||||
if (compare(len(number), 9)) return false;
|
||||
|
||||
ArraySet(weights, 1, 8, 0);
|
||||
|
||||
//set the weights for the following loop
|
||||
weights[1] = 3;
|
||||
weights[2] = 7;
|
||||
weights[3] = 1;
|
||||
weights[4] = 3;
|
||||
weights[5] = 7;
|
||||
weights[6] = 1;
|
||||
weights[7] = 3;
|
||||
weights[8] = 7;
|
||||
|
||||
cd = Right(number, 1);
|
||||
|
||||
for (i = 1; i lte 8; i = i + 1)
|
||||
{
|
||||
j = j + ((Mid(number, i, 1)) * weights[i]);
|
||||
}
|
||||
|
||||
modVal = ((10 - (j mod 10)) mod 10);
|
||||
|
||||
if (modVal eq cd)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
</cfscript>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!---
|
||||
DUMP
|
||||
--->
|
||||
<cffunction name="dump" access="public" output="true" return="void">
|
||||
<cfargument name="abort" type="boolean" default="false" />
|
||||
<cfdump var="#variables.instance#" />
|
||||
<cfif arguments.abort>
|
||||
<cfabort />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- Date: 7/6/2008 Usage: return a copy of the internal values --->
|
||||
<cffunction name="getMemento" output="false" access="public" returntype="any" hint="return a copy of the internal values">
|
||||
<cfreturn duplicate(variables.instance) />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
9
cfpayment/api/model/money.cfc
Normal file
9
cfpayment/api/model/money.cfc
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<!---
$Id$
Copyright 2007 Brian Ghidinelli (http://www.ghidinelli.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 name="money" output="false" hint="Holds details about the amount to be charged and its attributes">
<cfproperty name="cents" type="numeric" default="" />
<cfproperty name="currency" type="numeric" default="" />
<!---
PROPERTIES
--->
<cfset variables.instance = structNew() />
<cfset variables.instance.cents = 0 />
<cfset variables.instance.currency = "USD" />
<!--- there are a few currencies which do not have fractions of 1/100th for cents;
for those, we map them out here (http://en.wikipedia.org/wiki/List_of_circulating_currencies)
If you are a developer in one of those few countries, then you will need to
extend the money object and override this value.
--->
<cfset variables.instance.fraction = 100 />
<!--- INITIALIZATION / CONFIGURATION --->
<cffunction name="init" access="public" returntype="money" output="false">
<cfargument name="cents" type="numeric" required="false" default="0" />
<cfargument name="currency" type="string" required="false" default="USD" />
<cfset setCents(arguments.cents) />
<cfset setCurrency(arguments.currency) />
<cfreturn this />
</cffunction>
<!--- represent the amount internally as an integer of cents --->
<cffunction name="setCents" access="public" returntype="any" output="false">
<cfset variables.instance.cents = arguments[1] />
<cfreturn this />
</cffunction>
<cffunction name="getCents" access="public" returntype="any" output="false">
<cfreturn variables.instance.cents />
</cffunction>
<!--- NOTE: no setAmount method (see developer notes) --->
<cffunction name="getAmount" access="public" returntype="any" output="false">
<cfreturn numberFormat(getCents() / variables.instance.fraction, '-.__') />
</cffunction>
<!--- TODO: expand currency support beyond being just a placeholder to support conversion between currencies and l10n --->
|
||||
<cffunction name="getCurrency" access="public" output="false" returntype="any">
|
||||
<cfreturn variables.instance.currency />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="setCurrency" access="public" output="false" returntype="any">
|
||||
<cfargument name="currency" type="string" required="true" />
|
||||
<cfset variables.instance.currency = arguments.currency />
<cfreturn this />
|
||||
</cffunction>
</cfcomponent>
|
||||
1
cfpayment/api/model/oauth.cfc
Normal file
1
cfpayment/api/model/oauth.cfc
Normal file
|
|
@ -0,0 +1 @@
|
|||
<!---
Copyright 2007 Brian Ghidinelli (http://www.ghidinelli.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 name="oauth" output="false" hint="Object for holding accesstokens and secrets for services like Dwolla which authorize users with OAuth 2.0">
<cfproperty name="accesstoken" type="string" default="" />
<cfproperty name="secret" type="string" default="" />
<!---
PROPERTIES
--->
<cfset variables.instance = structNew() />
<cfset variables.instance.accesstoken = "" />
<cfset variables.instance.secret = "" />
<!---
INITIALIZATION / CONFIGURATION
--->
<cffunction name="init" access="public" returntype="accesstoken" output="false">
<cfargument name="accesstoken" type="any" required="false" default="" />
<cfargument name="secret" type="any" required="false" default="" />
<cfset setAccessToken(arguments.accesstoken) />
<cfset setSecret(arguments.secret) />
<cfreturn this />
</cffunction>
<!--- convenience boolean wrapper around validate() --->
<cffunction name="getIsValid" access="public" returntype="boolean" output="false" hint="True/false the bank account is valid">
<cfreturn arrayLen(validate()) EQ 0 />
</cffunction>
<!--- if we pass this successfully, we should be able to send it to the gateway safely --->
<cffunction name="validate" access="public" returntype="any" output="false">
<cfset var errors = arrayNew(1) />
<cfset var thisError = structNew() />
<!--- vault/customer ID (is optional, at least with braintree) --->
<cfif (NOT len(trim(getAccessToken())))>
<cfset thisError.field = "accesstoken" />
<cfset thisError.type = "required" />
<cfset thisError.message = "AccessToken is required" />
<cfset arrayAppend(errors, duplicate(thisError)) />
</cfif>
<cfreturn errors />
</cffunction>
<!---
ACCESSORS
--->
<cffunction name="setAccessToken" access="public" returntype="any" output="false"><cfset variables.instance.accesstoken = arguments[1] /><cfreturn this /></cffunction>
<cffunction name="getAccessToken" access="public" returntype="any" output="false"><cfreturn variables.instance.accesstoken /></cffunction>
<cffunction name="setSecret" access="public" returntype="any" output="false"><cfset variables.instance.secret = arguments[1] /><cfreturn this /></cffunction>
<cffunction name="getSecret" access="public" returntype="any" output="false"><cfreturn variables.instance.secret /></cffunction>
<!---
DUMP
--->
<cffunction name="dump" access="public" output="true" return="void">
<cfargument name="abort" type="boolean" default="false" />
<cfdump var="#variables.instance#" />
<cfif arguments.abort>
<cfabort />
</cfif>
</cffunction>
<!--- Date: 7/6/2008 Usage: return a copy of the internal values --->
<cffunction name="getMemento" output="false" access="public" returntype="any" hint="return a copy of the internal values">
<cfreturn duplicate(variables.instance) />
</cffunction>
</cfcomponent>
|
||||
346
cfpayment/api/model/response.cfc
Normal file
346
cfpayment/api/model/response.cfc
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
<!---
|
||||
$Id$
|
||||
|
||||
Copyright 2007 Brian Ghidinelli (http://www.ghidinelli.com/)
|
||||
Mark Mazelin (http://www.mkville.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 name="response" displayname="Gateway Response" output="false" hint="Normalized result for gateway response">
|
||||
|
||||
<!--- CONSTANTS in psuedo-constructor --->
|
||||
<cfscript>
|
||||
variables.cfpayment = structNew();
|
||||
|
||||
variables.cfpayment.Status = ""; // set in init() to be unprocessed
|
||||
variables.cfpayment.StatusCode = ""; // hold the HTTP/connection status code
|
||||
variables.cfpayment.Result = ""; // hold the raw response from the other end
|
||||
variables.cfpayment.TestMode = false;
|
||||
variables.cfpayment.Message = "";
|
||||
variables.cfpayment.TransactionID = ""; // transaction id from remote system
|
||||
variables.cfpayment.Authorization = ""; // six-character alphanum approval/authorization code
|
||||
variables.cfpayment.AVSCode = "";
|
||||
variables.cfpayment.CVVCode = "";
|
||||
variables.cfpayment.ParsedResult = "";
|
||||
variables.cfpayment.RequestData = ""; // store the payload from the Request; dev use only; populated only when testmode = true
|
||||
variables.cfpayment.TokenID = ""; // normalize an ID for vault/remote lockbox services (store/unstore methods)
|
||||
|
||||
// list the possible AVS responses
|
||||
variables.cfpayment.ResponseAVS = structNew();
|
||||
structInsert(variables.cfpayment.ResponseAVS, "A", "Street address matches, but 5-digit and 9-digit postal code do not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "B", "Street address matches, but postal code not verified.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "C", "Street address and postal code do not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "D", "Street address and postal code match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "E", "AVS data is invalid or AVS is not allowed for this card type.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "F", "Card member's name does not match, but billing postal code matches.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "G", "Non-U.S. issuing bank does not support AVS.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "H", "Card member's name does not match. Street address and postal code match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "I", "Address not verified.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "J", "Card member's name, billing address, and postal code match. Shipping information verified and chargeback protection guaranteed through the Fraud Protection Program.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "K", "Card member's name matches but billing address and billing postal code do not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "L", "Card member's name and billing postal code match, but billing address does not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "M", "Street address and postal code match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "N", "Street address and postal code do not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "O", "Card member's name and billing address match, but billing postal code does not match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "P", "Postal code matches, but street address not verified.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "Q", "Card member's name, billing address, and postal code match. Shipping information verified but chargeback protection not guaranteed.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "R", "System unavailable.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "S", "U.S.-issuing bank does not support AVS.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "T", "Card member's name does not match, but street address matches.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "U", "Address information unavailable.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "V", "Card member's name, billing address, and billing postal code match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "W", "Street address does not match, but 9-digit postal code matches.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "X", "Street address and 9-digit postal code match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "Y", "Street address and 5-digit postal code match.", true);
|
||||
structInsert(variables.cfpayment.ResponseAVS, "Z", "Street address does not match, but 5-digit postal code matches.", true);
|
||||
|
||||
// list the CVC or CVV2 response options
|
||||
variables.cfpayment.ResponseCVV = structNew();
|
||||
structInsert(variables.cfpayment.ResponseCVV, "D", "Suspicious transaction", true);
|
||||
structInsert(variables.cfpayment.ResponseCVV, "I", "Failed data validation check", true);
|
||||
structInsert(variables.cfpayment.ResponseCVV, "M", "Match", true);
|
||||
structInsert(variables.cfpayment.ResponseCVV, "N", "No Match", true);
|
||||
structInsert(variables.cfpayment.ResponseCVV, "P", "Not Processed", true);
|
||||
structInsert(variables.cfpayment.ResponseCVV, "S", "Should have been present", true);
|
||||
structInsert(variables.cfpayment.ResponseCVV, "U", "Issuer unable to process request", true);
|
||||
structInsert(variables.cfpayment.ResponseCVV, "X", "Card does not support verification", true);
|
||||
|
||||
</cfscript>
|
||||
|
||||
|
||||
<cffunction name="init" output="false" access="public" returntype="any" hint="Instantiate (and optionally populate) the response object">
|
||||
<cfargument name="service" type="any" required="true" />
|
||||
<cfargument name="Status" type="string" required="false" />
|
||||
<cfargument name="StatusCode" type="string" required="false" />
|
||||
<cfargument name="Message" type="string" required="false" />
|
||||
<cfargument name="Result" type="string" required="false" />
|
||||
<cfargument name="RequestData" type="struct" required="false" />
|
||||
<cfargument name="TestMode" type="boolean" required="false" />
|
||||
|
||||
<cfset variables.cfpayment.service = arguments.service />
|
||||
|
||||
<cfif NOT structKeyExists(arguments, "Status")>
|
||||
<cfset setStatus(getService().getStatusUnprocessed()) />
|
||||
</cfif>
|
||||
|
||||
<cfset populate(argumentCollection = arguments) />
|
||||
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getService" output="false" access="private" returntype="any" hint="get access to the service for generating responses, errors, etc">
|
||||
<cfreturn variables.cfpayment.service />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getSuccess" access="public" output="false" returntype="string" hint="Success is determined by comparing status to success in the core API">
|
||||
<cfreturn getStatus() EQ getService().getStatusSuccessful()>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="hasError" access="public" output="false" returntype="boolean" hint="An error is determined by the status code; the list of good/bad is in the core API">
|
||||
<cfreturn listFind(getService().getStatusErrors(), getStatus()) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getStatus" access="public" output="false" returntype="numeric" hint="Status tracks transaction flow from unprocessed to attempted to success or exception">
|
||||
<cfreturn variables.cfpayment.Status />
|
||||
</cffunction>
|
||||
<cffunction name="setStatus" access="public" output="false" returntype="any">
|
||||
<cfargument name="Status" type="any" required="true" />
|
||||
<cfset variables.cfpayment.Status = arguments.Status />
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getStatusCode" access="public" output="false" returntype="any" hint="StatusCode represents the original connection's result status. For HTTP this would be like 200, 404, 500, etc. For RESTful APIs which may use status codes to define results">
|
||||
<cfreturn variables.cfpayment.StatusCode />
|
||||
</cffunction>
|
||||
<cffunction name="setStatusCode" access="public" output="false" returntype="void">
|
||||
<cfargument name="StatusCode" type="any" required="true" />
|
||||
<cfset variables.cfpayment.StatusCode = arguments.StatusCode />
|
||||
</cffunction>
|
||||
|
||||
<!--- Usage: getAVSCode / setAVSCode methods for AVSCode value --->
|
||||
<cffunction name="getAVSCode" access="public" output="false" returntype="any">
|
||||
<cfreturn variables.cfpayment.AVSCode />
|
||||
</cffunction>
|
||||
<cffunction name="setAVSCode" access="public" output="false" returntype="any">
|
||||
<cfargument name="AVSCode" type="any" required="true" />
|
||||
|
||||
<cfif len(arguments.AVSCode)>
|
||||
<cfif structKeyExists(variables.cfpayment.ResponseAVS, arguments.AVSCode)>
|
||||
<cfset variables.cfpayment.AVSCode = uCase(arguments.AVSCode) />
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid AVS Response Code: #arguments.AVSCode#" type="cfpayment.InvalidResponse.AVS" />
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<!--- Usage: getCVVCode / setCVVCode methods for CVVCode value --->
|
||||
<cffunction name="getCVVCode" access="public" output="false" returntype="any">
|
||||
<cfreturn variables.cfpayment.CVVCode />
|
||||
</cffunction>
|
||||
<cffunction name="setCVVCode" access="public" output="false" returntype="any">
|
||||
<cfargument name="CVVCode" type="any" required="true" />
|
||||
|
||||
<cfif len(arguments.CVVCode)>
|
||||
<cfif structKeyExists(variables.cfpayment.ResponseCVV, arguments.CVVCode)>
|
||||
<cfset variables.cfpayment.CVVCode = uCase(arguments.CVVCode) />
|
||||
<cfelse>
|
||||
<cfthrow message="Invalid CVV Response Code: #arguments.CVVCode#" type="cfpayment.InvalidResponse.CVV" />
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- Gateways typically return both an Authorization code (from Visa/Amex/MC/etc) and a Transaction ID (their reference number) --->
|
||||
<cffunction name="getAuthorization" access="public" output="false" returntype="string" hint="Authorization code is a bank-provided ID generated by Visa/Amex/MC/etc">
|
||||
<cfreturn variables.cfpayment.Authorization />
|
||||
</cffunction>
|
||||
<cffunction name="setAuthorization" access="public" output="false" returntype="any">
|
||||
<cfargument name="Authorization" type="string" required="true" />
|
||||
<cfset variables.cfpayment.Authorization = arguments.Authorization />
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getTransactionID" access="public" output="false" returntype="any" hint="Transaction ID is an ID generated by the gateway to identify the transaction">
|
||||
<cfreturn variables.cfpayment.TransactionID />
|
||||
</cffunction>
|
||||
<cffunction name="setTransactionID" access="public" output="false" returntype="any">
|
||||
<cfargument name="TransactionID" type="any" required="true" />
|
||||
<cfset variables.cfpayment.TransactionID = arguments.TransactionID />
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getTokenID" access="public" output="false" returntype="any" hint="Token ID is the reference to an account stored by the gateway">
|
||||
<cfreturn variables.cfpayment.TokenID />
|
||||
</cffunction>
|
||||
<cffunction name="setTokenID" access="public" output="false" returntype="any">
|
||||
<cfargument name="TokenID" type="any" required="true" />
|
||||
<cfset variables.cfpayment.TokenID = arguments.TokenID />
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getResult" access="public" output="false" returntype="any" hint="Holds the raw response from the payment processor for the gateway to parse">
|
||||
<cfreturn variables.cfpayment.Result />
|
||||
</cffunction>
|
||||
<cffunction name="setResult" access="public" output="false" returntype="any">
|
||||
<cfargument name="Result" type="any" required="true" />
|
||||
<cfset variables.cfpayment.Result = arguments.Result />
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<!--- hold the parsed response from the payment processor for the gateway to access and leverage --->
|
||||
<cffunction name="getParsedResult" access="public" output="false" returntype="any">
|
||||
<cfreturn variables.cfpayment.ParsedResult />
|
||||
</cffunction>
|
||||
<cffunction name="setParsedResult" access="public" output="false" returntype="any">
|
||||
<cfargument name="ParsedResult" type="any" required="true" />
|
||||
<cfset variables.cfpayment.ParsedResult = arguments.ParsedResult />
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getTestMode" access="public" output="false" returntype="boolean">
|
||||
<cfreturn variables.cfpayment.TestMode />
|
||||
</cffunction>
|
||||
<cffunction name="setTestMode" access="public" output="false" returntype="void">
|
||||
<cfargument name="TestMode" type="boolean" required="true" />
|
||||
<cfset variables.cfpayment.TestMode = arguments.TestMode />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getRequestData" output="false" access="public" returntype="any" hint="RequestData is only populated when TestMode = true">
|
||||
<cfreturn variables.cfpayment.RequestData />
|
||||
</cffunction>
|
||||
<cffunction name="setRequestData" output="false" access="public" returntype="any" hint="Be cautious when populating RequestData. Card holder data must be protected in compliance with PCI DSS.">
|
||||
<cfset variables.cfpayment.RequestData = arguments[1] />
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- Usage: getMessage / setMessage methods for Message value --->
|
||||
<cffunction name="getMessage" access="public" output="false" returntype="string" hint="Human-readable transaction result">
|
||||
<cfreturn variables.cfpayment.Message />
|
||||
</cffunction>
|
||||
<cffunction name="setMessage" access="public" output="false" returntype="any">
|
||||
<cfargument name="Message" type="string" required="true" />
|
||||
<cfset variables.cfpayment.Message = arguments.Message />
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getAVSPostalMatch" output="false" access="private" returntype="string" hint="Normalize the AVS postal match code">
|
||||
<cfset var res = uCase(getAVSCode()) />
|
||||
|
||||
<!--- Y = yes, N = no, X = not relevant, U = unknown --->
|
||||
<cfif listFind("D,H,F,J,L,M,P,Q,V,W,X,Y,Z", res)>
|
||||
<cfreturn 'Y' />
|
||||
<cfelseif listFind("A,C,K,N,O", res)>
|
||||
<cfreturn 'N' />
|
||||
<cfelseif listFind("G,S", res)>
|
||||
<cfreturn 'X' />
|
||||
</cfif>
|
||||
|
||||
<cfreturn 'U' />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getAVSStreetMatch" output="false" access="private" returntype="string" hint="Normalize the AVS street match code">
|
||||
<cfset var res = uCase(getAVSCode()) />
|
||||
|
||||
<cfif listFind("A,B,D,H,J,M,O,Q,T,V,X,Y", res)><!--- it does match --->
|
||||
<cfreturn 'Y' />
|
||||
<cfelseif listFind("C,K,L,N,P,W,Z", res)><!--- it does not match --->
|
||||
<cfreturn 'N' />
|
||||
<cfelseif listFind("G,S", res)><!--- bank does not support/verify AVS --->
|
||||
<cfreturn 'X' />
|
||||
</cfif>
|
||||
|
||||
<cfreturn 'U' /><!--- unknown - AVS invalid or could not be verified --->
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getAVSMessage" output="false" access="public" returntype="string" hint="Get the human-readable AVS response">
|
||||
<cfset var ret = "" />
|
||||
<cfif structKeyExists(variables.cfpayment.ResponseAVS, getAVSCode())>
|
||||
<cfset ret = variables.cfpayment.ResponseAVS[getAVSCode()] />
|
||||
</cfif>
|
||||
<cfreturn ret />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getCVVMessage" output="false" access="public" returntype="string" hint="Get the human-readable CVV response">
|
||||
<cfset var ret = "" />
|
||||
<cfif structKeyExists(variables.cfpayment.ResponseCVV, getCVVCode())>
|
||||
<cfset ret = variables.cfpayment.ResponseCVV[getCVVCode()] />
|
||||
</cfif>
|
||||
<cfreturn ret />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="isValidAVS" output="false" access="public" returntype="boolean" hint="Check if AVS passed fully?">
|
||||
<cfargument name="AllowBlankCode" type="boolean" default="true" hint="Set to true to allow blank AVS return code to pass validity" />
|
||||
<cfargument name="AllowPostalOnlyMatch" type="boolean" default="false" hint="Set to true to allow postal-only AVS match to pass validity" />
|
||||
<cfargument name="AllowStreetOnlyMatch" type="boolean" default="false" hint="Set to true to allow prohibit street-only AVS match to pass validity" />
|
||||
<cfset var ret = false />
|
||||
<cfif (arguments.AllowBlankCode AND (len(getAVSCode()) EQ 0))>
|
||||
<cfset ret = true />
|
||||
<cfelseif len(getAVSCode())>
|
||||
<cfif arguments.AllowStreetOnlyMatch AND (getAVSStreetMatch() EQ "Y")>
|
||||
<cfset ret = true />
|
||||
<cfelseif arguments.AllowPostalOnlyMatch AND (getAVSPostalMatch() EQ "Y")>
|
||||
<cfset ret = true />
|
||||
<cfelseif (getAVSPostalMatch() EQ "Y") AND (getAVSStreetMatch() EQ "Y")>
|
||||
<cfset ret = true />
|
||||
</cfif>
|
||||
</cfif>
|
||||
<cfreturn ret />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="isValidCVV" output="false" access="public" returntype="boolean" hint="Check if the CVV response indicates a match">
|
||||
<cfargument name="AllowBlankCode" type="boolean" default="true" hint="Set to true to allow blank CVV return code to pass validity" />
|
||||
<cfset var ret = false />
|
||||
<cfif (arguments.AllowBlankCode AND (len(getCVVCode()) EQ 0)) OR (getCVVCode() EQ "M")>
|
||||
<cfset ret = true />
|
||||
</cfif>
|
||||
<cfreturn ret />
|
||||
</cffunction>
|
||||
|
||||
<!---
|
||||
DUMP
|
||||
--->
|
||||
<cffunction name="dump" access="public" output="true" return="void">
|
||||
<cfargument name="abort" type="boolean" default="false" />
|
||||
<cfdump var="#variables.instance#" />
|
||||
<cfif arguments.abort>
|
||||
<cfabort />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getMemento" output="false" access="public" returntype="any" hint="Return a copy of the internal values">
|
||||
<cfreturn duplicate(variables.cfpayment) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="populate" access="private" returntype="void" output="false" hint="Helper function to dynamically populate setters">
|
||||
<cfset var argName = "" />
|
||||
<cfloop collection="#arguments#" item="argName">
|
||||
<cfif structKeyExists(arguments, argName) AND structKeyExists(this, "set" & argName)>
|
||||
<cfinvoke component="#this#" method="set#argName#">
|
||||
<cfinvokeargument name="#argName#" value="#arguments[argName]#" />
|
||||
</cfinvoke>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue