/usr/share/pyshared/gluon/contrib/paymentech.py is in python-gluon 2.12.3-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | #!/usr/bin/env python
# -*- coding: utf-8 -*-
# This module provides a simple API for Paymentech(c) payments
# The original code was taken from this web2py issue post
# http://code.google.com/p/web2py/issues/detail?id=1170 by Adnan Smajlovic
#
# Copyright (C) <2012> Alan Etkin <spametki@gmail.com>
# License: BSD
#
import sys, httplib, urllib, urllib2
from xml.dom.minidom import parseString
# TODO: input validation, test, debugging output
class PaymenTech(object):
"""
The base class for connecting to the Paymentech service
Format notes
============
- Credit card expiration date (exp argument) must be of mmyyyy form
- The amount is an all integers string with two decimal places:
For example, $2.15 must be formatted as "215"
Point of sale and service options (to be passed on initialization)
==================================================================
user
password
industry
message
bin_code
merchant
terminal
(WARNING!: this is False by default)
development <bool>
(the following arguments have default values)
target
host
api_url
Testing
=======
As this module consumes webservice methods, it should be tested
with particular user data with the paymentech development environment
The simplest test would be running something like the following:
from paymentech import PaymenTech
# Read the basic point of sale argument list required above
# Remember to use development = True!
pos_data = {'user': <username>, ...}
# The data arguments are documented in the .charge() method help
charge_test = {'account': <account>, ...}
mypayment = PaymentTech(**pos_data)
result = mypayment.charge(**charge_test)
print "##################################"
print "# Charge test result #"
print "##################################"
print result
#################################################################
# Notes for web2py implementations #
#################################################################
# A recommended model for handling payments
# Store this constants in a private model file (i.e. 0_private.py)
PAYMENTECH_USER = <str>
PAYMENTECH_PASSWORD = <str>
PAYMENTECH_INDUSTRY = <str>
PAYMENTECH_MESSAGE = <str>
PAYMENTECH_BIN_CODE= <str>
PAYMENTECH_MERCHANT = <str>
PAYMENTECH_terminal = <str>
DEVELOPMENT = True
PAYMENTECH_TARGET = <str>
PAYMENTECH_HOST = <str>
PAYMENTECH_API_URL = <str>
# The following table would allow passing data with web2py and to
# update records with the webservice authorization output by using
# the DAL
#
# For example:
#
# # Create a PaymenTech instance
# mypaymentech = paymentech.PaymenTech(user=PAYMENTECH_USER, ...)
#
# # Fetch a payment inserted within the app
# myrow = db.paymentech[<id>]
#
# # Send the authorization request to the webservice
# result = mypaymentech.charge(myrow.as_dict())
#
# # Update the db record with the webservice response
# myrow.update_record(**result)
db.define_table("paymentech",
Field("account"),
Field("exp", comment="Must be of the mmyyyy form"),
Field("currency_code"),
Field("currency_exponent"),
Field("card_sec_val_ind"),
Field("card_sec_val"),
Field("avs_zip"),
Field("avs_address_1"),
Field("avs_address_2"),
Field("avs_city"),
Field("avs_state"),
Field("avs_phone"),
Field("avs_country"),
Field("profile_from_order_ind"),
Field("profile_order_override_ind"),
Field("order_id"),
Field("amount",
comment="all integers with two decimal digits, \
without dot separation"),
Field("header"),
Field("status_code"),
Field("status_message"),
Field("resp_code"),
Field("tx_ref_num"),
format="%(order_id)s")
TODO: add model form validators (for exp date and amount)
"""
charge_xml = """
<?xml version="1.0" encoding="UTF-8"?>
<Request>
<NewOrder>
<OrbitalConnectionUsername>%(user)s</OrbitalConnectionUsername>
<OrbitalConnectionPassword>%(password)s</OrbitalConnectionPassword>
<IndustryType>%(industry)s</IndustryType>
<MessageType>%(message)s</MessageType>
<BIN>%(bin)s</BIN>
<MerchantID>%(merchant)s</MerchantID>
<TerminalID>%(terminal)s</TerminalID>
<AccountNum>%(account)s</AccountNum>
<Exp>%(exp)s</Exp>
<CurrencyCode>%(currency_code)s</CurrencyCode>
<CurrencyExponent>%(currency_exponent)s</CurrencyExponent>
<CardSecValInd>%(card_sec_val_ind)s</CardSecValInd>
<CardSecVal>%(card_sec_val)s</CardSecVal>
<AVSzip>%(avs_zip)s</AVSzip>
<AVSaddress1>%(avs_address_1)s</AVSaddress1>
<AVSaddress2>%(avs_address_2)s</AVSaddress2>
<AVScity>%(avs_city)s</AVScity>
<AVSstate>%(avs_state)s</AVSstate>
<AVSphoneNum>%(avs_phone)s</AVSphoneNum>
<AVScountryCode>%(avs_country)s</AVScountryCode>
<CustomerProfileFromOrderInd>%(profile_from_order_ind)s</CustomerProfileFromOrderInd>
<CustomerProfileOrderOverrideInd>%(profile_order_override_ind)s</CustomerProfileOrderOverrideInd>
<OrderID>%(order_id)s</OrderID>
<Amount>%(amount)s</Amount>
</NewOrder>
</Request>
"""
def __init__(self, development=False, user=None, password=None,
industry=None, message=None, api_url=None,
bin_code=None, merchant=None, host=None,
terminal=None, target=None):
# PaymenTech point of sales data
self.user = user
self.password = password
self.industry = industry
self.message = message
self.bin_code = bin_code
self.merchant = merchant
self.terminal = terminal
# Service options
self.development = development
self.target = target
self.host = host
self.api_url = api_url
# dev: https://orbitalvar1.paymentech.net/authorize:443
# prod: https://orbital1.paymentech.net/authorize
if self.development is False:
if not self.target:
# production
self.target = "https://orbital1.paymentech.net/authorize"
self.host, self.api_url = \
urllib2.splithost(urllib2.splittype(self.target)[1])
else:
if not self.target:
# development
self.target = "https://orbitalvar1.paymentech.net/authorize"
if not self.host:
self.host = "orbitalvar1.paymentech.net/authorize:443"
if not self.api_url:
self.api_url = "/"
def charge(self, raw=None, **kwargs):
"""
Post an XML request to Paymentech
This is an example of a call with raw xml data:
from paymentech import PaymenTech
# Note: user/password/etc data is not mandatory as it
# is retrieved from instance attributes (set on init)
pt = PaymenTech(user="<myuser>",
password="<mypassword>",
...) # see basic user in the class help
result = pt.charge(raw=xml_string)
A better way to make a charge request is to unpack a dict object
with the operation data:
...
# The complete input values are listed below in
# "Transacion data..."
charge_data = dict(account=<str>, exp=<str mmyyyy>, ...)
result = pt.charge(**charge_data)
Variable xml_string contains all details about the order,
plus we are sending username/password in there too...
Transaction data (to be passed to the charge() method)
======================================================
(Note that it is possible to override the class user,
pass, etc. passing those arguments to the .charge() method,
which are documented in the class help)
account
exp <str mmyyyy>
currency_code
currency_exponent
card_sec_val_ind
card_sec_val
avs_zip
avs_address_1
avs_address_2
avs_city
avs_state
avs_phone
avs_country
profile_from_order_ind
profile_order_override_ind
order_id
amount <str> (all integers with two decimal digits, without dot
separation)
Request header example
======================
Request: sent as POST to https://orbitalvar1.paymentech.net/authorize:443
from 127.0.0.1
request headers:
Content-Type: application/PTI45
Content-Type: application/PTI46
Content-transfer-encoding: text
Request-number: 1
Document-type: Request
Trace-number: 1234556446
<?xml version="1.0" encoding="UTF-8"?>
"""
# default charge data
data = dict(user=self.user, password=self.password,
industry=self.industry, message=self.message,
bin_code=self.bin_code, merchant=self.merchant,
terminal=self.terminal, account="", exp="",
currency_code="", currency_exponent="",
card_sec_val_ind="", card_sec_val="", avs_zip="",
avs_address_1="", avs_address_2="", avs_city="",
avs_state="", avs_phone="", avs_country="",
profile_from_order_ind="",
profile_order_override_ind="", order_id="",
amount="")
result = dict()
# Complete the charge request with the method kwargs
for k, v in kwargs.iteritems():
data[k] = v
status_code = status_message = header = resp_code = \
tx_ref_num = order_id = None
conn = httplib.HTTPS(self.host)
conn.putrequest('POST', self.api_url)
if self.development:
content_type = "PTI56"
else:
content_type = "PTI46"
if raw is None:
xml_string = self.charge_xml % data
else:
xml_string = raw
conn.putheader("Content-Type",
"application/%s") % content_type
conn.putheader("Content-transfer-encoding", "text")
conn.putheader("Request-number", "1")
conn.putheader("Content-length", str(len(xml_string)))
conn.putheader("Document-type", "Request")
conn.putheader("Trace-number", str(data["order_id"]))
conn.putheader("MIME-Version", "1.0")
conn.endheaders()
conn.send(xml_string)
result["status_code"], result["status_message"], \
result["header"] = conn.getreply()
fp = conn.getfile()
output = fp.read()
fp.close()
dom = parseString(output)
result["resp_code"] = \
dom.getElementsByTagName('RespCode')[0].firstChild.data
result["tx_ref_num"] = \
dom.getElementsByTagName('TxRefNum')[0].firstChild.data
result["order_id"] = \
dom.getElementsByTagName('CustomerRefNum')[0].firstChild.data
return result
|