541 lines
10 KiB
Python
541 lines
10 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
import hashlib
|
||
|
import string
|
||
|
import urlparse
|
||
|
from decimal import Decimal, ROUND_HALF_UP
|
||
|
|
||
|
from common import (PaymentCommon, PaymentResponse, FORM, CANCELED, PAID,
|
||
|
ERROR, Form, DENIED, ACCEPTED)
|
||
|
def N_(message): return message
|
||
|
|
||
|
ENVIRONMENT_TEST = 'TEST'
|
||
|
ENVIRONMENT_TEST_URL = 'https://secure.ogone.com/ncol/test/orderstandard.asp'
|
||
|
ENVIRONMENT_PROD = 'PROD'
|
||
|
ENVIRONMENT_PROD_URL = 'https://secure.ogone.com/ncol/prod/orderstandard.asp'
|
||
|
ENVIRONMENT = [ENVIRONMENT_TEST, ENVIRONMENT_PROD]
|
||
|
|
||
|
SHA_IN_PARAMS = """
|
||
|
ACCEPTANCE
|
||
|
ACCEPTURL
|
||
|
ADDMATCH
|
||
|
ADDRMATCH
|
||
|
AIACTIONNUMBER
|
||
|
AIAGIATA
|
||
|
AIAIRNAME
|
||
|
AIAIRTAX
|
||
|
AIBOOKIND*XX*
|
||
|
AICARRIER*XX*
|
||
|
AICHDET
|
||
|
AICLASS*XX*
|
||
|
AICONJTI
|
||
|
AIDEPTCODE
|
||
|
AIDESTCITY*XX*
|
||
|
AIDESTCITYL*XX*
|
||
|
AIEXTRAPASNAME*XX*
|
||
|
AIEYCD
|
||
|
AIFLDATE*XX*
|
||
|
AIFLNUM*XX*
|
||
|
AIGLNUM
|
||
|
AIINVOICE
|
||
|
AIIRST
|
||
|
AIORCITY*XX*
|
||
|
AIORCITYL*XX*
|
||
|
AIPASNAME
|
||
|
AIPROJNUM
|
||
|
AISTOPOV*XX*
|
||
|
AITIDATE
|
||
|
AITINUM
|
||
|
AITINUML*XX*
|
||
|
AITYPCH
|
||
|
AIVATAMNT
|
||
|
AIVATAPPL
|
||
|
ALIAS
|
||
|
ALIASOPERATION
|
||
|
ALIASPERSISTEDAFTERUSE
|
||
|
ALIASUSAGE
|
||
|
ALLOWCORRECTION
|
||
|
AMOUNT
|
||
|
AMOUNT*XX*
|
||
|
AMOUNTHTVA
|
||
|
AMOUNTTVA
|
||
|
ARP_TRN
|
||
|
BACKURL
|
||
|
BATCHID
|
||
|
BGCOLOR
|
||
|
BLVERNUM
|
||
|
BIC
|
||
|
BIN
|
||
|
BRAND
|
||
|
BRANDVISUAL
|
||
|
BUTTONBGCOLOR
|
||
|
BUTTONTXTCOLOR
|
||
|
CANCELURL
|
||
|
CARDNO
|
||
|
CATALOGURL
|
||
|
CAVV_3D
|
||
|
CAVVALGORITHM_3D
|
||
|
CERTID
|
||
|
CHECK_AAV
|
||
|
CIVILITY
|
||
|
CN
|
||
|
COM
|
||
|
COMPLUS
|
||
|
CONVCCY
|
||
|
COSTCENTER
|
||
|
COSTCODE
|
||
|
CREDITCODE
|
||
|
CREDITDEBIT
|
||
|
CUID
|
||
|
CURRENCY
|
||
|
CVC
|
||
|
CVCFLAG
|
||
|
DATA
|
||
|
DATATYPE
|
||
|
DATEIN
|
||
|
DATEOUT
|
||
|
DBXML
|
||
|
DCC_COMMPERC
|
||
|
DCC_CONVAMOUNT
|
||
|
DCC_CONVCCY
|
||
|
DCC_EXCHRATE
|
||
|
DCC_EXCHRATETS
|
||
|
DCC_INDICATOR
|
||
|
DCC_MARGINPERC
|
||
|
DCC_REF
|
||
|
DCC_SOURCE
|
||
|
DCC_VALID
|
||
|
DECLINEURL
|
||
|
DELIVERYDATE
|
||
|
DEVICE
|
||
|
DISCOUNTRATE
|
||
|
DISPLAYMODE
|
||
|
ECI
|
||
|
ECI_3D
|
||
|
ECOM_BILLTO_COMPANY
|
||
|
ECOM_BILLTO_POSTAL_CITY
|
||
|
ECOM_BILLTO_POSTAL_COUNTRYCODE
|
||
|
ECOM_BILLTO_POSTAL_COUNTY
|
||
|
ECOM_BILLTO_POSTAL_NAME_FIRST
|
||
|
ECOM_BILLTO_POSTAL_NAME_LAST
|
||
|
ECOM_BILLTO_POSTAL_NAME_PREFIX
|
||
|
ECOM_BILLTO_POSTAL_POSTALCODE
|
||
|
ECOM_BILLTO_POSTAL_STREET_LINE1
|
||
|
ECOM_BILLTO_POSTAL_STREET_LINE2
|
||
|
ECOM_BILLTO_POSTAL_STREET_LINE3
|
||
|
ECOM_BILLTO_POSTAL_STREET_NUMBER
|
||
|
ECOM_BILLTO_TELECOM_MOBILE_NUMBER
|
||
|
ECOM_BILLTO_TELECOM_PHONE_NUMBER
|
||
|
ECOM_CONSUMERID
|
||
|
ECOM_CONSUMER_GENDER
|
||
|
ECOM_CONSUMEROGID
|
||
|
ECOM_CONSUMERORDERID
|
||
|
ECOM_CONSUMERUSERALIAS
|
||
|
ECOM_CONSUMERUSERPWD
|
||
|
ECOM_CONSUMERUSERID
|
||
|
ECOM_ESTIMATEDDELIVERYDATE
|
||
|
ECOM_ESTIMATEDELIVERYDATE
|
||
|
ECOM_PAYMENT_CARD_EXPDATE_MONTH
|
||
|
ECOM_PAYMENT_CARD_EXPDATE_YEAR
|
||
|
ECOM_PAYMENT_CARD_NAME
|
||
|
ECOM_PAYMENT_CARD_VERIFICATION
|
||
|
ECOM_SHIPMETHOD
|
||
|
ECOM_SHIPMETHODDETAILS
|
||
|
ECOM_SHIPMETHODSPEED
|
||
|
ECOM_SHIPMETHODTYPE
|
||
|
ECOM_SHIPTO_COMPANY
|
||
|
ECOM_SHIPTO_DOB
|
||
|
ECOM_SHIPTO_ONLINE_EMAIL
|
||
|
ECOM_SHIPTO_POSTAL_CITY
|
||
|
ECOM_SHIPTO_POSTAL_COUNTRYCODE
|
||
|
ECOM_SHIPTO_POSTAL_COUNTY
|
||
|
ECOM_SHIPTO_POSTAL_NAME_FIRST
|
||
|
ECOM_SHIPTO_POSTAL_NAME_LAST
|
||
|
ECOM_SHIPTO_POSTAL_NAME_PREFIX
|
||
|
ECOM_SHIPTO_POSTAL_POSTALCODE
|
||
|
ECOM_SHIPTO_POSTAL_STATE
|
||
|
ECOM_SHIPTO_POSTAL_STREET_LINE1
|
||
|
ECOM_SHIPTO_POSTAL_STREET_LINE2
|
||
|
ECOM_SHIPTO_POSTAL_STREET_NUMBER
|
||
|
ECOM_SHIPTO_TELECOM_FAX_NUMBER
|
||
|
ECOM_SHIPTO_TELECOM_MOBILE_NUMBER
|
||
|
ECOM_SHIPTO_TELECOM_PHONE_NUMBER
|
||
|
ECOM_SHIPTO_TVA
|
||
|
ED
|
||
|
EMAIL
|
||
|
EXCEPTIONURL
|
||
|
EXCLPMLIST
|
||
|
EXECUTIONDATE*XX*
|
||
|
FACEXCL*XX*
|
||
|
FACTOTAL*XX*
|
||
|
FIRSTCALL
|
||
|
FLAG3D
|
||
|
FONTTYPE
|
||
|
FORCECODE1
|
||
|
FORCECODE2
|
||
|
FORCECODEHASH
|
||
|
FORCEPROCESS
|
||
|
FORCETP
|
||
|
FP_ACTIV
|
||
|
GENERIC_BL
|
||
|
GIROPAY_ACCOUNT_NUMBER
|
||
|
GIROPAY_BLZ
|
||
|
GIROPAY_OWNER_NAME
|
||
|
GLOBORDERID
|
||
|
GUID
|
||
|
HDFONTTYPE
|
||
|
HDTBLBGCOLOR
|
||
|
HDTBLTXTCOLOR
|
||
|
HEIGHTFRAME
|
||
|
HOMEURL
|
||
|
HTTP_ACCEPT
|
||
|
HTTP_USER_AGENT
|
||
|
INCLUDE_BIN
|
||
|
INCLUDE_COUNTRIES
|
||
|
INITIAL_REC_TRN
|
||
|
INVDATE
|
||
|
INVDISCOUNT
|
||
|
INVLEVEL
|
||
|
INVORDERID
|
||
|
ISSUERID
|
||
|
IST_MOBILE
|
||
|
ITEM_COUNT
|
||
|
ITEMATTRIBUTES*XX*
|
||
|
ITEMCATEGORY*XX*
|
||
|
ITEMCOMMENTS*XX*
|
||
|
ITEMDESC*XX*
|
||
|
ITEMDISCOUNT*XX*
|
||
|
ITEMFDMPRODUCTCATEG*XX*
|
||
|
ITEMID*XX*
|
||
|
ITEMNAME*XX*
|
||
|
ITEMPRICE*XX*
|
||
|
ITEMQUANT*XX*
|
||
|
ITEMQUANTORIG*XX*
|
||
|
ITEMUNITOFMEASURE*XX*
|
||
|
ITEMVAT*XX*
|
||
|
ITEMVATCODE*XX*
|
||
|
ITEMWEIGHT*XX*
|
||
|
LANGUAGE
|
||
|
LEVEL1AUTHCPC
|
||
|
LIDEXCL*XX*
|
||
|
LIMITCLIENTSCRIPTUSAGE
|
||
|
LINE_REF
|
||
|
LINE_REF1
|
||
|
LINE_REF2
|
||
|
LINE_REF3
|
||
|
LINE_REF4
|
||
|
LINE_REF5
|
||
|
LINE_REF6
|
||
|
LIST_BIN
|
||
|
LIST_COUNTRIES
|
||
|
LOGO
|
||
|
MANDATEID
|
||
|
MAXITEMQUANT*XX*
|
||
|
MERCHANTID
|
||
|
MODE
|
||
|
MTIME
|
||
|
MVER
|
||
|
NETAMOUNT
|
||
|
OPERATION
|
||
|
ORDERID
|
||
|
ORDERSHIPCOST
|
||
|
ORDERSHIPMETH
|
||
|
ORDERSHIPTAX
|
||
|
ORDERSHIPTAXCODE
|
||
|
ORIG
|
||
|
OR_INVORDERID
|
||
|
OR_ORDERID
|
||
|
OWNERADDRESS
|
||
|
OWNERADDRESS2
|
||
|
OWNERCTY
|
||
|
OWNERTELNO
|
||
|
OWNERTELNO2
|
||
|
OWNERTOWN
|
||
|
OWNERZIP
|
||
|
PAIDAMOUNT
|
||
|
PARAMPLUS
|
||
|
PARAMVAR
|
||
|
PAYID
|
||
|
PAYMETHOD
|
||
|
PM
|
||
|
PMLIST
|
||
|
PMLISTPMLISTTYPE
|
||
|
PMLISTTYPE
|
||
|
PMLISTTYPEPMLIST
|
||
|
PMTYPE
|
||
|
POPUP
|
||
|
POST
|
||
|
PSPID
|
||
|
PSWD
|
||
|
RECIPIENTACCOUNTNUMBER
|
||
|
RECIPIENTDOB
|
||
|
RECIPIENTLASTNAME
|
||
|
RECIPIENTZIP
|
||
|
REF
|
||
|
REFER
|
||
|
REFID
|
||
|
REFKIND
|
||
|
REF_CUSTOMERID
|
||
|
REF_CUSTOMERREF
|
||
|
REGISTRED
|
||
|
REMOTE_ADDR
|
||
|
REQGENFIELDS
|
||
|
RNPOFFERT
|
||
|
RTIMEOUT
|
||
|
RTIMEOUTREQUESTEDTIMEOUT
|
||
|
SCORINGCLIENT
|
||
|
SEQUENCETYPE
|
||
|
SETT_BATCH
|
||
|
SID
|
||
|
SIGNDATE
|
||
|
STATUS_3D
|
||
|
SUBSCRIPTION_ID
|
||
|
SUB_AM
|
||
|
SUB_AMOUNT
|
||
|
SUB_COM
|
||
|
SUB_COMMENT
|
||
|
SUB_CUR
|
||
|
SUB_ENDDATE
|
||
|
SUB_ORDERID
|
||
|
SUB_PERIOD_MOMENT
|
||
|
SUB_PERIOD_MOMENT_M
|
||
|
SUB_PERIOD_MOMENT_WW
|
||
|
SUB_PERIOD_NUMBER
|
||
|
SUB_PERIOD_NUMBER_D
|
||
|
SUB_PERIOD_NUMBER_M
|
||
|
SUB_PERIOD_NUMBER_WW
|
||
|
SUB_PERIOD_UNIT
|
||
|
SUB_STARTDATE
|
||
|
SUB_STATUS
|
||
|
TAAL
|
||
|
TAXINCLUDED*XX*
|
||
|
TBLBGCOLOR
|
||
|
TBLTXTCOLOR
|
||
|
TID
|
||
|
TITLE
|
||
|
TOTALAMOUNT
|
||
|
TP
|
||
|
TRACK2
|
||
|
TXTBADDR2
|
||
|
TXTCOLOR
|
||
|
TXTOKEN
|
||
|
TXTOKENTXTOKENPAYPAL
|
||
|
TXSHIPPING
|
||
|
TXSHIPPINGLOCATIONPROFILE
|
||
|
TXURL
|
||
|
TXVERIFIER
|
||
|
TYPE_COUNTRY
|
||
|
UCAF_AUTHENTICATION_DATA
|
||
|
UCAF_PAYMENT_CARD_CVC2
|
||
|
UCAF_PAYMENT_CARD_EXPDATE_MONTH
|
||
|
UCAF_PAYMENT_CARD_EXPDATE_YEAR
|
||
|
UCAF_PAYMENT_CARD_NUMBER
|
||
|
USERID
|
||
|
USERTYPE
|
||
|
VERSION
|
||
|
WBTU_MSISDN
|
||
|
WBTU_ORDERID
|
||
|
WEIGHTUNIT
|
||
|
WIN3DS
|
||
|
WITHROOT
|
||
|
""".split()
|
||
|
|
||
|
SHA_OUT_PARAMS = """
|
||
|
AAVADDRESS
|
||
|
AAVCHECK
|
||
|
AAVMAIL
|
||
|
AAVNAME
|
||
|
AAVPHONE
|
||
|
AAVZIP
|
||
|
ACCEPTANCE
|
||
|
ALIAS
|
||
|
AMOUNT
|
||
|
BIC
|
||
|
BIN
|
||
|
BRAND
|
||
|
CARDNO
|
||
|
CCCTY
|
||
|
CN
|
||
|
COLLECTOR_BIC
|
||
|
COLLECTOR_IBAN
|
||
|
COMPLUS
|
||
|
CREATION_STATUS
|
||
|
CREDITDEBIT
|
||
|
CURRENCY
|
||
|
CVCCHECK
|
||
|
DCC_COMMPERCENTAGE
|
||
|
DCC_CONVAMOUNT
|
||
|
DCC_CONVCCY
|
||
|
DCC_EXCHRATE
|
||
|
DCC_EXCHRATESOURCE
|
||
|
DCC_EXCHRATETS
|
||
|
DCC_INDICATOR
|
||
|
DCC_MARGINPERCENTAGE
|
||
|
DCC_VALIDHOURS
|
||
|
DEVICEID
|
||
|
DIGESTCARDNO
|
||
|
ECI
|
||
|
ED
|
||
|
EMAIL
|
||
|
ENCCARDNO
|
||
|
FXAMOUNT
|
||
|
FXCURRENCY
|
||
|
IP
|
||
|
IPCTY
|
||
|
MANDATEID
|
||
|
MOBILEMODE
|
||
|
NBREMAILUSAGE
|
||
|
NBRIPUSAGE
|
||
|
NBRIPUSAGE_ALLTX
|
||
|
NBRUSAGE
|
||
|
NCERROR
|
||
|
ORDERID
|
||
|
PAYID
|
||
|
PAYMENT_REFERENCE
|
||
|
PM
|
||
|
SCO_CATEGORY
|
||
|
SCORING
|
||
|
SEQUENCETYPE
|
||
|
SIGNDATE
|
||
|
STATUS
|
||
|
SUBBRAND
|
||
|
SUBSCRIPTION_ID
|
||
|
TRXDATE
|
||
|
VC"""
|
||
|
|
||
|
class Payment(PaymentCommon):
|
||
|
# See http://payment-services.ingenico.com/fr/fr/ogone/support/guides/integration%20guides/e-commerce
|
||
|
description = {
|
||
|
'caption': N_('Système de paiement Ogone / Ingenico Payment System e-Commerce'),
|
||
|
'parameters': [
|
||
|
{'name': 'environment',
|
||
|
'default': ENVIRONMENT_TEST,
|
||
|
'caption': N_(u'Environnement'),
|
||
|
'choices': ENVIRONMENT,
|
||
|
},
|
||
|
{'name': 'pspid',
|
||
|
'caption': N_(u"Nom d'affiliation dans le système"),
|
||
|
'required': True,
|
||
|
},
|
||
|
{'name': 'language',
|
||
|
'caption': N_(u'Langage'),
|
||
|
'default': 'fr_FR',
|
||
|
'choices': (('fr_FR', N_('français')),),
|
||
|
},
|
||
|
{'name': 'hash_algorithm',
|
||
|
'caption': N_(u'Algorithme de hachage'),
|
||
|
'default': 'sha1',
|
||
|
},
|
||
|
{'name': 'sha_in',
|
||
|
'caption': N_(u'Clé SHA-IN'),
|
||
|
'required': True,
|
||
|
},
|
||
|
{'name': 'sha_out',
|
||
|
'caption': N_(u'Clé SHA-OUT'),
|
||
|
'required': True,
|
||
|
},
|
||
|
{'name': 'currency',
|
||
|
'caption': N_(u'Monnaie'),
|
||
|
'default': 'EUR',
|
||
|
'choices': ('EUR',),
|
||
|
},
|
||
|
{'name': 'accepturl',
|
||
|
'caption': N_(u'Monnaie'),
|
||
|
'default': 'EUR',
|
||
|
'choices': ('EUR',),
|
||
|
},
|
||
|
]
|
||
|
}
|
||
|
|
||
|
def sha_sign(self, algo, key, params, keep):
|
||
|
'''Ogone signature algorithm of query string'''
|
||
|
values = params.items()
|
||
|
values = [(a.upper(), b) for a, b in values]
|
||
|
values = sorted(values)
|
||
|
values = ['%s=%s' % (a, b) for a, b in values if a in keep]
|
||
|
tosign = key.join(values)
|
||
|
tosign += key
|
||
|
hashing = getattr(hashlib, algo)
|
||
|
return hashing(tosign).hexdigest().upper()
|
||
|
|
||
|
def sha_sign_in(self, params):
|
||
|
return self.sha_sign(self.hash_algorithm, self.sha_in, params, SHA_IN_PARAMS)
|
||
|
|
||
|
def sha_sign_out(self, params):
|
||
|
return self.sha_sign(self.hash_algorithm, self.sha_out, params, SHA_OUT_PARAMS)
|
||
|
|
||
|
def get_request_url(self):
|
||
|
if self.environment == ENVIRONMENT_TEST:
|
||
|
return ENVIRONMENT_TEST_URL
|
||
|
if self.environment == ENVIRONMENT_PROD:
|
||
|
return ENVIRONMENT_PROD_URL
|
||
|
raise NotImplementedError('unknown environment %s' % self.environment)
|
||
|
|
||
|
def request(self, amount, orderid=None, name=None, email=None,
|
||
|
language=None, description=None, **kwargs):
|
||
|
reference = orderid or self.transaction_id(20, string.digits + string.ascii_letters)
|
||
|
language = language or self.language
|
||
|
# convertir en centimes
|
||
|
amount = Decimal(amount) * 100
|
||
|
# arrondi comptable francais
|
||
|
amount = amount.quantize(Decimal('1.'), rounding=ROUND_HALF_UP)
|
||
|
params = {
|
||
|
'AMOUNT': amount,
|
||
|
'ORDERID': reference,
|
||
|
'PSPID': self.pspid,
|
||
|
'LANGUAGE': language,
|
||
|
'CURRENCY': self.currency,
|
||
|
}
|
||
|
if name:
|
||
|
params['CN'] = name
|
||
|
if email:
|
||
|
params['EMAIL'] = email
|
||
|
if description:
|
||
|
params['COM'] = description
|
||
|
for key, value in kwargs.iteritems():
|
||
|
params[key.upper()] = value
|
||
|
# uniformize all values to UTF-8 string
|
||
|
for key in params:
|
||
|
params[key] = unicode(params[key]).encode('utf-8')
|
||
|
params['SHASIGN'] = self.sha_sign_in(params)
|
||
|
url = self.get_request_url()
|
||
|
form = Form(
|
||
|
url=url,
|
||
|
method='POST',
|
||
|
fields=[{'type': 'hidden',
|
||
|
'name': key,
|
||
|
'value': params[key]} for key in params])
|
||
|
return reference, FORM, form
|
||
|
|
||
|
def response(self, query_string):
|
||
|
params = urlparse.parse_qs(query_string, True)
|
||
|
params = {key.upper(): params[key][0] for key in params}
|
||
|
reference = params['ORDERID']
|
||
|
transaction_id = params['PAYID']
|
||
|
status = params['STATUS']
|
||
|
error = params['NCERROR']
|
||
|
signed = False
|
||
|
if self.sha_in:
|
||
|
signature = params.get('SHASIGN')
|
||
|
expected_signature = self.sha_sign_out(params)
|
||
|
signed = signature == expected_signature
|
||
|
print 'signed', signature
|
||
|
print 'expected', expected_signature
|
||
|
if status == '1':
|
||
|
result = CANCELED
|
||
|
elif status == '2':
|
||
|
result = DENIED
|
||
|
elif status == '5':
|
||
|
result = ACCEPTED
|
||
|
elif status == '9':
|
||
|
result = PAID
|
||
|
else:
|
||
|
self.logger.error('response STATUS=%s NCERROR=%s NCERRORPLUS=%s',
|
||
|
status, error, params.get('NCERRORPLUS', ''))
|
||
|
result = ERROR
|
||
|
return PaymentResponse(
|
||
|
result=result,
|
||
|
signed=signed,
|
||
|
bank_data=params,
|
||
|
order_id=reference,
|
||
|
transaction_id=transaction_id)
|