'depends': ['decimal_precision', 'mail'],
'data': [
'views/payment_acquirer_views.xml',
- 'views/ogone.xml',
- 'views/paypal.xml',
'data/payment_acquirer_data.xml',
- 'data/ogone.xml',
- 'data/paypal.xml',
'security/ir.model.access.csv',
],
'installable': True,
##############################################################################
from openerp.addons.web import http
-from openerp.addons.web.http import request
-# from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
-from openerp.addons.website.models import website
import logging
-import requests
-from urllib import urlencode
_logger = logging.getLogger(__name__)
-class PaypalController(http.Controller):
- _notify_url = '/payment/paypal/ipn/'
- _return_url = '/payment/paypal/dpn/'
- _cancel_url = '/payment/paypal/cancel/'
- # _ipn_url2 = '/payment/paypal/<int:acquirer_id>/ipn/'
-
- @website.route('/payment/paypal/<int:acquirer_id>/ipn/', type='http', auth='admin')
- def paypal_ipn(self, **post):
- print 'Entering paypal_ipn with post', post
- # step 1: return an empty HTTP 200 response -> will be done at the end by returning ''
-
- # step 2: POST the complete, unaltered message back to Paypal (preceded by cmd=_notify-validate), with same encoding
- paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"
- post_url = '%s?cmd=_notify-validate&%s' % (paypal_url, urlencode(post))
- resp = requests.post(post_url)
- print '\tReceived response', resp, resp.text
-
- # step 3: paypal send either VERIFIED or INVALID (single word)
- if resp.text == 'VERIFIED':
- # _logger.warning('')
- cr, uid, context = request.cr, request.uid, request.context
- # payment_transaction = request.registry['payment.transaction']
- # payment_transaction.validate()
- elif resp.text == 'INVALID':
- # _logger.warning('')
- pass
- else:
- # _logger.warning('') -> something went wrong
- pass
-
- return ''
-
- @website.route([
- '/payment/paypal/test/dpn',
- ], type='http', auth="public")
- def paypal_test_success(self, **post):
- """ TODO
- """
- cr, uid, context = request.cr, request.uid, request.context
- print post
- return ''
-
-
-class OgoneController(http.Controller):
- _accept_url = '/payment/ogone/test/accept'
- _decline_url = '/payment/ogone/test/decline'
- _exception_url = '/payment/ogone/test/exception'
- _cancel_url = '/payment/ogone/test/cancel'
-
- @website.route([
- '/payment/ogone/feedback', '/payment/ogone/test/accept',
- '/payment/ogone/decline', '/payment/ogone/test/decline',
- '/payment/ogone/exception', '/payment/ogone/test/exception',
- '/payment/ogone/cancel', '/payment/ogone/test/cancel',
- ], type='http', auth='admin')
- def feedback(self, **post):
- cr, uid, context = request.cr, request.uid, request.context
- Payment = request.registry['payment.transaction']
- print 'Entering ogone feedback with', post
-
- res = Payment.tx_ogone_feedback(cr, uid, post, context)
- print res
- return ''
+class PaymentController(http.Controller):
+ pass
+++ /dev/null
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
-import ogone
+++ /dev/null
-# -*- coding: utf-8 -*-
-
-OGONE_ERROR_MAP = {
- '0020001001': "Authorization failed, please retry",
- '0020001002': "Authorization failed, please retry",
- '0020001003': "Authorization failed, please retry",
- '0020001004': "Authorization failed, please retry",
- '0020001005': "Authorization failed, please retry",
- '0020001006': "Authorization failed, please retry",
- '0020001007': "Authorization failed, please retry",
- '0020001008': "Authorization failed, please retry",
- '0020001009': "Authorization failed, please retry",
- '0020001010': "Authorization failed, please retry",
- '0030001999': "Our payment system is currently under maintenance, please try later",
- '0050001005': "Expiry date error",
- '0050001007': "Requested Operation code not allowed",
- '0050001008': "Invalid delay value",
- '0050001010': "Input date in invalid format",
- '0050001013': "Unable to parse socket input stream",
- '0050001014': "Error in parsing stream content",
- '0050001015': "Currency error",
- '0050001016': "Transaction still posted at end of wait",
- '0050001017': "Sync value not compatible with delay value",
- '0050001019': "Transaction duplicate of a pre-existing transaction",
- '0050001020': "Acceptation code empty while required for the transaction",
- '0050001024': "Maintenance acquirer differs from original transaction acquirer",
- '0050001025': "Maintenance merchant differs from original transaction merchant",
- '0050001028': "Maintenance operation not accurate for the original transaction",
- '0050001031': "Host application unknown for the transaction",
- '0050001032': "Unable to perform requested operation with requested currency",
- '0050001033': "Maintenance card number differs from original transaction card number",
- '0050001034': "Operation code not allowed",
- '0050001035': "Exception occurred in socket input stream treatment",
- '0050001036': "Card length does not correspond to an acceptable value for the brand",
- '0050001036': "Card length does not correspond to an acceptable value for the brand",
- '0050001068': "A technical problem occurred, please contact helpdesk",
- '0050001069': "Invalid check for CardID and Brand",
- '0050001070': "A technical problem occurred, please contact helpdesk",
- '0050001116': "Unknown origin IP",
- '0050001117': "No origin IP detected",
- '0050001118': "Merchant configuration problem, please contact support",
- '10001001': "Communication failure",
- '10001002': "Communication failure",
- '10001003': "Communication failure",
- '10001004': "Communication failure",
- '10001005': "Communication failure",
- '20001001': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001002': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001003': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001004': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001005': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001006': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001007': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001008': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001009': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001010': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001101': "A technical problem occurred, please contact helpdesk",
- '20001105': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
- '20001111': "A technical problem occurred, please contact helpdesk",
- '20002001': "Origin for the response of the bank can not be checked",
- '20002002': "Beneficiary account number has been modified during processing",
- '20002003': "Amount has been modified during processing",
- '20002004': "Currency has been modified during processing",
- '20002005': "No feedback from the bank server has been detected",
- '30001001': "Payment refused by the acquirer",
- '30001002': "Duplicate request",
- '30001010': "A technical problem occurred, please contact helpdesk",
- '30001011': "A technical problem occurred, please contact helpdesk",
- '30001012': "Card black listed - Contact acquirer",
- '30001015': "Your merchant's acquirer is temporarily unavailable, please try later or choose another payment method.",
- '30001051': "A technical problem occurred, please contact helpdesk",
- '30001054': "A technical problem occurred, please contact helpdesk",
- '30001057': "Your merchant's acquirer is temporarily unavailable, please try later or choose another payment method.",
- '30001058': "Your merchant's acquirer is temporarily unavailable, please try later or choose another payment method.",
- '30001060': "Aquirer indicates that a failure occured during payment processing",
- '30001070': "RATEPAY Invalid Response Type (Failure)",
- '30001071': "RATEPAY Missing Mandatory status code field (failure)",
- '30001072': "RATEPAY Missing Mandatory Result code field (failure)",
- '30001073': "RATEPAY Response parsing Failed",
- '30001090': "CVC check required by front end and returned invalid by acquirer",
- '30001091': "ZIP check required by front end and returned invalid by acquirer",
- '30001092': "Address check required by front end and returned as invalid by acquirer.",
- '30001100': "Unauthorized buyer's country",
- '30001101': "IP country <> card country",
- '30001102': "Number of different countries too high",
- '30001103': "unauthorized card country",
- '30001104': "unauthorized ip address country",
- '30001105': "Anonymous proxy",
- '30001110': "If the problem persists, please contact Support, or go to paysafecard's card balance page (https://customer.cc.at.paysafecard.com/psccustomer/GetWelcomePanelServlet?language=en) to see when the amount reserved on your card will be available again.",
- '30001120': "IP address in merchant's black list",
- '30001130': "BIN in merchant's black list",
- '30001131': "Wrong BIN for 3xCB",
- '30001140': "Card in merchant's card blacklist",
- '30001141': "Email in blacklist",
- '30001142': "Passenger name in blacklist",
- '30001143': "Card holder name in blacklist",
- '30001144': "Passenger name different from owner name",
- '30001145': "Time to departure too short",
- '30001149': "Card Configured in Card Supplier Limit for another relation (CSL)",
- '30001150': "Card not configured in the system for this customer (CSL)",
- '30001151': "REF1 not allowed for this relationship (Contract number",
- '30001152': "Card/Supplier Amount limit reached (CSL)",
- '30001153': "Card not allowed for this supplier (Date out of contract bounds)",
- '30001154': "You have reached the usage limit allowed",
- '30001155': "You have reached the usage limit allowed",
- '30001156': "You have reached the usage limit allowed",
- '30001157': "Unauthorized IP country for itinerary",
- '30001158': "email usage limit reached",
- '30001159': "Unauthorized card country/IP country combination",
- '30001160': "Postcode in highrisk group",
- '30001161': "generic blacklist match",
- '30001162': "Billing Address is a PO Box",
- '30001180': "maximum scoring reached",
- '30001997': "Authorization canceled by simulation",
- '30001998': "A technical problem occurred, please try again.",
- '30001999': "Your merchant's acquirer is temporarily unavailable, please try later or choose another payment method.",
- '30002001': "Payment refused by the financial institution",
- '30002001': "Payment refused by the financial institution",
- '30021001': "Call acquirer support call number.",
- '30022001': "Payment must be approved by the acquirer before execution.",
- '30031001': "Invalid merchant number.",
- '30041001': "Retain card.",
- '30051001': "Authorization declined",
- '30071001': "Retain card - special conditions.",
- '30121001': "Invalid transaction",
- '30131001': "Invalid amount",
- '30131002': "You have reached the total amount allowed",
- '30141001': "Invalid card number",
- '30151001': "Unknown acquiring institution.",
- '30171001': "Payment method cancelled by the buyer",
- '30171002': "The maximum time allowed is elapsed.",
- '30191001': "Try again later.",
- '30201001': "A technical problem occurred, please contact helpdesk",
- '30301001': "Invalid format",
- '30311001': "Unknown acquirer ID.",
- '30331001': "Card expired.",
- '30341001': "Suspicion of fraud.",
- '30341002': "Suspicion of fraud (3rdMan)",
- '30341003': "Suspicion of fraud (Perseuss)",
- '30341004': "Suspicion of fraud (ETHOCA)",
- '30381001': "A technical problem occurred, please contact helpdesk",
- '30401001': "Invalid function.",
- '30411001': "Lost card.",
- '30431001': "Stolen card, pick up",
- '30511001': "Insufficient funds.",
- '30521001': "No Authorization. Contact the issuer of your card.",
- '30541001': "Card expired.",
- '30551001': "Invalid PIN.",
- '30561001': "Card not in authorizer's database.",
- '30571001': "Transaction not permitted on card.",
- '30581001': "Transaction not allowed on this terminal",
- '30591001': "Suspicion of fraud.",
- '30601001': "The merchant must contact the acquirer.",
- '30611001': "Amount exceeds card ceiling.",
- '30621001': "Restricted card.",
- '30631001': "Security policy not respected.",
- '30641001': "Amount changed from ref. trn.",
- '30681001': "Tardy response.",
- '30751001': "PIN entered incorrectly too often",
- '30761001': "Card holder already contesting.",
- '30771001': "PIN entry required.",
- '30811001': "Message flow error.",
- '30821001': "Authorization center unavailable",
- '30831001': "Authorization center unavailable",
- '30901001': "Temporary system shutdown.",
- '30911001': "Acquirer unavailable.",
- '30921001': "Invalid card type for acquirer.",
- '30941001': "Duplicate transaction",
- '30961001': "Processing temporarily not possible",
- '30971001': "A technical problem occurred, please contact helpdesk",
- '30981001': "A technical problem occurred, please contact helpdesk",
- '31011001': "Unknown acceptance code",
- '31021001': "Invalid currency",
- '31031001': "Acceptance code missing",
- '31041001': "Inactive card",
- '31051001': "Merchant not active",
- '31061001': "Invalid expiration date",
- '31071001': "Interrupted host communication",
- '31081001': "Card refused",
- '31091001': "Invalid password",
- '31101001': "Plafond transaction (majoré du bonus) dépassé",
- '31111001': "Plafond mensuel (majoré du bonus) dépassé",
- '31121001': "Plafond centre de facturation dépassé",
- '31131001': "Plafond entreprise dépassé",
- '31141001': "Code MCC du fournisseur non autorisé pour la carte",
- '31151001': "Numéro SIRET du fournisseur non autorisé pour la carte",
- '31161001': "This is not a valid online banking account",
- '32001004': "A technical problem occurred, please try again.",
- '34011001': "Bezahlung mit RatePAY nicht möglich.",
- '39991001': "A technical problem occurred, please contact the helpdesk of your acquirer",
- '40001001': "A technical problem occurred, please try again.",
- '40001002': "A technical problem occurred, please try again.",
- '40001003': "A technical problem occurred, please try again.",
- '40001004': "A technical problem occurred, please try again.",
- '40001005': "A technical problem occurred, please try again.",
- '40001006': "A technical problem occurred, please try again.",
- '40001007': "A technical problem occurred, please try again.",
- '40001008': "A technical problem occurred, please try again.",
- '40001009': "A technical problem occurred, please try again.",
- '40001010': "A technical problem occurred, please try again.",
- '40001011': "A technical problem occurred, please contact helpdesk",
- '40001012': "Your merchant's acquirer is temporarily unavailable, please try later or choose another payment method.",
- '40001013': "A technical problem occurred, please contact helpdesk",
- '40001016': "A technical problem occurred, please contact helpdesk",
- '40001018': "A technical problem occurred, please try again.",
- '40001019': "Sorry, an error occurred during processing. Please retry the operation (use back button of the browser). If problem persists, contact your merchant's helpdesk.",
- '40001020': "Sorry, an error occurred during processing. Please retry the operation (use back button of the browser). If problem persists, contact your merchant's helpdesk.",
- '40001050': "A technical problem occurred, please contact helpdesk",
- '40001133': "Authentication failed, the signature of your bank access control server is incorrect",
- '40001134': "Authentication failed, please retry or cancel.",
- '40001135': "Authentication temporary unavailable, please retry or cancel.",
- '40001136': "Technical problem with your browser, please retry or cancel",
- '40001137': "Your bank access control server is temporary unavailable, please retry or cancel",
- '40001998': "Temporary technical problem. Please retry a little bit later.",
- '50001001': "Unknown card type",
- '50001002': "Card number format check failed for given card number.",
- '50001003': "Merchant data error",
- '50001004': "Merchant identification missing",
- '50001005': "Expiry date error",
- '50001006': "Amount is not a number",
- '50001007': "A technical problem occurred, please contact helpdesk",
- '50001008': "A technical problem occurred, please contact helpdesk",
- '50001009': "A technical problem occurred, please contact helpdesk",
- '50001010': "A technical problem occurred, please contact helpdesk",
- '50001011': "Brand not supported for that merchant",
- '50001012': "A technical problem occurred, please contact helpdesk",
- '50001013': "A technical problem occurred, please contact helpdesk",
- '50001014': "A technical problem occurred, please contact helpdesk",
- '50001015': "Invalid currency code",
- '50001016': "A technical problem occurred, please contact helpdesk",
- '50001017': "A technical problem occurred, please contact helpdesk",
- '50001018': "A technical problem occurred, please contact helpdesk",
- '50001019': "A technical problem occurred, please contact helpdesk",
- '50001020': "A technical problem occurred, please contact helpdesk",
- '50001021': "A technical problem occurred, please contact helpdesk",
- '50001022': "A technical problem occurred, please contact helpdesk",
- '50001023': "A technical problem occurred, please contact helpdesk",
- '50001024': "A technical problem occurred, please contact helpdesk",
- '50001025': "A technical problem occurred, please contact helpdesk",
- '50001026': "A technical problem occurred, please contact helpdesk",
- '50001027': "A technical problem occurred, please contact helpdesk",
- '50001028': "A technical problem occurred, please contact helpdesk",
- '50001029': "A technical problem occurred, please contact helpdesk",
- '50001030': "A technical problem occurred, please contact helpdesk",
- '50001031': "A technical problem occurred, please contact helpdesk",
- '50001032': "A technical problem occurred, please contact helpdesk",
- '50001033': "A technical problem occurred, please contact helpdesk",
- '50001034': "A technical problem occurred, please contact helpdesk",
- '50001035': "A technical problem occurred, please contact helpdesk",
- '50001036': "Card length does not correspond to an acceptable value for the brand",
- '50001037': "Purchasing card number for a regular merchant",
- '50001038': "Non Purchasing card for a Purchasing card merchant",
- '50001039': "Details sent for a non-Purchasing card merchant, please contact helpdesk",
- '50001040': "Details not sent for a Purchasing card transaction, please contact helpdesk",
- '50001041': "Payment detail validation failed",
- '50001042': "Given transactions amounts (tax,discount,shipping,net,etc…) do not compute correctly together",
- '50001043': "A technical problem occurred, please contact helpdesk",
- '50001044': "No acquirer configured for this operation",
- '50001045': "No UID configured for this operation",
- '50001046': "Operation not allowed for the merchant",
- '50001047': "A technical problem occurred, please contact helpdesk",
- '50001048': "A technical problem occurred, please contact helpdesk",
- '50001049': "A technical problem occurred, please contact helpdesk",
- '50001050': "A technical problem occurred, please contact helpdesk",
- '50001051': "A technical problem occurred, please contact helpdesk",
- '50001052': "A technical problem occurred, please contact helpdesk",
- '50001053': "A technical problem occurred, please contact helpdesk",
- '50001054': "Card number incorrect or incompatible",
- '50001055': "A technical problem occurred, please contact helpdesk",
- '50001056': "A technical problem occurred, please contact helpdesk",
- '50001057': "A technical problem occurred, please contact helpdesk",
- '50001058': "A technical problem occurred, please contact helpdesk",
- '50001059': "A technical problem occurred, please contact helpdesk",
- '50001060': "A technical problem occurred, please contact helpdesk",
- '50001061': "A technical problem occurred, please contact helpdesk",
- '50001062': "A technical problem occurred, please contact helpdesk",
- '50001063': "Card Issue Number does not correspond to range or not present",
- '50001064': "Start Date not valid or not present",
- '50001066': "Format of CVC code invalid",
- '50001067': "The merchant is not enrolled for 3D-Secure",
- '50001068': "The card number or account number (PAN) is invalid",
- '50001069': "Invalid check for CardID and Brand",
- '50001070': "The ECI value given is either not supported, or in conflict with other data in the transaction",
- '50001071': "Incomplete TRN demat",
- '50001072': "Incomplete PAY demat",
- '50001073': "No demat APP",
- '50001074': "Authorisation too old",
- '50001075': "VERRes was an error message",
- '50001076': "DCP amount greater than authorisation amount",
- '50001077': "Details negative amount",
- '50001078': "Details negative quantity",
- '50001079': "Could not decode/decompress received PARes (3D-Secure)",
- '50001080': "Received PARes was an erereor message from ACS (3D-Secure)",
- '50001081': "Received PARes format was invalid according to the 3DS specifications (3D-Secure)",
- '50001082': "PAReq/PARes reconciliation failure (3D-Secure)",
- '50001084': "Maximum amount reached",
- '50001087': "The transaction type requires authentication, please check with your bank.",
- '50001090': "CVC missing at input, but CVC check asked",
- '50001091': "ZIP missing at input, but ZIP check asked",
- '50001092': "Address missing at input, but Address check asked",
- '50001095': "Invalid date of birth",
- '50001096': "Invalid commodity code",
- '50001097': "The requested currency and brand are incompatible.",
- '50001111': "Data validation error",
- '50001113': "This order has already been processed",
- '50001114': "Error pre-payment check page access",
- '50001115': "Request not received in secure mode",
- '50001116': "Unknown IP address origin",
- '50001117': "NO IP address origin",
- '50001118': "Pspid not found or not correct",
- '50001119': "Password incorrect or disabled due to numbers of errors",
- '50001120': "Invalid currency",
- '50001121': "Invalid number of decimals for the currency",
- '50001122': "Currency not accepted by the merchant",
- '50001123': "Card type not active",
- '50001124': "Number of lines don't match with number of payments",
- '50001125': "Format validation error",
- '50001126': "Overflow in data capture requests for the original order",
- '50001127': "The original order is not in a correct status",
- '50001128': "missing authorization code for unauthorized order",
- '50001129': "Overflow in refunds requests",
- '50001130': "Error access to original order",
- '50001131': "Error access to original history item",
- '50001132': "The Selected Catalog is empty",
- '50001133': "Duplicate request",
- '50001134': "Authentication failed, please retry or cancel.",
- '50001135': "Authentication temporary unavailable, please retry or cancel.",
- '50001136': "Technical problem with your browser, please retry or cancel",
- '50001137': "Your bank access control server is temporary unavailable, please retry or cancel",
- '50001150': "Fraud Detection, Technical error (IP not valid)",
- '50001151': "Fraud detection : technical error (IPCTY unknown or error)",
- '50001152': "Fraud detection : technical error (CCCTY unknown or error)",
- '50001153': "Overflow in redo-authorisation requests",
- '50001170': "Dynamic BIN check failed",
- '50001171': "Dynamic country check failed",
- '50001172': "Error in Amadeus signature",
- '50001174': "Card Holder Name is too long",
- '50001175': "Name contains invalid characters",
- '50001176': "Card number is too long",
- '50001177': "Card number contains non-numeric info",
- '50001178': "Card Number Empty",
- '50001179': "CVC too long",
- '50001180': "CVC contains non-numeric info",
- '50001181': "Expiration date contains non-numeric info",
- '50001182': "Invalid expiration month",
- '50001183': "Expiration date must be in the future",
- '50001184': "SHA Mismatch",
- '50001205': "Missing mandatory fields for billing address.",
- '50001206': "Missing mandatory field date of birth.",
- '50001207': "Missing required shopping basket details.",
- '50001208': "Missing social security number",
- '50001209': "Invalid country code",
- '50001210': "Missing yearly salary",
- '50001211': "Missing gender",
- '50001212': "Missing email",
- '50001213': "Missing IP address",
- '50001214': "Missing part payment campaign ID",
- '50001215': "Missing invoice number",
- '50001216': "The alias must be different than the card number",
- '60000001': "account number unknown",
- '60000003': "not credited dd-mm-yy",
- '60000005': "name/number do not correspond",
- '60000007': "account number blocked",
- '60000008': "specific direct debit block",
- '60000009': "account number WKA",
- '60000010': "administrative reason",
- '60000011': "account number expired",
- '60000012': "no direct debit authorisation given",
- '60000013': "debit not approved",
- '60000014': "double payment",
- '60000018': "name/address/city not entered",
- '60001001': "no original direct debit for revocation",
- '60001002': "payer’s account number format error",
- '60001004': "payer’s account at different bank",
- '60001005': "payee’s account at different bank",
- '60001006': "payee’s account number format error",
- '60001007': "payer’s account number blocked",
- '60001008': "payer’s account number expired",
- '60001009': "payee’s account number expired",
- '60001010': "direct debit not possible",
- '60001011': "creditor payment not possible",
- '60001012': "payer’s account number unknown WKA-number",
- '60001013': "payee’s account number unknown WKA-number",
- '60001014': "impermissible WKA transaction",
- '60001015': "period for revocation expired",
- '60001017': "reason for revocation not correct",
- '60001018': "original run number not numeric",
- '60001019': "payment ID incorrect",
- '60001020': "amount not numeric",
- '60001021': "amount zero not permitted",
- '60001022': "negative amount not permitted",
- '60001023': "payer and payee giro account number",
- '60001025': "processing code (verwerkingscode) incorrect",
- '60001028': "revocation not permitted",
- '60001029': "guaranteed direct debit on giro account number",
- '60001030': "NBC transaction type incorrect",
- '60001031': "description too large",
- '60001032': "book account number not issued",
- '60001034': "book account number incorrect",
- '60001035': "payer’s account number not numeric",
- '60001036': "payer’s account number not eleven-proof",
- '60001037': "payer’s account number not issued",
- '60001039': "payer’s account number of DNB/BGC/BLA",
- '60001040': "payee’s account number not numeric",
- '60001041': "payee’s account number not eleven-proof",
- '60001042': "payee’s account number not issued",
- '60001044': "payee’s account number unknown",
- '60001050': "payee’s name missing",
- '60001051': "indicate payee’s bank account number instead of 3102",
- '60001052': "no direct debit contract",
- '60001053': "amount beyond bounds",
- '60001054': "selective direct debit block",
- '60001055': "original run number unknown",
- '60001057': "payer’s name missing",
- '60001058': "payee’s account number missing",
- '60001059': "restore not permitted",
- '60001060': "bank’s reference (navraaggegeven) missing",
- '60001061': "BEC/GBK number incorrect",
- '60001062': "BEC/GBK code incorrect",
- '60001087': "book account number not numeric",
- '60001090': "cancelled on request",
- '60001091': "cancellation order executed",
- '60001092': "cancelled instead of bended",
- '60001093': "book account number is a shortened account number",
- '60001094': "instructing party account number not identical with payer",
- '60001095': "payee unknown GBK acceptor",
- '60001097': "instructing party account number not identical with payee",
- '60001099': "clearing not permitted",
- '60001101': "payer’s account number not spaces",
- '60001102': "PAN length not numeric",
- '60001103': "PAN length outside limits",
- '60001104': "track number not numeric",
- '60001105': "track number not valid",
- '60001106': "PAN sequence number not numeric",
- '60001107': "domestic PAN not numeric",
- '60001108': "domestic PAN not eleven-proof",
- '60001109': "domestic PAN not issued",
- '60001110': "foreign PAN not numeric",
- '60001111': "card valid date not numeric",
- '60001112': "book period number (boekperiodenr) not numeric",
- '60001113': "transaction number not numeric",
- '60001114': "transaction time not numeric",
- '60001115': "transaction no valid time",
- '60001116': "transaction date not numeric",
- '60001117': "transaction no valid date",
- '60001118': "STAN not numeric",
- '60001119': "instructing party’s name missing",
- '60001120': "foreign amount (bedrag-vv) not numeric",
- '60001122': "rate (verrekenkoers) not numeric",
- '60001125': "number of decimals (aantaldecimalen) incorrect",
- '60001126': "tariff (tarifering) not B/O/S",
- '60001127': "domestic costs (kostenbinnenland) not numeric",
- '60001128': "domestic costs (kostenbinnenland) not higher than zero",
- '60001129': "foreign costs (kostenbuitenland) not numeric",
- '60001130': "foreign costs (kostenbuitenland) not higher than zero",
- '60001131': "domestic costs (kostenbinnenland) not zero",
- '60001132': "foreign costs (kostenbuitenland) not zero",
- '60001134': "Euro record not fully filled in",
- '60001135': "Client currency incorrect",
- '60001136': "Amount NLG not numeric",
- '60001137': "Amount NLG not higher than zero",
- '60001138': "Amount NLG not equal to Amount",
- '60001139': "Amount NLG incorrectly converted",
- '60001140': "Amount EUR not numeric",
- '60001141': "Amount EUR not greater than zero",
- '60001142': "Amount EUR not equal to Amount",
- '60001143': "Amount EUR incorrectly converted",
- '60001144': "Client currency not NLG",
- '60001145': "rate euro-vv (Koerseuro-vv) not numeric",
- '60001146': "comma rate euro-vv (Kommakoerseuro-vv) incorrect",
- '60001147': "acceptgiro distributor not valid",
- '60001148': "Original run number and/or BRN are missing",
- '60001149': "Amount/Account number/ BRN different",
- '60001150': "Direct debit already revoked/restored",
- '60001151': "Direct debit already reversed/revoked/restored",
- '60001153': "Payer’s account number not known",
-}
-
-DATA_VALIDATION_ERROR = '50001111'
-
-
-def retryable(error):
- return error in [
- '0020001001', '0020001002', '0020001003', '0020001004', '0020001005',
- '0020001006', '0020001007', '0020001008', '0020001009', '0020001010',
- '30001010', '30001011', '30001015',
- '30001057', '30001058',
- '30001998', '30001999',
- #'30611001', # amount exceeds card limit
- '30961001',
- '40001001', '40001002', '40001003', '40001004', '40001005',
- '40001006', '40001007', '40001008', '40001009', '40001010',
- '40001012',
- '40001018', '40001019', '40001020',
- '40001134', '40001135', '40001136', '40001137',
- #'50001174', # cardholder name too long
- ]
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<openerp>
- <data noupdate="0">
-
- <record id="payment_acquirer_ogone" model="payment.acquirer">
- <field name="name">ogone</field>
- <field name="view_template_id" ref="ogone_acquirer_button"/>
- <field name="env">test</field>
- <field name='ogone_pspid'>pinky</field>
- <field name='ogone_userid'>OOAPI</field>
- <field name='ogone_password'>R!ci/6Nu8a</field>
- <field name="ogone_shakey_in">tINY4Yv14789gUix1130</field>
- <field name="ogone_shakey_out">tINYj885Tfvd4P471464</field>
- </record>
-
- </data>
-</openerp>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<openerp>
- <data noupdate="0">
-
- <record id="payment_acquirer_paypal" model="payment.acquirer">
- <field name="name">paypal</field>
- <field name="view_template_id" ref="paypal_acquirer_button"/>
- <field name="env">test</field>
- <field name="paypal_tx_url">https://www.sandbox.paypal.com/cgi-bin/webscr</field>
- <field name="paypal_email_id">tde+paypal-facilitator@openerp.com</field>
- <field name="paypal_username">'tde+paypal-facilitator_api1.openerp.com</field>
- </record>
-
- </data>
-</openerp>
##############################################################################
import payment_acquirer
-import paypal
-import ogone
+++ /dev/null
-# -*- coding: utf-'8' "-*-"
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
-from hashlib import sha1
-import logging
-from lxml import etree, objectify
-from pprint import pformat
-# import requests
-import time
-from urllib import urlencode
-import urllib2
-# import urlparse
-
-from openerp.addons.payment_acquirer.data import ogone
-from openerp.addons.payment_acquirer.controllers.main import OgoneController
-from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
-from openerp.osv import osv, fields
-from openerp.tools import float_round
-
-_logger = logging.getLogger(__name__)
-
-
-class PaymentAcquirerOgone(osv.Model):
- _inherit = 'payment.acquirer'
-
- def _get_ogone_urls(self, cr, uid, ids, name, args, context=None):
- """ Ogone URLS:
-
- - standard order: POST address for form-based
-
- @TDETODO: complete me
- """
- res = {}
- for acquirer in self.browse(cr, uid, ids, context=context):
- qualif = acquirer.env
- res[acquirer.id] = {
- 'ogone_standard_order_url': 'https://secure.ogone.com/ncol/%s/orderstandard.asp' % qualif,
- 'ogone_direct_order_url': 'https://secure.ogone.com/ncol/%s/orderdirect.asp' % qualif,
- 'ogone_direct_query_url': 'https://secure.ogone.com/ncol/%s/querydirect.asp' % qualif,
- 'ogone_afu_agree_url': 'https://secure.ogone.com/ncol/%s/AFU_agree.asp' % qualif,
- }
- return res
-
- _columns = {
- 'ogone_pspid': fields.char(
- 'PSPID', required_if_provider='ogone'),
- 'ogone_userid': fields.char(
- 'API User id', required_if_provider='ogone'),
- 'ogone_password': fields.char(
- 'Password', required_if_provider='ogone'),
- 'ogone_shakey_in': fields.char(
- 'SHA Key IN', size=32, required_if_provider='ogone'),
- 'ogone_shakey_out': fields.char(
- 'SHA Key OUT', size=32, required_if_provider='ogone'),
- # store ogone contact URLs -> not necessary IMHO
- 'ogone_standard_order_url': fields.function(
- _get_ogone_urls, type='char', multi='_get_ogone_urls',
- string='Stanrd Order URL (form)'),
- 'ogone_direct_order_url': fields.function(
- _get_ogone_urls, type='char', multi='_get_ogone_urls',
- string='Direct Order URL (2)'),
- 'ogone_direct_query_url': fields.function(
- _get_ogone_urls, type='char', multi='_get_ogone_urls',
- string='Direct Query URL'),
- 'ogone_afu_agree_url': fields.function(
- _get_ogone_urls, type='char', multi='_get_ogone_urls',
- string='AFU Agree URL'),
- }
-
- def _ogone_generate_shasign(self, acquirer, inout, values):
- """ Generate the shasign for incoming or outgoing communications.
-
- :param browse acquirer: the payment.acquirer browse record. It should
- have a shakey in shaky out
- :param string inout: 'in' (openerp contacting ogone) or 'out' (ogone
- contacting openerp). In this last case only some
- fields should be contained (see e-Commerce basic)
- :param dict values: transaction values
-
- :return string: shasign
- """
- assert inout in ('in', 'out')
- assert acquirer.name == 'ogone'
- key = getattr(acquirer, 'ogone_shakey_' + inout)
-
- def filter_key(key):
- if inout == 'in':
- return True
- else:
- keys = "ORDERID CURRENCY AMOUNT PM ACCEPTANCE STATUS CARDNO ALIAS ED CN TRXDATE PAYID NCERROR BRAND ECI IP COMPLUS".split()
- return key.upper() in keys
-
- items = sorted((k.upper(), v) for k, v in values.items())
- sign = ''.join('%s=%s%s' % (k, v, key) for k, v in items if v and filter_key(k))
- shasign = sha1(sign).hexdigest()
- return shasign
-
- def ogone_form_generate_values(self, cr, uid, id, reference, amount, currency, partner_id=False, partner_values=None, tx_custom_values=None, context=None):
- if partner_values is None:
- partner_values = {}
- base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
- acquirer = self.browse(cr, uid, id, context=context)
- partner = None
- if partner_id:
- partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
- tx_values = {
- 'PSPID': acquirer.ogone_pspid,
- 'ORDERID': reference,
- 'AMOUNT': '%d' % int(float_round(amount, 2) * 100),
- 'CURRENCY': currency and currency.name or 'EUR',
- 'LANGUAGE': partner and partner.lang or partner_values.get('lang', ''),
- 'CN': partner and partner.name or partner_values.get('name', ''),
- 'EMAIL': partner and partner.email or partner_values.get('email', ''),
- 'OWNERZIP': partner and partner.zip or partner_values.get('zip', ''),
- 'OWNERADDRESS': partner and ' '.join((partner.street, partner.street2)).strip() or ' '.join((partner_values.get('street', ''), partner_values.get('street2', ''))).strip(),
- 'OWNERTOWN': partner and partner.city or partner_values.get('city', ''),
- 'OWNERCTY': partner and partner.country_id and partner.country_id.name or partner_values.get('country_name', ''),
- 'OWNERTELNO': partner and partner.phone or partner_values.get('phone', ''),
- 'ACCEPTURL': '%s/%s' % (base_url, OgoneController._accept_url),
- 'DECLINEURL': '%s/%s' % (base_url, OgoneController._decline_url),
- 'EXCEPTIONURL': '%s/%s' % (base_url, OgoneController._exception_url),
- 'CANCELURL': '%s/%s' % (base_url, OgoneController._cancel_url),
- }
- if tx_custom_values:
- tx_values.update(tx_custom_values)
- shasign = self._ogone_generate_shasign(acquirer, 'in', tx_values)
- tx_values['SHASIGN'] = shasign
- return tx_values
-
-
-class PaymentTxOgone(osv.Model):
- _inherit = 'payment.transaction'
-
- _columns = {
- 'ogone_3ds': fields.dummy('3ds Activated'),
- 'ogone_3ds_html': fields.html('3DS HTML'),
- 'ogone_feedback_model': fields.char(),
- 'ogone_feedback_eval': fields.char(),
- 'ogone_complus': fields.char('Complus'),
- }
-
- # --------------------------------------------------
- # FORM RELATED METHODS
- # --------------------------------------------------
-
- def _ogone_form_get_tx_from_shasign_out(self, cr, uid, data, context=None):
- reference, pay_id, shasign = data.get('orderID'), data.get('PAYID'), data.get('SHASIGN')
- if not reference or not pay_id or not shasign:
- error_msg = 'Ogone: received data with missing reference (%s) or pay_id (%s) or shashign (%s)' % (reference, pay_id, shasign)
- _logger.error(error_msg)
- raise ValidationError(error_msg)
-
- # find tx -> @TDENOTE use paytid ?
- tx_ids = self.pool['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context)
- if not tx_ids or len(tx_ids) > 1:
- error_msg = 'Ogone: received data for reference' % (reference)
- if not tx_ids:
- error_msg += '; no order found'
- else:
- error_msg += '; multiple order found'
- _logger.error(error_msg)
- raise ValidationError(error_msg)
- tx = self.pool['payment.transaction'].browse(cr, uid, tx_ids[0], context=context)
-
- # verify shasign
- shasign_check = self.pool['payment.acquirer']._generate_ogone_shasign(tx.acquirer_id, 'out', data)
- if shasign_check.upper() != shasign.upper():
- error_msg = 'Ogone: invalid shasign, received %s, computed %s, for data %s' % (shasign, shasign_check, data)
- _logger.error(error_msg)
- raise ValidationError(error_msg)
-
- return tx
-
- def ogone_form_generate_values(self, cr, uid, id, tx_custom_values=None, context=None):
- tx = self.browse(cr, uid, id, context=context)
-
- tx_data = {
- 'LANGUAGE': tx.partner_lang,
- 'CN': tx.partner_name,
- 'EMAIL': tx.partner_email,
- 'OWNERZIP': tx.partner_zip,
- 'OWNERADDRESS': tx.partner_address,
- 'OWNERTOWN': tx.partner_city,
- 'OWNERCTY': tx.partner_country_id and tx.partner_country_id.name or '',
- 'OWNERTELNO': tx.partner_phone,
- }
- if tx_custom_values:
- tx_data.update(tx_custom_values)
- return self.pool['payment.acquirer'].ogone_form_generate_values(
- cr, uid, tx.acquirer_id.id,
- tx.reference, tx.amount, tx.currency_id,
- tx_custom_values=tx_data,
- context=context
- )
-
- def ogone_form_feedback(self, cr, uid, data, context=None):
- print '-- ogone: ogone_form_feedback'
- tx = self._ogone_get_tx_from_shasign_out(cr, uid, data, context)
- if not tx:
- raise ValidationError('Ogone: feedback: tx not found')
-
- status = int(data.get('STATUS', '0'))
- print '\togone: statuts %s' % status
- if status in [5, 9]:
- tx.write({'state': 'done'})
- return True
- else:
- error = 'Ogone: feedback error: %(error_str)s\n\n%(error_code)s: %(error_msg)s' % {
- 'error_str': data.get('NCERROR'),
- 'error_code': data.get('NCERRORPLUS'),
- 'error_msg': ogone.OGONE_ERROR_MAP.get(data.get('NCERRORPLUS')),
- }
- _logger.info(error)
- tx.write({'state': 'error', 'state_message': error})
- return False
-
- # --------------------------------------------------
- # S2S RELATED METHODS
- # --------------------------------------------------
-
- def ogone_s2s_create_alias(self, cr, uid, id, values, context=None):
- """ Purpose: create an alias via batch """
- tx = self.browse(cr, uid, id, context=context)
- assert tx.type == 'server2server', 'Calling s2s dedicated method for a %s acquirer' % tx.type
- alias = 'OPENERP-%d-%d' % (tx.partner_id.id, tx.id)
-
- expiry_date = '%s%s' % (values['expiry_date_mm'], values['expiry_date_yy'][2:])
- line = 'ADDALIAS;%(alias)s;%(holder_name)s;%(number)s;%(expiry_date)s;%(brand)s;%(pspid)s'
- line = line % dict(values, alias=alias, expiry_date=expiry_date, pspid=tx.acquirer_id.ogone_pspid)
-
- tx_data = {
- 'FILE_REFERENCE': 'OPENERP-NEW-ALIAS-%s' % time.time(), # something unique,
- 'TRANSACTION_CODE': 'ATR',
- 'OPERATION': 'SAL',
- 'NB_PAYMENTS': 1, # even if we do not actually have any payment, ogone want it to not be 0
- 'FILE': line,
- 'REPLY_TYPE': 'XML',
- 'PSPID': tx.acquirer_id.ogone_pspid,
- 'USERID': tx.acquirer_id.ogone_userid,
- 'PSWD': tx.acquirer_id.ogone_password,
- 'PROCESS_MODE': 'CHECKANDPROCESS',
- }
-
- request = urllib2.Request(tx.acquirer_id.ogone_afu_agree_url, urlencode(tx_data))
- result = urllib2.urlopen(request).read()
-
- try:
- tree = objectify.fromstring(result)
- except etree.XMLSyntaxError:
- _logger.exception('Invalid xml response from ogone')
- return None
-
- error_code = error_str = None
- if hasattr(tree, 'PARAMS_ERROR'):
- error_code = tree.NCERROR.text
- error_str = 'PARAMS ERROR: %s' % (tree.PARAMS_ERROR.text or '',)
- else:
- node = tree.FORMAT_CHECK
- error_node = getattr(node, 'FORMAT_CHECK_ERROR', None)
- if error_node is not None:
- error_code = error_node.NCERROR.text
- error_str = 'CHECK ERROR: %s' % (error_node.ERROR.text or '',)
-
- if error_code:
- error_msg = ogone.OGONE_ERROR_MAP.get(error_code)
- error = '%s\n\n%s: %s' % (error_str, error_code, error_msg)
- _logger.error(error)
- raise Exception(error) # TODO specific exception
-
- tx.write({'partner_reference': alias})
- return True
-
- def ogone_s2s_generate_values(self, cr, uid, id, custom_values, context=None):
- tx = self.browse(cr, uid, id, context=context)
- tx_data = {
- 'PSPID': tx.acquirer_id.ogone_pspid,
- 'USERID': tx.acquirer_id.ogone_userid,
- 'PSWD': tx.acquirer_id.ogone_password,
- 'OrderID': tx.reference,
- 'amount': '%d' % int(float_round(tx.amount, 2) * 100), # tde check amount or str * 100 ?
- 'CURRENCY': tx.currency_id.name,
- 'LANGUAGE': tx.partner_lang,
- 'OPERATION': 'SAL',
- 'ECI': 2, # Recurring (from MOTO)
- 'ALIAS': tx.partner_reference,
- 'RTIMEOUT': 30,
- }
- if custom_values.get('ogone_cvc'):
- tx_data['CVC'] = custom_values.get('ogone_cvc')
- if custom_values.pop('ogone_3ds', None):
- tx_data.update({
- 'FLAG3D': 'Y', # YEAH!!
- })
- if custom_values.get('ogone_complus'):
- tx_data['COMPLUS'] = custom_values.get('ogone_complus')
- if custom_values.get('ogone_accept_url'):
- pass
-
- shasign = self.pool['payment.acquirer']._ogone_generate_shasign(tx.acquirer_id, 'in', tx_data)
- tx_data['SHASIGN'] = shasign
- return tx_data
-
- def ogone_s2s_execute(self, cr, uid, id, values, context=None):
- tx = self.browse(cr, uid, id, context=context)
-
- tx_data = self.ogone_s2s_generate_values(cr, uid, id, values, context=context)
- _logger.info('Generated Ogone s2s data %s', pformat(tx_data)) # debug
-
- request = urllib2.Request(tx.acquirer_id.ogone_direct_order_url, urlencode(tx_data))
- result = urllib2.urlopen(request).read()
- _logger.info('Contacted Ogone direct order; result %s', result) # debug
-
- tree = objectify.fromstring(result)
- payid = tree.get('PAYID')
- print 'payid', payid
-
- query_direct_data = dict(
- PSPID=tx.acquirer_id.ogone_pspid,
- USERID=tx.acquirer_id.ogone_userid,
- PSWD=tx.acquirer_id.ogone_password,
- ID=payid,
- )
- query_direct_url = 'https://secure.ogone.com/ncol/%s/querydirect.asp' % (tx.acquirer_id.env,)
-
- tries = 2
- tx_done = False
- tx_status = False
- while not tx_done or tries > 0:
- try:
- tree = objectify.fromstring(result)
- except etree.XMLSyntaxError:
- # invalid response from ogone
- _logger.exception('Invalid xml response from ogone')
- raise
-
- # see https://secure.ogone.com/ncol/paymentinfos1.asp
- VALID_TX = [5, 9]
- WAIT_TX = [41, 50, 51, 52, 55, 56, 91, 92, 99]
- PENDING_TX = [46] # 3DS HTML response
- # other status are errors...
-
- status = tree.get('STATUS')
- if status == '':
- status = None
- else:
- status = int(status)
-
- if status in VALID_TX:
- tx_status = True
- tx_done = True
-
- elif status in PENDING_TX:
- html = str(tree.HTML_ANSWER)
- tx_data.update(ogone_3ds_html=html.decode('base64'))
- tx_status = False
- tx_done = True
-
- elif status in WAIT_TX:
- time.sleep(1500)
-
- request = urllib2.Request(query_direct_url, urlencode(query_direct_data))
- result = urllib2.urlopen(request).read()
- _logger.debug('Contacted Ogone query direct; result %s', result)
-
- else:
- error_code = tree.get('NCERROR')
- if not ogone.retryable(error_code):
- error_str = tree.get('NCERRORPLUS')
- error_msg = ogone.OGONE_ERROR_MAP.get(error_code)
- error = 'ERROR: %s\n\n%s: %s' % (error_str, error_code, error_msg)
- _logger.info(error)
- raise Exception(error)
-
- tries = tries - 1
-
- if not tx_done and tries == 0:
- raise Exception('Cannot get transaction status...')
-
- return (tx_status, orderid, payid)
+++ /dev/null
-# -*- coding: utf-'8' "-*-"
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
-from openerp.addons.payment_acquirer.controllers.main import PaypalController
-from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
-from openerp.osv import osv, fields
-
-import logging
-import requests
-import urlparse
-
-_logger = logging.getLogger(__name__)
-
-
-class AcquirerPaypal(osv.Model):
- _inherit = 'payment.acquirer'
-
- _columns = {
- 'paypal_email_id': fields.char('Email ID', required_if_provider='paypal'),
- 'paypal_username': fields.char('Username', required_if_provider='paypal'),
- 'paypal_password': fields.char('Password'),
- 'paypal_signature': fields.char('Signature'),
- 'paypal_tx_url': fields.char('Transaction URL', required_if_provider='paypal'),
- 'paypal_use_dpn': fields.boolean('Use DPN'),
- 'paypal_use_ipn': fields.boolean('Use IPN'),
- }
-
- _defaults = {
- 'paypal_use_dpn': True,
- 'paypal_use_ipn': True,
- 'paypal_tx_url': 'https://www.sandbox.paypal.com/cgi-bin/webscr',
- }
-
- def paypal_form_generate_values(self, cr, uid, id, reference, amount, currency, partner_id=False, partner_values=None, tx_custom_values=None, context=None):
- if partner_values is None:
- partner_values = {}
- base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
- acquirer = self.browse(cr, uid, id, context=context)
- partner = None
- if partner_id:
- partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
- tx_values = {
- 'cmd': '_xclick',
- 'business': acquirer.paypal_email_id,
- 'item_name': reference,
- 'item_number': reference,
- 'amount': amount,
- 'currency_code': currency and currency.name or 'EUR',
- 'address1': partner and ' '.join((partner.street, partner.street2)).strip() or ' '.join((partner_values.get('street', ''), partner_values.get('street2', ''))).strip(),
- 'city': partner and partner.city or partner_values.get('city', ''),
- 'country': partner and partner.country_id and partner.country_id.name or partner_values.get('country_name', ''),
- 'email': partner and partner.email or partner_values.get('email', ''),
- 'zip': partner and partner.zip or partner_values.get('zip', ''),
- 'first_name': partner and partner.name or partner_values.get('name', '').split()[-1:],
- 'last_name': partner and partner.name or partner_values.get('name', '').split()[:-1],
- 'return': '%s/%s' % (base_url, PaypalController._return_url),
- 'notify_url': '%s/%s' % (base_url, PaypalController._notify_url),
- 'cancel_return': '%s/%s' % (base_url, PaypalController._cancel_url),
- }
- if tx_custom_values:
- tx_values.update(tx_custom_values)
- return tx_values
-
-
-class TxPaypal(osv.Model):
- _inherit = 'payment.transaction'
-
- _columns = {
- 'paypal_txn_id': fields.char('Transaction ID'),
- }
-
- # --------------------------------------------------
- # FORM RELATED METHODS
- # --------------------------------------------------
-
- def paypal_form_generate_values(self, cr, uid, id, tx_custom_values=None, context=None):
- tx = self.browse(cr, uid, id, context=context)
-
- tx_data = {
- 'item_name': tx.name,
- 'first_name': tx.partner_name and tx.partner_name.split()[-1:],
- 'last_name': tx.partner_name and tx.partner_name.split()[:-1],
- 'email': tx.partner_email,
- 'zip': tx.partner_zip,
- 'address1': tx.partner_address,
- 'city': tx.partner_city,
- 'country': tx.partner_country_id and tx.partner_country_id.name or '',
- }
- if tx_custom_values:
- tx_data.update(tx_custom_values)
- return self.pool['payment.acquirer'].paypal_form_generate_values(
- cr, uid, tx.acquirer_id.id,
- tx.reference, tx.amount, tx.currency_id,
- tx_custom_values=tx_data,
- context=context
- )
-
-
-
- def validate_paypal_notification(self, cr, uid, url, context=None):
- parsed_url = urlparse.urlparse(url)
- query_parameters = parsed_url.query
- parameters = urlparse.parse_qs(query_parameters)
-
- invalid_parameters = []
-
- # check tx effectively exists
- txn_id = parameters.get('txn_id')[0]
- tx_ids = self.search(cr, uid, [('paypal_txn_id', '=', txn_id)], context=context)
- if not tx_ids:
- _logger.warning(
- 'Received a notification from Paypal for a tx %s that does not exists in database.' %
- txn_id
- )
- return False
- elif len(tx_ids) > 1:
- _logger.warning(
- 'Received a notification from Paypal for a tx %s that is duplicated in database.' %
- txn_id
- )
-
- tx = self.browse(cr, uid, tx_ids[0], context=context)
-
- if parameters.get('notify_version')[0] != '2.6':
- _logger.warning(
- 'Received a notification from Paypal with version %s instead of 2.6. This could lead to issues when managing it.' %
- parameters.get('notify_version')
- )
- if parameters.get('test_ipn')[0]:
- _logger.warning(
- 'Received a notification from Paypal using sandbox'
- ),
- # check transaction
- if parameters.get('payment_status')[0] != 'Completed':
- invalid_parameters.append(('payment_status', 'Completed'))
- # check what is buyed
- if parameters.get('mc_gross')[0] != tx.amount:
- invalid_parameters.append(('mc_gross', tx.amount))
- if parameters.get('mc_currency')[0] != tx.currency_id.name:
- invalid_parameters.append(('mc_currency', tx.currency_id.name))
- # if parameters.get('payment_fee') != tx.payment_fee:
- # invalid_parameters.append(('payment_fee', tx.payment_fee))
- # if parameters.get('quantity') != tx.quantity:
- # invalid_parameters.append(('mc_currency', tx.quantity))
- # if parameters.get('shipping') != tx.shipping:
- # invalid_parameters.append(('shipping', tx.shipping))
- # check buyer
- # if parameters.get('payer_id') != tx.payer_id:
- # invalid_parameters.append(('mc_gross', tx.payer_id))
- # if parameters.get('payer_email') != tx.payer_email:
- # invalid_parameters.append(('payer_email', tx.payer_email))
- # check seller
- # if parameters.get('receiver_email') != tx.receiver_email:
- # invalid_parameters.append(('receiver_email', tx.receiver_email))
- # if parameters.get('receiver_id') != tx.receiver_id:
- # invalid_parameters.append(('receiver_id', tx.receiver_id))
-
- if not invalid_parameters:
- self.write(cr, uid, [tx.id], {
- 'payment_type': parameters.get('payment_type')[0],
- 'date_validate': parameters.get('payment_date', [fields.datetime.now()])[0],
- 'txn_type': parameters.get('express_checkout')[0],
- }, context=context)
- return tx.id
- else:
- _warn_message = 'The following transaction parameters are incorrect:\n'
- for item in invalid_parameters:
- _warn_message += '\t%s: received %s instead of %s\n' % (item[0], parameters.get(item[0])[0], item[1])
- _logger.warning(_warn_message)
-
- return False
-
- def create_paypal_command(self, cr, uid, cmd, parameters):
- parameters.update(cmd=cmd)
- return requests.post(self._paypal_url, data=parameters)
-
- def _validate_paypal(self, cr, uid, ids, context=None):
- res = []
- for tx in self.browse(cr, uid, ids, context=context):
- parameters = {}
- parameters.update(
- cmd='_notify-validate',
- business='tdelavallee-facilitator@gmail.com',
- item_name="%s %s" % ('cacapoutch', tx.reference),
- item_number=tx.reference,
- amount=tx.amount,
- currency_code=tx.currency_id.name,
- )
- print '\t', parameters
- # paypal_url = "https://www.paypal.com/cgi-bin/webscr"
- paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"
- resp = requests.post(paypal_url, data=parameters)
- print resp
- print resp.url
- print resp.text
- response = urlparse.parse_qsl(resp)
- print response
- # transaction's unique id
- # response["txn_id"]
-
- # "Failed", "Reversed", "Refunded", "Canceled_Reversal", "Denied"
- status = "refused"
- retry_time = False
-
- if response["payment_status"] == "Voided":
- status = "refused"
- elif response["payment_status"] in ("Completed", "Processed") and response["item_number"] == tx.reference and response["mc_gross"] == tx.amount:
- status = "validated"
- elif response["payment_status"] in ("Expired", "Pending"):
- status = "pending"
- retry_time = 60
-
- res.append(
- (status, retry_time, "payment_status=%s&pending_reason=%s&reason_code=%s" % (
- response["payment_status"],
- response.get("pending_reason"),
- response.get("reason_code")))
- )
- return response
-
- def _transaction_feedback_paypal(self, **values):
- print values
- return True
#
##############################################################################
-from . import test_payment_acquirer
-
-checks = [
- test_payment_acquirer,
-]
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+import common
from openerp.tests import common
-class TestPaymentAcquirer(common.TransactionCase):
+class PaymentAcquirerCommon(common.TransactionCase):
def setUp(self):
- super(TestPaymentAcquirer, self).setUp()
+ super(PaymentAcquirerCommon, self).setUp()
self.payment_acquirer = self.registry('payment.acquirer')
self.payment_transaction = self.registry('payment.transaction')
+++ /dev/null
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Business Applications
-# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
-from openerp.addons.payment_acquirer.controllers.main import OgoneController
-from openerp.addons.payment_acquirer.tests.common import TestPaymentAcquirer
-from openerp.osv.orm import except_orm
-
-from lxml import objectify
-# import requests
-# import urlparse
-
-
-class BasicPayment(TestPaymentAcquirer):
-
- def test_10_paypal_basic(self):
- pass
-
- def test_11_paypal_form(self):
- cr, uid = self.cr, self.uid
- context = {}
- base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url')
- # ogone_url = self.payment_acquirer._get_ogone_urls(cr, uid, [ogone_id], None, None)[ogone_id]['ogone_standard_order_url']
-
- model, paypal_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer', 'paypal_acquirer_button')
-
- # forgot some mandatory fields: should crash
- with self.assertRaises(except_orm):
- paypal_id = self.payment_acquirer.create(
- cr, uid, {
- 'name': 'paypal',
- 'env': 'test',
- 'view_template_id': paypal_view_id,
- 'paypal_email_id': 'tde+paypal-facilitator@openerp.com',
- }, context=context
- )
- # tde+buyer@openerp.com
-
- # create a new paypal account
- paypal_id = self.payment_acquirer.create(
- cr, uid, {
- 'name': 'paypal',
- 'env': 'test',
- 'view_template_id': paypal_view_id,
- 'paypal_email_id': 'tde+paypal-facilitator@openerp.com',
- 'paypal_username': 'tde+paypal-facilitator_api1.openerp.com',
- }, context=context
- )
- # verify acquirer data
- paypal = self.payment_acquirer.browse(cr, uid, paypal_id, context)
- self.assertEqual(paypal.env, 'test', 'test without test env')
-
- # render the button
- res = self.payment_acquirer.render(
- cr, uid, paypal_id,
- 'test_ref0', 0.01, self.currency_euro,
- partner_id=None,
- partner_values=self.buyer_values,
- context=context)
- print res
-
- # # check some basic paypal methods
- # res = self.payment_transaction.validate_paypal_notification(
- # cr, uid,
- # 'http://localhost/payment?mc_gross=19.95&protection_eligibility=Eligible&address_status=confirmed&payer_id=LPLWNMTBWMFAY&tax=0.00&address_street=1+Main+St&payment_date=20%3A12%3A59+Jan+13%2C+2009+PST&payment_status=Completed&charset=windows-1252&address_zip=95131&first_name=Test&mc_fee=0.88&address_country_code=US&address_name=Test+User¬ify_version=2.6&custom=&payer_status=verified&address_country=United+States&address_city=San+Jose&quantity=1&verify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtf&payer_email=gpmac_1231902590_per%40paypal.com&txn_id=61E67681CH3238416&payment_type=instant&last_name=User&address_state=CA&receiver_email=gpmac_1231902686_biz%40paypal.com&payment_fee=0.88&receiver_id=S8XGHLYDW9T3S&txn_type=express_checkout&item_name=&mc_currency=USD&item_number=&residence_country=US&test_ipn=1&handling_amount=0.00&transaction_subject=&payment_gross=19.95&shipping=0.00')
- # self.assertEqual(res, False, 'payment: paypal validation on a txn_id that does not exists should return False')
-
- # txn_id = self.payment_transaction.create(
- # cr, uid, {
- # 'amount': 0.01,
- # 'acquirer_id': paypal_id,
- # 'currency_id': currency_id,
- # 'reference': 'test_reference',
- # 'paypal_txn_id': '61E67681CH3238416',
- # }, context=context
- # )
- # res = self.payment_transaction.validate_paypal_notification(
- # cr, uid,
- # 'http://localhost/payment?mc_gross=19.95&protection_eligibility=Eligible&address_status=confirmed&payer_id=LPLWNMTBWMFAY&tax=0.00&address_street=1+Main+St&payment_date=20%3A12%3A59+Jan+13%2C+2009+PST&payment_status=Completed&charset=windows-1252&address_zip=95131&first_name=Test&mc_fee=0.88&address_country_code=US&address_name=Test+User¬ify_version=2.6&custom=&payer_status=verified&address_country=United+States&address_city=San+Jose&quantity=1&verify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtf&payer_email=gpmac_1231902590_per%40paypal.com&txn_id=61E67681CH3238416&payment_type=instant&last_name=User&address_state=CA&receiver_email=gpmac_1231902686_biz%40paypal.com&payment_fee=0.88&receiver_id=S8XGHLYDW9T3S&txn_type=express_checkout&item_name=&mc_currency=USD&item_number=&residence_country=US&test_ipn=1&handling_amount=0.00&transaction_subject=&payment_gross=19.95&shipping=0.00')
- # print res
-
- # # user pays using Paypal
- # resp = self.payment_transaction.create_paypal_command(
- # cr, uid, cmd='_xclick', parameters={
- # 'business': 'tdelavallee-facilitator@gmail.com',
- # 'amount': 50,
- # 'item_name': 'test_item',
- # 'quantity': 1,
- # 'currency_code': 'USD',
- # 'return': 'http://www.example.com',
- # })
- # print resp
- # print resp.url
- # print resp.text
-
- # self.payment_transaction.validate(cr, uid, [tx_id], context=context)
-
- def test_20_ogone_form(self):
- cr, uid = self.cr, self.uid
- context = {}
- base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url')
- # ogone_url = self.payment_acquirer._get_ogone_urls(cr, uid, [ogone_id], None, None)[ogone_id]['ogone_standard_order_url']
-
- model, ogone_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer', 'ogone_acquirer_button')
-
- # create a new ogone account
- ogone_id = self.payment_acquirer.create(
- cr, uid, {
- 'name': 'ogone',
- 'env': 'test',
- 'view_template_id': ogone_view_id,
- 'ogone_pspid': 'pinky',
- 'ogone_userid': 'OOAPI',
- 'ogone_password': 'R!ci/6Nu8a',
- 'ogone_shakey_in': 'tINY4Yv14789gUix1130',
- 'ogone_shakey_out': 'tINYj885Tfvd4P471464',
- }, context=context
- )
- # verify acquirer data
- ogone = self.payment_acquirer.browse(cr, uid, ogone_id, context)
- self.assertEqual(ogone.env, 'test', 'test without test env')
-
- form_values = {
- 'PSPID': 'pinky',
- 'ORDERID': 'test_ref0',
- 'AMOUNT': '1',
- 'CURRENCY': 'EUR',
- 'LANGUAGE': 'en_US',
- 'CN': 'Norbert Buyer',
- 'EMAIL': 'norbert.buyer@example.com',
- 'OWNERZIP': '1000',
- 'OWNERADDRESS': 'Huge Street 2/543',
- 'OWNERCTY': 'Belgium',
- 'OWNERTOWN': 'Sin City',
- 'OWNERTELNO': '0032 12 34 56 78',
- 'SHASIGN': 'ea74bb42d4f25746279cdd44a737aaddc71e7f9f',
- 'ACCEPTURL': '%s/%s' % (base_url, OgoneController._accept_url),
- 'DECLINEURL': '%s/%s' % (base_url, OgoneController._decline_url),
- 'EXCEPTIONURL': '%s/%s' % (base_url, OgoneController._exception_url),
- 'CANCELURL': '%s/%s' % (base_url, OgoneController._cancel_url),
- }
-
- # render the button
- res = self.payment_acquirer.render(
- cr, uid, ogone_id,
- 'test_ref0', 0.01, self.currency_euro,
- partner_id=None,
- partner_values=self.buyer_values,
- context=context)
- # check form result
- tree = objectify.fromstring(res)
- self.assertEqual(tree.get('action'), 'https://secure.ogone.com/ncol/test/orderstandard.asp', 'ogone: wrong form POST url')
- for form_input in tree.input:
- if form_input.get('name') in ['submit']:
- continue
- self.assertEqual(
- form_input.get('value'),
- form_values[form_input.get('name')],
- 'ogone: wrong value for form: received %s instead of %s' % (form_input.get('value'), form_values[form_input.get('name')])
- )
- # resp = requests.post(tree.get('action'), data=form_values)
-
- # create a new draft tx
- tx_id = self.payment_transaction.create(
- cr, uid, {
- 'amount': 0.01,
- 'acquirer_id': ogone_id,
- 'currency_id': self.currency_euro_id,
- 'reference': 'test_ref0',
- 'partner_id': self.buyer_id,
- }, context=context
- )
- # render the button
- res = self.payment_acquirer.render(
- cr, uid, ogone_id,
- 'test_ref0', 0.01, self.currency_euro,
- tx_id=tx_id,
- partner_id=None,
- partner_values=self.buyer_values,
- context=context)
- # check form result
- tree = objectify.fromstring(res)
- self.assertEqual(tree.get('action'), 'https://secure.ogone.com/ncol/test/orderstandard.asp', 'ogone: wrong form POST url')
- for form_input in tree.input:
- if form_input.get('name') in ['submit']:
- continue
- self.assertEqual(
- form_input.get('value'),
- form_values[form_input.get('name')],
- 'ogone: wrong value for form input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')])
- )
-
- def test_21_ogone_s2s(self):
- cr, uid = self.cr, self.uid
- context = {}
-
- model, ogone_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer', 'ogone_acquirer_button')
-
- # create a new ogone account
- ogone_id = self.payment_acquirer.create(
- cr, uid, {
- 'name': 'ogone',
- 'env': 'test',
- 'view_template_id': ogone_view_id,
- 'ogone_pspid': 'pinky',
- 'ogone_userid': 'OOAPI',
- 'ogone_password': 'R!ci/6Nu8a',
- 'ogone_shakey_in': 'tINY4Yv14789gUix1130',
- 'ogone_shakey_out': 'tINYj885Tfvd4P471464',
- }, context=context
- )
-
- # create a new draft tx
- tx_id = self.payment_transaction.create(
- cr, uid, {
- 'amount': 0.01,
- 'acquirer_id': ogone_id,
- 'currency_id': self.currency_euro_id,
- 'reference': 'test_ogone_0',
- 'partner_id': self.buyer_id,
- 'type': 'server2server',
- }, context=context
- )
-
- res = self.payment_transaction.ogone_s2s_create_alias(
- cr, uid, tx_id, {
- 'expiry_date_mm': '01',
- 'expiry_date_yy': '2015',
- 'holder_name': 'Norbert Poilu',
- 'number': '4000000000000002',
- 'brand': 'VISA',
- }, context=context)
- print res
-
- res = self.payment_transaction.ogone_s2s_execute(cr, uid, tx_id, {}, context=context)
- print res
-
-
-# {
-# 'orderID': u'reference',
-# 'STATUS': u'9',
-# 'CARDNO': u'XXXXXXXXXXXX0002',
-# 'PAYID': u'24998692',
-# 'CN': u'Norbert Poilu',
-# 'NCERROR': u'0',
-# 'TRXDATE': u'11/05/13',
-# 'IP': u'85.201.233.72',
-# 'BRAND': u'VISA',
-# 'ACCEPTANCE': u'test123',
-# 'currency': u'EUR',
-# 'amount': u'1.95',
-# 'SHASIGN': u'EFDC56879EF7DE72CCF4B397076B5C9A844CB0FA',
-# 'ED': u'0314',
-# 'PM': u'CreditCard'
-# }
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<openerp>
- <data noupdate="0">
-
- <template id="ogone_acquirer_button">
- <form t-if="acquirer" t-att-action="acquirer.ogone_standard_order_url" method="post" target="_self">
- <!-- seller -->
- <input type='hidden' name='PSPID' t-att-value='tx_values["PSPID"]'/>
- <input type='hidden' name='ORDERID' t-att-value='tx_values["ORDERID"]'/>
- <!-- cart -->
- <input type='hidden' name='AMOUNT' t-att-value='tx_values["AMOUNT"]'/>
- <input type='hidden' name='CURRENCY' t-att-value='tx_values["CURRENCY"]'/>
- <!-- buyer -->
- <input type='hidden' name='LANGUAGE' t-att-value='tx_values["LANGUAGE"]'/>
- <input type='hidden' name='CN' t-att-value='tx_values["CN"]'/>
- <input type='hidden' name='EMAIL' t-att-value='tx_values["EMAIL"]'/>
- <input type='hidden' name='OWNERZIP' t-att-value='tx_values["OWNERZIP"]'/>
- <input type='hidden' name='OWNERADDRESS' t-att-value='tx_values["OWNERADDRESS"]'/>
- <input type='hidden' name='OWNERCTY' t-att-value='tx_values["OWNERCTY"]'/>
- <input type='hidden' name='OWNERTOWN' t-att-value='tx_values["OWNERTOWN"]'/>
- <input type='hidden' name='OWNERTELNO' t-att-value='tx_values["OWNERTELNO"]'/>
- <!-- before payment verification -->
- <input type='hidden' name='SHASIGN' t-att-value='tx_values["SHASIGN"]'/>
- <!-- look and print -->
- <!-- <input type='hidden' name='TITLE' t-att-value='tx_dict["currency_name"]'/>
- <input type='hidden' name='BGCOLOR' t-att-value='tx_dict["currency_name"]'/>
- <input type='hidden' name='TXTCOLOR' t-att-value='tx_dict["currency_name"]'/>
- <input type='hidden' name='TBLBGCOLOR' t-att-value='tx_dict["currency_name"]'/>
- <input type='hidden' name='TBLTXTCOLOR' t-att-value='tx_dict["currency_name"]'/>
- <input type='hidden' name='BUTTONBGCOLOR' t-att-value='tx_dict["currency_name"]'/>
- <input type='hidden' name='BUTTONTXTCOLOR' t-att-value='tx_dict["currency_name"]'/>
- <input type='hidden' name='LOGO' t-att-value='tx_dict["currency_name"]'/>
- <input type='hidden' name='FONTTYPE' t-att-value='tx_dict["currency_name"]'/> -->
- <!-- redirection -->
- <input type='hidden' name='ACCEPTURL' t-att-value='tx_values["ACCEPTURL"]'/>
- <input type='hidden' name='DECLINEURL' t-att-value='tx_values["DECLINEURL"]'/>
- <input type='hidden' name='EXCEPTIONURL' t-att-value='tx_values["EXCEPTIONURL"]'/>
- <input type='hidden' name='CANCELURL' t-att-value='tx_values["CANCELURL"]'/>
- <input type="image" name="submit" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
- </form>
- </template>
-
- </data>
-</openerp>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<openerp>
- <data noupdate="0">
-
- <template id="paypal_acquirer_button">
- <form t-if="acquirer.paypal_email_id" t-att-action="acquirer.paypal_tx_url" method="post" target="_self">
- <input type="hidden" name="cmd" value="tx_values['cmd']"/>
- <input type="hidden" name="business" t-att-value="tx_values['business']"/>
- <input type="hidden" name="item_name" t-attf-value="tx_values['item_name']"/>
- <input type="hidden" name="item_number" t-att-value="tx_values['item_number']"/>
- <input type="hidden" name="amount" t-att-value="tx_values['amount']"/>
- <input type="hidden" name="currency_code" t-att-value="tx_values['currency_code']"/>
- <!-- partner / address data -->
- <input type="hidden" name="address1" t-att-value="tx_values['address1']"/>
- <input type="hidden" name="city" t-att-value="tx_values['city']"/>
- <input type="hidden" name="country" t-att-value="tx_values['country']"/>
- <input type="hidden" name="email" t-att-value="tx_values['email']"/>
- <input type="hidden" name="first_name" t-att-value="tx_values['first_name']"/>
- <input type="hidden" name="last_name" t-att-value="tx_values['last_name']"/>
- <input type="hidden" name="zip" t-att-value="tx_values['zip']"/>
- <!-- URLs -->
- <input t-if="acquirer.paypal_use_dpn" type='hidden' name='return'
- t-att-value="tx_values['return']"/>
- <input t-if="acquirer.paypal_use_ipn" type='hidden' name='notify_url'
- t-att-value="tx_values['notify_url']"/>
- <input t-if="tx_values['cancel_return']" type="hidden" name="cancel_return"
- t-att-value="tx_values['cancel_return']"/>
- <!-- button -->
- <input type="image" name="submit" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
- </form>
- </template>
-
- </data>
-</openerp>
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import models
+import controllers
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+{
+ 'name': 'Ogone Payment Acquirer',
+ 'category': 'Hidden',
+ 'summary': 'Payment acquirer: Ogone',
+ 'version': '0.1',
+ 'description': """Ogone Payment Acquirer""",
+ 'author': 'OpenERP SA',
+ 'depends': ['payment_acquirer'],
+ 'data': [
+ 'views/ogone.xml',
+ 'data/ogone.xml',
+ ],
+ 'installable': True,
+}
--- /dev/null
+import main
\ No newline at end of file
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.addons.web import http
+from openerp.addons.web.http import request
+# from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
+from openerp.addons.website.models import website
+
+import logging
+import requests
+from urllib import urlencode
+
+_logger = logging.getLogger(__name__)
+
+
+class OgoneController(http.Controller):
+ _accept_url = '/payment/ogone/test/accept'
+ _decline_url = '/payment/ogone/test/decline'
+ _exception_url = '/payment/ogone/test/exception'
+ _cancel_url = '/payment/ogone/test/cancel'
+
+ @website.route([
+ '/payment/ogone/feedback', '/payment/ogone/test/accept',
+ '/payment/ogone/decline', '/payment/ogone/test/decline',
+ '/payment/ogone/exception', '/payment/ogone/test/exception',
+ '/payment/ogone/cancel', '/payment/ogone/test/cancel',
+ ], type='http', auth='admin')
+ def feedback(self, **post):
+ cr, uid, context = request.cr, request.uid, request.context
+ Payment = request.registry['payment.transaction']
+ print 'Entering ogone feedback with', post
+
+ res = Payment.tx_ogone_feedback(cr, uid, post, context)
+ print res
+ return ''
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import ogone
--- /dev/null
+# -*- coding: utf-8 -*-
+
+OGONE_ERROR_MAP = {
+ '0020001001': "Authorization failed, please retry",
+ '0020001002': "Authorization failed, please retry",
+ '0020001003': "Authorization failed, please retry",
+ '0020001004': "Authorization failed, please retry",
+ '0020001005': "Authorization failed, please retry",
+ '0020001006': "Authorization failed, please retry",
+ '0020001007': "Authorization failed, please retry",
+ '0020001008': "Authorization failed, please retry",
+ '0020001009': "Authorization failed, please retry",
+ '0020001010': "Authorization failed, please retry",
+ '0030001999': "Our payment system is currently under maintenance, please try later",
+ '0050001005': "Expiry date error",
+ '0050001007': "Requested Operation code not allowed",
+ '0050001008': "Invalid delay value",
+ '0050001010': "Input date in invalid format",
+ '0050001013': "Unable to parse socket input stream",
+ '0050001014': "Error in parsing stream content",
+ '0050001015': "Currency error",
+ '0050001016': "Transaction still posted at end of wait",
+ '0050001017': "Sync value not compatible with delay value",
+ '0050001019': "Transaction duplicate of a pre-existing transaction",
+ '0050001020': "Acceptation code empty while required for the transaction",
+ '0050001024': "Maintenance acquirer differs from original transaction acquirer",
+ '0050001025': "Maintenance merchant differs from original transaction merchant",
+ '0050001028': "Maintenance operation not accurate for the original transaction",
+ '0050001031': "Host application unknown for the transaction",
+ '0050001032': "Unable to perform requested operation with requested currency",
+ '0050001033': "Maintenance card number differs from original transaction card number",
+ '0050001034': "Operation code not allowed",
+ '0050001035': "Exception occurred in socket input stream treatment",
+ '0050001036': "Card length does not correspond to an acceptable value for the brand",
+ '0050001036': "Card length does not correspond to an acceptable value for the brand",
+ '0050001068': "A technical problem occurred, please contact helpdesk",
+ '0050001069': "Invalid check for CardID and Brand",
+ '0050001070': "A technical problem occurred, please contact helpdesk",
+ '0050001116': "Unknown origin IP",
+ '0050001117': "No origin IP detected",
+ '0050001118': "Merchant configuration problem, please contact support",
+ '10001001': "Communication failure",
+ '10001002': "Communication failure",
+ '10001003': "Communication failure",
+ '10001004': "Communication failure",
+ '10001005': "Communication failure",
+ '20001001': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001002': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001003': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001004': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001005': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001006': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001007': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001008': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001009': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001010': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001101': "A technical problem occurred, please contact helpdesk",
+ '20001105': "We received an unknown status for the transaction. We will contact your acquirer and update the status of the transaction within one working day. Please check the status later.",
+ '20001111': "A technical problem occurred, please contact helpdesk",
+ '20002001': "Origin for the response of the bank can not be checked",
+ '20002002': "Beneficiary account number has been modified during processing",
+ '20002003': "Amount has been modified during processing",
+ '20002004': "Currency has been modified during processing",
+ '20002005': "No feedback from the bank server has been detected",
+ '30001001': "Payment refused by the acquirer",
+ '30001002': "Duplicate request",
+ '30001010': "A technical problem occurred, please contact helpdesk",
+ '30001011': "A technical problem occurred, please contact helpdesk",
+ '30001012': "Card black listed - Contact acquirer",
+ '30001015': "Your merchant's acquirer is temporarily unavailable, please try later or choose another payment method.",
+ '30001051': "A technical problem occurred, please contact helpdesk",
+ '30001054': "A technical problem occurred, please contact helpdesk",
+ '30001057': "Your merchant's acquirer is temporarily unavailable, please try later or choose another payment method.",
+ '30001058': "Your merchant's acquirer is temporarily unavailable, please try later or choose another payment method.",
+ '30001060': "Aquirer indicates that a failure occured during payment processing",
+ '30001070': "RATEPAY Invalid Response Type (Failure)",
+ '30001071': "RATEPAY Missing Mandatory status code field (failure)",
+ '30001072': "RATEPAY Missing Mandatory Result code field (failure)",
+ '30001073': "RATEPAY Response parsing Failed",
+ '30001090': "CVC check required by front end and returned invalid by acquirer",
+ '30001091': "ZIP check required by front end and returned invalid by acquirer",
+ '30001092': "Address check required by front end and returned as invalid by acquirer.",
+ '30001100': "Unauthorized buyer's country",
+ '30001101': "IP country <> card country",
+ '30001102': "Number of different countries too high",
+ '30001103': "unauthorized card country",
+ '30001104': "unauthorized ip address country",
+ '30001105': "Anonymous proxy",
+ '30001110': "If the problem persists, please contact Support, or go to paysafecard's card balance page (https://customer.cc.at.paysafecard.com/psccustomer/GetWelcomePanelServlet?language=en) to see when the amount reserved on your card will be available again.",
+ '30001120': "IP address in merchant's black list",
+ '30001130': "BIN in merchant's black list",
+ '30001131': "Wrong BIN for 3xCB",
+ '30001140': "Card in merchant's card blacklist",
+ '30001141': "Email in blacklist",
+ '30001142': "Passenger name in blacklist",
+ '30001143': "Card holder name in blacklist",
+ '30001144': "Passenger name different from owner name",
+ '30001145': "Time to departure too short",
+ '30001149': "Card Configured in Card Supplier Limit for another relation (CSL)",
+ '30001150': "Card not configured in the system for this customer (CSL)",
+ '30001151': "REF1 not allowed for this relationship (Contract number",
+ '30001152': "Card/Supplier Amount limit reached (CSL)",
+ '30001153': "Card not allowed for this supplier (Date out of contract bounds)",
+ '30001154': "You have reached the usage limit allowed",
+ '30001155': "You have reached the usage limit allowed",
+ '30001156': "You have reached the usage limit allowed",
+ '30001157': "Unauthorized IP country for itinerary",
+ '30001158': "email usage limit reached",
+ '30001159': "Unauthorized card country/IP country combination",
+ '30001160': "Postcode in highrisk group",
+ '30001161': "generic blacklist match",
+ '30001162': "Billing Address is a PO Box",
+ '30001180': "maximum scoring reached",
+ '30001997': "Authorization canceled by simulation",
+ '30001998': "A technical problem occurred, please try again.",
+ '30001999': "Your merchant's acquirer is temporarily unavailable, please try later or choose another payment method.",
+ '30002001': "Payment refused by the financial institution",
+ '30002001': "Payment refused by the financial institution",
+ '30021001': "Call acquirer support call number.",
+ '30022001': "Payment must be approved by the acquirer before execution.",
+ '30031001': "Invalid merchant number.",
+ '30041001': "Retain card.",
+ '30051001': "Authorization declined",
+ '30071001': "Retain card - special conditions.",
+ '30121001': "Invalid transaction",
+ '30131001': "Invalid amount",
+ '30131002': "You have reached the total amount allowed",
+ '30141001': "Invalid card number",
+ '30151001': "Unknown acquiring institution.",
+ '30171001': "Payment method cancelled by the buyer",
+ '30171002': "The maximum time allowed is elapsed.",
+ '30191001': "Try again later.",
+ '30201001': "A technical problem occurred, please contact helpdesk",
+ '30301001': "Invalid format",
+ '30311001': "Unknown acquirer ID.",
+ '30331001': "Card expired.",
+ '30341001': "Suspicion of fraud.",
+ '30341002': "Suspicion of fraud (3rdMan)",
+ '30341003': "Suspicion of fraud (Perseuss)",
+ '30341004': "Suspicion of fraud (ETHOCA)",
+ '30381001': "A technical problem occurred, please contact helpdesk",
+ '30401001': "Invalid function.",
+ '30411001': "Lost card.",
+ '30431001': "Stolen card, pick up",
+ '30511001': "Insufficient funds.",
+ '30521001': "No Authorization. Contact the issuer of your card.",
+ '30541001': "Card expired.",
+ '30551001': "Invalid PIN.",
+ '30561001': "Card not in authorizer's database.",
+ '30571001': "Transaction not permitted on card.",
+ '30581001': "Transaction not allowed on this terminal",
+ '30591001': "Suspicion of fraud.",
+ '30601001': "The merchant must contact the acquirer.",
+ '30611001': "Amount exceeds card ceiling.",
+ '30621001': "Restricted card.",
+ '30631001': "Security policy not respected.",
+ '30641001': "Amount changed from ref. trn.",
+ '30681001': "Tardy response.",
+ '30751001': "PIN entered incorrectly too often",
+ '30761001': "Card holder already contesting.",
+ '30771001': "PIN entry required.",
+ '30811001': "Message flow error.",
+ '30821001': "Authorization center unavailable",
+ '30831001': "Authorization center unavailable",
+ '30901001': "Temporary system shutdown.",
+ '30911001': "Acquirer unavailable.",
+ '30921001': "Invalid card type for acquirer.",
+ '30941001': "Duplicate transaction",
+ '30961001': "Processing temporarily not possible",
+ '30971001': "A technical problem occurred, please contact helpdesk",
+ '30981001': "A technical problem occurred, please contact helpdesk",
+ '31011001': "Unknown acceptance code",
+ '31021001': "Invalid currency",
+ '31031001': "Acceptance code missing",
+ '31041001': "Inactive card",
+ '31051001': "Merchant not active",
+ '31061001': "Invalid expiration date",
+ '31071001': "Interrupted host communication",
+ '31081001': "Card refused",
+ '31091001': "Invalid password",
+ '31101001': "Plafond transaction (majoré du bonus) dépassé",
+ '31111001': "Plafond mensuel (majoré du bonus) dépassé",
+ '31121001': "Plafond centre de facturation dépassé",
+ '31131001': "Plafond entreprise dépassé",
+ '31141001': "Code MCC du fournisseur non autorisé pour la carte",
+ '31151001': "Numéro SIRET du fournisseur non autorisé pour la carte",
+ '31161001': "This is not a valid online banking account",
+ '32001004': "A technical problem occurred, please try again.",
+ '34011001': "Bezahlung mit RatePAY nicht möglich.",
+ '39991001': "A technical problem occurred, please contact the helpdesk of your acquirer",
+ '40001001': "A technical problem occurred, please try again.",
+ '40001002': "A technical problem occurred, please try again.",
+ '40001003': "A technical problem occurred, please try again.",
+ '40001004': "A technical problem occurred, please try again.",
+ '40001005': "A technical problem occurred, please try again.",
+ '40001006': "A technical problem occurred, please try again.",
+ '40001007': "A technical problem occurred, please try again.",
+ '40001008': "A technical problem occurred, please try again.",
+ '40001009': "A technical problem occurred, please try again.",
+ '40001010': "A technical problem occurred, please try again.",
+ '40001011': "A technical problem occurred, please contact helpdesk",
+ '40001012': "Your merchant's acquirer is temporarily unavailable, please try later or choose another payment method.",
+ '40001013': "A technical problem occurred, please contact helpdesk",
+ '40001016': "A technical problem occurred, please contact helpdesk",
+ '40001018': "A technical problem occurred, please try again.",
+ '40001019': "Sorry, an error occurred during processing. Please retry the operation (use back button of the browser). If problem persists, contact your merchant's helpdesk.",
+ '40001020': "Sorry, an error occurred during processing. Please retry the operation (use back button of the browser). If problem persists, contact your merchant's helpdesk.",
+ '40001050': "A technical problem occurred, please contact helpdesk",
+ '40001133': "Authentication failed, the signature of your bank access control server is incorrect",
+ '40001134': "Authentication failed, please retry or cancel.",
+ '40001135': "Authentication temporary unavailable, please retry or cancel.",
+ '40001136': "Technical problem with your browser, please retry or cancel",
+ '40001137': "Your bank access control server is temporary unavailable, please retry or cancel",
+ '40001998': "Temporary technical problem. Please retry a little bit later.",
+ '50001001': "Unknown card type",
+ '50001002': "Card number format check failed for given card number.",
+ '50001003': "Merchant data error",
+ '50001004': "Merchant identification missing",
+ '50001005': "Expiry date error",
+ '50001006': "Amount is not a number",
+ '50001007': "A technical problem occurred, please contact helpdesk",
+ '50001008': "A technical problem occurred, please contact helpdesk",
+ '50001009': "A technical problem occurred, please contact helpdesk",
+ '50001010': "A technical problem occurred, please contact helpdesk",
+ '50001011': "Brand not supported for that merchant",
+ '50001012': "A technical problem occurred, please contact helpdesk",
+ '50001013': "A technical problem occurred, please contact helpdesk",
+ '50001014': "A technical problem occurred, please contact helpdesk",
+ '50001015': "Invalid currency code",
+ '50001016': "A technical problem occurred, please contact helpdesk",
+ '50001017': "A technical problem occurred, please contact helpdesk",
+ '50001018': "A technical problem occurred, please contact helpdesk",
+ '50001019': "A technical problem occurred, please contact helpdesk",
+ '50001020': "A technical problem occurred, please contact helpdesk",
+ '50001021': "A technical problem occurred, please contact helpdesk",
+ '50001022': "A technical problem occurred, please contact helpdesk",
+ '50001023': "A technical problem occurred, please contact helpdesk",
+ '50001024': "A technical problem occurred, please contact helpdesk",
+ '50001025': "A technical problem occurred, please contact helpdesk",
+ '50001026': "A technical problem occurred, please contact helpdesk",
+ '50001027': "A technical problem occurred, please contact helpdesk",
+ '50001028': "A technical problem occurred, please contact helpdesk",
+ '50001029': "A technical problem occurred, please contact helpdesk",
+ '50001030': "A technical problem occurred, please contact helpdesk",
+ '50001031': "A technical problem occurred, please contact helpdesk",
+ '50001032': "A technical problem occurred, please contact helpdesk",
+ '50001033': "A technical problem occurred, please contact helpdesk",
+ '50001034': "A technical problem occurred, please contact helpdesk",
+ '50001035': "A technical problem occurred, please contact helpdesk",
+ '50001036': "Card length does not correspond to an acceptable value for the brand",
+ '50001037': "Purchasing card number for a regular merchant",
+ '50001038': "Non Purchasing card for a Purchasing card merchant",
+ '50001039': "Details sent for a non-Purchasing card merchant, please contact helpdesk",
+ '50001040': "Details not sent for a Purchasing card transaction, please contact helpdesk",
+ '50001041': "Payment detail validation failed",
+ '50001042': "Given transactions amounts (tax,discount,shipping,net,etc…) do not compute correctly together",
+ '50001043': "A technical problem occurred, please contact helpdesk",
+ '50001044': "No acquirer configured for this operation",
+ '50001045': "No UID configured for this operation",
+ '50001046': "Operation not allowed for the merchant",
+ '50001047': "A technical problem occurred, please contact helpdesk",
+ '50001048': "A technical problem occurred, please contact helpdesk",
+ '50001049': "A technical problem occurred, please contact helpdesk",
+ '50001050': "A technical problem occurred, please contact helpdesk",
+ '50001051': "A technical problem occurred, please contact helpdesk",
+ '50001052': "A technical problem occurred, please contact helpdesk",
+ '50001053': "A technical problem occurred, please contact helpdesk",
+ '50001054': "Card number incorrect or incompatible",
+ '50001055': "A technical problem occurred, please contact helpdesk",
+ '50001056': "A technical problem occurred, please contact helpdesk",
+ '50001057': "A technical problem occurred, please contact helpdesk",
+ '50001058': "A technical problem occurred, please contact helpdesk",
+ '50001059': "A technical problem occurred, please contact helpdesk",
+ '50001060': "A technical problem occurred, please contact helpdesk",
+ '50001061': "A technical problem occurred, please contact helpdesk",
+ '50001062': "A technical problem occurred, please contact helpdesk",
+ '50001063': "Card Issue Number does not correspond to range or not present",
+ '50001064': "Start Date not valid or not present",
+ '50001066': "Format of CVC code invalid",
+ '50001067': "The merchant is not enrolled for 3D-Secure",
+ '50001068': "The card number or account number (PAN) is invalid",
+ '50001069': "Invalid check for CardID and Brand",
+ '50001070': "The ECI value given is either not supported, or in conflict with other data in the transaction",
+ '50001071': "Incomplete TRN demat",
+ '50001072': "Incomplete PAY demat",
+ '50001073': "No demat APP",
+ '50001074': "Authorisation too old",
+ '50001075': "VERRes was an error message",
+ '50001076': "DCP amount greater than authorisation amount",
+ '50001077': "Details negative amount",
+ '50001078': "Details negative quantity",
+ '50001079': "Could not decode/decompress received PARes (3D-Secure)",
+ '50001080': "Received PARes was an erereor message from ACS (3D-Secure)",
+ '50001081': "Received PARes format was invalid according to the 3DS specifications (3D-Secure)",
+ '50001082': "PAReq/PARes reconciliation failure (3D-Secure)",
+ '50001084': "Maximum amount reached",
+ '50001087': "The transaction type requires authentication, please check with your bank.",
+ '50001090': "CVC missing at input, but CVC check asked",
+ '50001091': "ZIP missing at input, but ZIP check asked",
+ '50001092': "Address missing at input, but Address check asked",
+ '50001095': "Invalid date of birth",
+ '50001096': "Invalid commodity code",
+ '50001097': "The requested currency and brand are incompatible.",
+ '50001111': "Data validation error",
+ '50001113': "This order has already been processed",
+ '50001114': "Error pre-payment check page access",
+ '50001115': "Request not received in secure mode",
+ '50001116': "Unknown IP address origin",
+ '50001117': "NO IP address origin",
+ '50001118': "Pspid not found or not correct",
+ '50001119': "Password incorrect or disabled due to numbers of errors",
+ '50001120': "Invalid currency",
+ '50001121': "Invalid number of decimals for the currency",
+ '50001122': "Currency not accepted by the merchant",
+ '50001123': "Card type not active",
+ '50001124': "Number of lines don't match with number of payments",
+ '50001125': "Format validation error",
+ '50001126': "Overflow in data capture requests for the original order",
+ '50001127': "The original order is not in a correct status",
+ '50001128': "missing authorization code for unauthorized order",
+ '50001129': "Overflow in refunds requests",
+ '50001130': "Error access to original order",
+ '50001131': "Error access to original history item",
+ '50001132': "The Selected Catalog is empty",
+ '50001133': "Duplicate request",
+ '50001134': "Authentication failed, please retry or cancel.",
+ '50001135': "Authentication temporary unavailable, please retry or cancel.",
+ '50001136': "Technical problem with your browser, please retry or cancel",
+ '50001137': "Your bank access control server is temporary unavailable, please retry or cancel",
+ '50001150': "Fraud Detection, Technical error (IP not valid)",
+ '50001151': "Fraud detection : technical error (IPCTY unknown or error)",
+ '50001152': "Fraud detection : technical error (CCCTY unknown or error)",
+ '50001153': "Overflow in redo-authorisation requests",
+ '50001170': "Dynamic BIN check failed",
+ '50001171': "Dynamic country check failed",
+ '50001172': "Error in Amadeus signature",
+ '50001174': "Card Holder Name is too long",
+ '50001175': "Name contains invalid characters",
+ '50001176': "Card number is too long",
+ '50001177': "Card number contains non-numeric info",
+ '50001178': "Card Number Empty",
+ '50001179': "CVC too long",
+ '50001180': "CVC contains non-numeric info",
+ '50001181': "Expiration date contains non-numeric info",
+ '50001182': "Invalid expiration month",
+ '50001183': "Expiration date must be in the future",
+ '50001184': "SHA Mismatch",
+ '50001205': "Missing mandatory fields for billing address.",
+ '50001206': "Missing mandatory field date of birth.",
+ '50001207': "Missing required shopping basket details.",
+ '50001208': "Missing social security number",
+ '50001209': "Invalid country code",
+ '50001210': "Missing yearly salary",
+ '50001211': "Missing gender",
+ '50001212': "Missing email",
+ '50001213': "Missing IP address",
+ '50001214': "Missing part payment campaign ID",
+ '50001215': "Missing invoice number",
+ '50001216': "The alias must be different than the card number",
+ '60000001': "account number unknown",
+ '60000003': "not credited dd-mm-yy",
+ '60000005': "name/number do not correspond",
+ '60000007': "account number blocked",
+ '60000008': "specific direct debit block",
+ '60000009': "account number WKA",
+ '60000010': "administrative reason",
+ '60000011': "account number expired",
+ '60000012': "no direct debit authorisation given",
+ '60000013': "debit not approved",
+ '60000014': "double payment",
+ '60000018': "name/address/city not entered",
+ '60001001': "no original direct debit for revocation",
+ '60001002': "payer’s account number format error",
+ '60001004': "payer’s account at different bank",
+ '60001005': "payee’s account at different bank",
+ '60001006': "payee’s account number format error",
+ '60001007': "payer’s account number blocked",
+ '60001008': "payer’s account number expired",
+ '60001009': "payee’s account number expired",
+ '60001010': "direct debit not possible",
+ '60001011': "creditor payment not possible",
+ '60001012': "payer’s account number unknown WKA-number",
+ '60001013': "payee’s account number unknown WKA-number",
+ '60001014': "impermissible WKA transaction",
+ '60001015': "period for revocation expired",
+ '60001017': "reason for revocation not correct",
+ '60001018': "original run number not numeric",
+ '60001019': "payment ID incorrect",
+ '60001020': "amount not numeric",
+ '60001021': "amount zero not permitted",
+ '60001022': "negative amount not permitted",
+ '60001023': "payer and payee giro account number",
+ '60001025': "processing code (verwerkingscode) incorrect",
+ '60001028': "revocation not permitted",
+ '60001029': "guaranteed direct debit on giro account number",
+ '60001030': "NBC transaction type incorrect",
+ '60001031': "description too large",
+ '60001032': "book account number not issued",
+ '60001034': "book account number incorrect",
+ '60001035': "payer’s account number not numeric",
+ '60001036': "payer’s account number not eleven-proof",
+ '60001037': "payer’s account number not issued",
+ '60001039': "payer’s account number of DNB/BGC/BLA",
+ '60001040': "payee’s account number not numeric",
+ '60001041': "payee’s account number not eleven-proof",
+ '60001042': "payee’s account number not issued",
+ '60001044': "payee’s account number unknown",
+ '60001050': "payee’s name missing",
+ '60001051': "indicate payee’s bank account number instead of 3102",
+ '60001052': "no direct debit contract",
+ '60001053': "amount beyond bounds",
+ '60001054': "selective direct debit block",
+ '60001055': "original run number unknown",
+ '60001057': "payer’s name missing",
+ '60001058': "payee’s account number missing",
+ '60001059': "restore not permitted",
+ '60001060': "bank’s reference (navraaggegeven) missing",
+ '60001061': "BEC/GBK number incorrect",
+ '60001062': "BEC/GBK code incorrect",
+ '60001087': "book account number not numeric",
+ '60001090': "cancelled on request",
+ '60001091': "cancellation order executed",
+ '60001092': "cancelled instead of bended",
+ '60001093': "book account number is a shortened account number",
+ '60001094': "instructing party account number not identical with payer",
+ '60001095': "payee unknown GBK acceptor",
+ '60001097': "instructing party account number not identical with payee",
+ '60001099': "clearing not permitted",
+ '60001101': "payer’s account number not spaces",
+ '60001102': "PAN length not numeric",
+ '60001103': "PAN length outside limits",
+ '60001104': "track number not numeric",
+ '60001105': "track number not valid",
+ '60001106': "PAN sequence number not numeric",
+ '60001107': "domestic PAN not numeric",
+ '60001108': "domestic PAN not eleven-proof",
+ '60001109': "domestic PAN not issued",
+ '60001110': "foreign PAN not numeric",
+ '60001111': "card valid date not numeric",
+ '60001112': "book period number (boekperiodenr) not numeric",
+ '60001113': "transaction number not numeric",
+ '60001114': "transaction time not numeric",
+ '60001115': "transaction no valid time",
+ '60001116': "transaction date not numeric",
+ '60001117': "transaction no valid date",
+ '60001118': "STAN not numeric",
+ '60001119': "instructing party’s name missing",
+ '60001120': "foreign amount (bedrag-vv) not numeric",
+ '60001122': "rate (verrekenkoers) not numeric",
+ '60001125': "number of decimals (aantaldecimalen) incorrect",
+ '60001126': "tariff (tarifering) not B/O/S",
+ '60001127': "domestic costs (kostenbinnenland) not numeric",
+ '60001128': "domestic costs (kostenbinnenland) not higher than zero",
+ '60001129': "foreign costs (kostenbuitenland) not numeric",
+ '60001130': "foreign costs (kostenbuitenland) not higher than zero",
+ '60001131': "domestic costs (kostenbinnenland) not zero",
+ '60001132': "foreign costs (kostenbuitenland) not zero",
+ '60001134': "Euro record not fully filled in",
+ '60001135': "Client currency incorrect",
+ '60001136': "Amount NLG not numeric",
+ '60001137': "Amount NLG not higher than zero",
+ '60001138': "Amount NLG not equal to Amount",
+ '60001139': "Amount NLG incorrectly converted",
+ '60001140': "Amount EUR not numeric",
+ '60001141': "Amount EUR not greater than zero",
+ '60001142': "Amount EUR not equal to Amount",
+ '60001143': "Amount EUR incorrectly converted",
+ '60001144': "Client currency not NLG",
+ '60001145': "rate euro-vv (Koerseuro-vv) not numeric",
+ '60001146': "comma rate euro-vv (Kommakoerseuro-vv) incorrect",
+ '60001147': "acceptgiro distributor not valid",
+ '60001148': "Original run number and/or BRN are missing",
+ '60001149': "Amount/Account number/ BRN different",
+ '60001150': "Direct debit already revoked/restored",
+ '60001151': "Direct debit already reversed/revoked/restored",
+ '60001153': "Payer’s account number not known",
+}
+
+DATA_VALIDATION_ERROR = '50001111'
+
+
+def retryable(error):
+ return error in [
+ '0020001001', '0020001002', '0020001003', '0020001004', '0020001005',
+ '0020001006', '0020001007', '0020001008', '0020001009', '0020001010',
+ '30001010', '30001011', '30001015',
+ '30001057', '30001058',
+ '30001998', '30001999',
+ #'30611001', # amount exceeds card limit
+ '30961001',
+ '40001001', '40001002', '40001003', '40001004', '40001005',
+ '40001006', '40001007', '40001008', '40001009', '40001010',
+ '40001012',
+ '40001018', '40001019', '40001020',
+ '40001134', '40001135', '40001136', '40001137',
+ #'50001174', # cardholder name too long
+ ]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data noupdate="0">
+
+ <record id="payment_acquirer_ogone" model="payment.acquirer">
+ <field name="name">ogone</field>
+ <field name="view_template_id" ref="ogone_acquirer_button"/>
+ <field name="env">test</field>
+ <field name='ogone_pspid'>pinky</field>
+ <field name='ogone_userid'>OOAPI</field>
+ <field name='ogone_password'>R!ci/6Nu8a</field>
+ <field name="ogone_shakey_in">tINY4Yv14789gUix1130</field>
+ <field name="ogone_shakey_out">tINYj885Tfvd4P471464</field>
+ </record>
+
+ </data>
+</openerp>
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import ogone
--- /dev/null
+# -*- coding: utf-'8' "-*-"
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from hashlib import sha1
+import logging
+from lxml import etree, objectify
+from pprint import pformat
+# import requests
+import time
+from urllib import urlencode
+import urllib2
+# import urlparse
+
+from openerp.addons.payment_acquirer.data import ogone
+from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
+from openerp.addons.payment_acquirer_ogone.controllers.main import OgoneController
+from openerp.osv import osv, fields
+from openerp.tools import float_round
+
+_logger = logging.getLogger(__name__)
+
+
+class PaymentAcquirerOgone(osv.Model):
+ _inherit = 'payment.acquirer'
+
+ def _get_ogone_urls(self, cr, uid, ids, name, args, context=None):
+ """ Ogone URLS:
+
+ - standard order: POST address for form-based
+
+ @TDETODO: complete me
+ """
+ res = {}
+ for acquirer in self.browse(cr, uid, ids, context=context):
+ qualif = acquirer.env
+ res[acquirer.id] = {
+ 'ogone_standard_order_url': 'https://secure.ogone.com/ncol/%s/orderstandard.asp' % qualif,
+ 'ogone_direct_order_url': 'https://secure.ogone.com/ncol/%s/orderdirect.asp' % qualif,
+ 'ogone_direct_query_url': 'https://secure.ogone.com/ncol/%s/querydirect.asp' % qualif,
+ 'ogone_afu_agree_url': 'https://secure.ogone.com/ncol/%s/AFU_agree.asp' % qualif,
+ }
+ return res
+
+ _columns = {
+ 'ogone_pspid': fields.char(
+ 'PSPID', required_if_provider='ogone'),
+ 'ogone_userid': fields.char(
+ 'API User id', required_if_provider='ogone'),
+ 'ogone_password': fields.char(
+ 'Password', required_if_provider='ogone'),
+ 'ogone_shakey_in': fields.char(
+ 'SHA Key IN', size=32, required_if_provider='ogone'),
+ 'ogone_shakey_out': fields.char(
+ 'SHA Key OUT', size=32, required_if_provider='ogone'),
+ # store ogone contact URLs -> not necessary IMHO
+ 'ogone_standard_order_url': fields.function(
+ _get_ogone_urls, type='char', multi='_get_ogone_urls',
+ string='Stanrd Order URL (form)'),
+ 'ogone_direct_order_url': fields.function(
+ _get_ogone_urls, type='char', multi='_get_ogone_urls',
+ string='Direct Order URL (2)'),
+ 'ogone_direct_query_url': fields.function(
+ _get_ogone_urls, type='char', multi='_get_ogone_urls',
+ string='Direct Query URL'),
+ 'ogone_afu_agree_url': fields.function(
+ _get_ogone_urls, type='char', multi='_get_ogone_urls',
+ string='AFU Agree URL'),
+ }
+
+ def _ogone_generate_shasign(self, acquirer, inout, values):
+ """ Generate the shasign for incoming or outgoing communications.
+
+ :param browse acquirer: the payment.acquirer browse record. It should
+ have a shakey in shaky out
+ :param string inout: 'in' (openerp contacting ogone) or 'out' (ogone
+ contacting openerp). In this last case only some
+ fields should be contained (see e-Commerce basic)
+ :param dict values: transaction values
+
+ :return string: shasign
+ """
+ assert inout in ('in', 'out')
+ assert acquirer.name == 'ogone'
+ key = getattr(acquirer, 'ogone_shakey_' + inout)
+
+ def filter_key(key):
+ if inout == 'in':
+ return True
+ else:
+ keys = "ORDERID CURRENCY AMOUNT PM ACCEPTANCE STATUS CARDNO ALIAS ED CN TRXDATE PAYID NCERROR BRAND ECI IP COMPLUS".split()
+ return key.upper() in keys
+
+ items = sorted((k.upper(), v) for k, v in values.items())
+ sign = ''.join('%s=%s%s' % (k, v, key) for k, v in items if v and filter_key(k))
+ shasign = sha1(sign).hexdigest()
+ return shasign
+
+ def ogone_form_generate_values(self, cr, uid, id, reference, amount, currency, partner_id=False, partner_values=None, tx_custom_values=None, context=None):
+ if partner_values is None:
+ partner_values = {}
+ base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
+ acquirer = self.browse(cr, uid, id, context=context)
+ partner = None
+ if partner_id:
+ partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
+ tx_values = {
+ 'PSPID': acquirer.ogone_pspid,
+ 'ORDERID': reference,
+ 'AMOUNT': '%d' % int(float_round(amount, 2) * 100),
+ 'CURRENCY': currency and currency.name or 'EUR',
+ 'LANGUAGE': partner and partner.lang or partner_values.get('lang', ''),
+ 'CN': partner and partner.name or partner_values.get('name', ''),
+ 'EMAIL': partner and partner.email or partner_values.get('email', ''),
+ 'OWNERZIP': partner and partner.zip or partner_values.get('zip', ''),
+ 'OWNERADDRESS': partner and ' '.join((partner.street, partner.street2)).strip() or ' '.join((partner_values.get('street', ''), partner_values.get('street2', ''))).strip(),
+ 'OWNERTOWN': partner and partner.city or partner_values.get('city', ''),
+ 'OWNERCTY': partner and partner.country_id and partner.country_id.name or partner_values.get('country_name', ''),
+ 'OWNERTELNO': partner and partner.phone or partner_values.get('phone', ''),
+ 'ACCEPTURL': '%s/%s' % (base_url, OgoneController._accept_url),
+ 'DECLINEURL': '%s/%s' % (base_url, OgoneController._decline_url),
+ 'EXCEPTIONURL': '%s/%s' % (base_url, OgoneController._exception_url),
+ 'CANCELURL': '%s/%s' % (base_url, OgoneController._cancel_url),
+ }
+ if tx_custom_values:
+ tx_values.update(tx_custom_values)
+ shasign = self._ogone_generate_shasign(acquirer, 'in', tx_values)
+ tx_values['SHASIGN'] = shasign
+ return tx_values
+
+
+class PaymentTxOgone(osv.Model):
+ _inherit = 'payment.transaction'
+
+ _columns = {
+ 'ogone_3ds': fields.dummy('3ds Activated'),
+ 'ogone_3ds_html': fields.html('3DS HTML'),
+ 'ogone_feedback_model': fields.char(),
+ 'ogone_feedback_eval': fields.char(),
+ 'ogone_complus': fields.char('Complus'),
+ }
+
+ # --------------------------------------------------
+ # FORM RELATED METHODS
+ # --------------------------------------------------
+
+ def _ogone_form_get_tx_from_shasign_out(self, cr, uid, data, context=None):
+ reference, pay_id, shasign = data.get('orderID'), data.get('PAYID'), data.get('SHASIGN')
+ if not reference or not pay_id or not shasign:
+ error_msg = 'Ogone: received data with missing reference (%s) or pay_id (%s) or shashign (%s)' % (reference, pay_id, shasign)
+ _logger.error(error_msg)
+ raise ValidationError(error_msg)
+
+ # find tx -> @TDENOTE use paytid ?
+ tx_ids = self.pool['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context)
+ if not tx_ids or len(tx_ids) > 1:
+ error_msg = 'Ogone: received data for reference' % (reference)
+ if not tx_ids:
+ error_msg += '; no order found'
+ else:
+ error_msg += '; multiple order found'
+ _logger.error(error_msg)
+ raise ValidationError(error_msg)
+ tx = self.pool['payment.transaction'].browse(cr, uid, tx_ids[0], context=context)
+
+ # verify shasign
+ shasign_check = self.pool['payment.acquirer']._generate_ogone_shasign(tx.acquirer_id, 'out', data)
+ if shasign_check.upper() != shasign.upper():
+ error_msg = 'Ogone: invalid shasign, received %s, computed %s, for data %s' % (shasign, shasign_check, data)
+ _logger.error(error_msg)
+ raise ValidationError(error_msg)
+
+ return tx
+
+ def ogone_form_generate_values(self, cr, uid, id, tx_custom_values=None, context=None):
+ tx = self.browse(cr, uid, id, context=context)
+
+ tx_data = {
+ 'LANGUAGE': tx.partner_lang,
+ 'CN': tx.partner_name,
+ 'EMAIL': tx.partner_email,
+ 'OWNERZIP': tx.partner_zip,
+ 'OWNERADDRESS': tx.partner_address,
+ 'OWNERTOWN': tx.partner_city,
+ 'OWNERCTY': tx.partner_country_id and tx.partner_country_id.name or '',
+ 'OWNERTELNO': tx.partner_phone,
+ }
+ if tx_custom_values:
+ tx_data.update(tx_custom_values)
+ return self.pool['payment.acquirer'].ogone_form_generate_values(
+ cr, uid, tx.acquirer_id.id,
+ tx.reference, tx.amount, tx.currency_id,
+ tx_custom_values=tx_data,
+ context=context
+ )
+
+ def ogone_form_feedback(self, cr, uid, data, context=None):
+ print '-- ogone: ogone_form_feedback'
+ tx = self._ogone_get_tx_from_shasign_out(cr, uid, data, context)
+ if not tx:
+ raise ValidationError('Ogone: feedback: tx not found')
+
+ status = int(data.get('STATUS', '0'))
+ print '\togone: statuts %s' % status
+ if status in [5, 9]:
+ tx.write({'state': 'done'})
+ return True
+ else:
+ error = 'Ogone: feedback error: %(error_str)s\n\n%(error_code)s: %(error_msg)s' % {
+ 'error_str': data.get('NCERROR'),
+ 'error_code': data.get('NCERRORPLUS'),
+ 'error_msg': ogone.OGONE_ERROR_MAP.get(data.get('NCERRORPLUS')),
+ }
+ _logger.info(error)
+ tx.write({'state': 'error', 'state_message': error})
+ return False
+
+ # --------------------------------------------------
+ # S2S RELATED METHODS
+ # --------------------------------------------------
+
+ def ogone_s2s_create_alias(self, cr, uid, id, values, context=None):
+ """ Purpose: create an alias via batch """
+ tx = self.browse(cr, uid, id, context=context)
+ assert tx.type == 'server2server', 'Calling s2s dedicated method for a %s acquirer' % tx.type
+ alias = 'OPENERP-%d-%d' % (tx.partner_id.id, tx.id)
+
+ expiry_date = '%s%s' % (values['expiry_date_mm'], values['expiry_date_yy'][2:])
+ line = 'ADDALIAS;%(alias)s;%(holder_name)s;%(number)s;%(expiry_date)s;%(brand)s;%(pspid)s'
+ line = line % dict(values, alias=alias, expiry_date=expiry_date, pspid=tx.acquirer_id.ogone_pspid)
+
+ tx_data = {
+ 'FILE_REFERENCE': 'OPENERP-NEW-ALIAS-%s' % time.time(), # something unique,
+ 'TRANSACTION_CODE': 'ATR',
+ 'OPERATION': 'SAL',
+ 'NB_PAYMENTS': 1, # even if we do not actually have any payment, ogone want it to not be 0
+ 'FILE': line,
+ 'REPLY_TYPE': 'XML',
+ 'PSPID': tx.acquirer_id.ogone_pspid,
+ 'USERID': tx.acquirer_id.ogone_userid,
+ 'PSWD': tx.acquirer_id.ogone_password,
+ 'PROCESS_MODE': 'CHECKANDPROCESS',
+ }
+
+ request = urllib2.Request(tx.acquirer_id.ogone_afu_agree_url, urlencode(tx_data))
+ result = urllib2.urlopen(request).read()
+
+ try:
+ tree = objectify.fromstring(result)
+ except etree.XMLSyntaxError:
+ _logger.exception('Invalid xml response from ogone')
+ return None
+
+ error_code = error_str = None
+ if hasattr(tree, 'PARAMS_ERROR'):
+ error_code = tree.NCERROR.text
+ error_str = 'PARAMS ERROR: %s' % (tree.PARAMS_ERROR.text or '',)
+ else:
+ node = tree.FORMAT_CHECK
+ error_node = getattr(node, 'FORMAT_CHECK_ERROR', None)
+ if error_node is not None:
+ error_code = error_node.NCERROR.text
+ error_str = 'CHECK ERROR: %s' % (error_node.ERROR.text or '',)
+
+ if error_code:
+ error_msg = ogone.OGONE_ERROR_MAP.get(error_code)
+ error = '%s\n\n%s: %s' % (error_str, error_code, error_msg)
+ _logger.error(error)
+ raise Exception(error) # TODO specific exception
+
+ tx.write({'partner_reference': alias})
+ return True
+
+ def ogone_s2s_generate_values(self, cr, uid, id, custom_values, context=None):
+ tx = self.browse(cr, uid, id, context=context)
+ tx_data = {
+ 'PSPID': tx.acquirer_id.ogone_pspid,
+ 'USERID': tx.acquirer_id.ogone_userid,
+ 'PSWD': tx.acquirer_id.ogone_password,
+ 'OrderID': tx.reference,
+ 'amount': '%d' % int(float_round(tx.amount, 2) * 100), # tde check amount or str * 100 ?
+ 'CURRENCY': tx.currency_id.name,
+ 'LANGUAGE': tx.partner_lang,
+ 'OPERATION': 'SAL',
+ 'ECI': 2, # Recurring (from MOTO)
+ 'ALIAS': tx.partner_reference,
+ 'RTIMEOUT': 30,
+ }
+ if custom_values.get('ogone_cvc'):
+ tx_data['CVC'] = custom_values.get('ogone_cvc')
+ if custom_values.pop('ogone_3ds', None):
+ tx_data.update({
+ 'FLAG3D': 'Y', # YEAH!!
+ })
+ if custom_values.get('ogone_complus'):
+ tx_data['COMPLUS'] = custom_values.get('ogone_complus')
+ if custom_values.get('ogone_accept_url'):
+ pass
+
+ shasign = self.pool['payment.acquirer']._ogone_generate_shasign(tx.acquirer_id, 'in', tx_data)
+ tx_data['SHASIGN'] = shasign
+ return tx_data
+
+ def ogone_s2s_execute(self, cr, uid, id, values, context=None):
+ tx = self.browse(cr, uid, id, context=context)
+
+ tx_data = self.ogone_s2s_generate_values(cr, uid, id, values, context=context)
+ _logger.info('Generated Ogone s2s data %s', pformat(tx_data)) # debug
+
+ request = urllib2.Request(tx.acquirer_id.ogone_direct_order_url, urlencode(tx_data))
+ result = urllib2.urlopen(request).read()
+ _logger.info('Contacted Ogone direct order; result %s', result) # debug
+
+ tree = objectify.fromstring(result)
+ payid = tree.get('PAYID')
+ print 'payid', payid
+
+ query_direct_data = dict(
+ PSPID=tx.acquirer_id.ogone_pspid,
+ USERID=tx.acquirer_id.ogone_userid,
+ PSWD=tx.acquirer_id.ogone_password,
+ ID=payid,
+ )
+ query_direct_url = 'https://secure.ogone.com/ncol/%s/querydirect.asp' % (tx.acquirer_id.env,)
+
+ tries = 2
+ tx_done = False
+ tx_status = False
+ while not tx_done or tries > 0:
+ try:
+ tree = objectify.fromstring(result)
+ except etree.XMLSyntaxError:
+ # invalid response from ogone
+ _logger.exception('Invalid xml response from ogone')
+ raise
+
+ # see https://secure.ogone.com/ncol/paymentinfos1.asp
+ VALID_TX = [5, 9]
+ WAIT_TX = [41, 50, 51, 52, 55, 56, 91, 92, 99]
+ PENDING_TX = [46] # 3DS HTML response
+ # other status are errors...
+
+ status = tree.get('STATUS')
+ if status == '':
+ status = None
+ else:
+ status = int(status)
+
+ if status in VALID_TX:
+ tx_status = True
+ tx_done = True
+
+ elif status in PENDING_TX:
+ html = str(tree.HTML_ANSWER)
+ tx_data.update(ogone_3ds_html=html.decode('base64'))
+ tx_status = False
+ tx_done = True
+
+ elif status in WAIT_TX:
+ time.sleep(1500)
+
+ request = urllib2.Request(query_direct_url, urlencode(query_direct_data))
+ result = urllib2.urlopen(request).read()
+ _logger.debug('Contacted Ogone query direct; result %s', result)
+
+ else:
+ error_code = tree.get('NCERROR')
+ if not ogone.retryable(error_code):
+ error_str = tree.get('NCERRORPLUS')
+ error_msg = ogone.OGONE_ERROR_MAP.get(error_code)
+ error = 'ERROR: %s\n\n%s: %s' % (error_str, error_code, error_msg)
+ _logger.info(error)
+ raise Exception(error)
+
+ tries = tries - 1
+
+ if not tx_done and tries == 0:
+ raise Exception('Cannot get transaction status...')
+
+ return (tx_status, orderid, payid)
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from . import test_ogone
+
+checks = [
+ test_ogone,
+]
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.addons.payment_acquirer.tests.common import PaymentAcquirerCommon
+from openerp.addons.payment_acquirer_ogone.controllers.main import OgoneController
+# from openerp.osv.orm import except_orm
+
+from lxml import objectify
+# import requests
+# import urlparse
+
+
+class BasicPayment(PaymentAcquirerCommon):
+
+ def test_20_ogone_form(self):
+ cr, uid = self.cr, self.uid
+ context = {}
+ base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url')
+ # ogone_url = self.payment_acquirer._get_ogone_urls(cr, uid, [ogone_id], None, None)[ogone_id]['ogone_standard_order_url']
+
+ model, ogone_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_ogone', 'ogone_acquirer_button')
+
+ # create a new ogone account
+ ogone_id = self.payment_acquirer.create(
+ cr, uid, {
+ 'name': 'ogone',
+ 'env': 'test',
+ 'view_template_id': ogone_view_id,
+ 'ogone_pspid': 'pinky',
+ 'ogone_userid': 'OOAPI',
+ 'ogone_password': 'R!ci/6Nu8a',
+ 'ogone_shakey_in': 'tINY4Yv14789gUix1130',
+ 'ogone_shakey_out': 'tINYj885Tfvd4P471464',
+ }, context=context
+ )
+ # verify acquirer data
+ ogone = self.payment_acquirer.browse(cr, uid, ogone_id, context)
+ self.assertEqual(ogone.env, 'test', 'test without test env')
+
+ form_values = {
+ 'PSPID': 'pinky',
+ 'ORDERID': 'test_ref0',
+ 'AMOUNT': '1',
+ 'CURRENCY': 'EUR',
+ 'LANGUAGE': 'en_US',
+ 'CN': 'Norbert Buyer',
+ 'EMAIL': 'norbert.buyer@example.com',
+ 'OWNERZIP': '1000',
+ 'OWNERADDRESS': 'Huge Street 2/543',
+ 'OWNERCTY': 'Belgium',
+ 'OWNERTOWN': 'Sin City',
+ 'OWNERTELNO': '0032 12 34 56 78',
+ 'SHASIGN': 'ea74bb42d4f25746279cdd44a737aaddc71e7f9f',
+ 'ACCEPTURL': '%s/%s' % (base_url, OgoneController._accept_url),
+ 'DECLINEURL': '%s/%s' % (base_url, OgoneController._decline_url),
+ 'EXCEPTIONURL': '%s/%s' % (base_url, OgoneController._exception_url),
+ 'CANCELURL': '%s/%s' % (base_url, OgoneController._cancel_url),
+ }
+
+ # render the button
+ res = self.payment_acquirer.render(
+ cr, uid, ogone_id,
+ 'test_ref0', 0.01, self.currency_euro,
+ partner_id=None,
+ partner_values=self.buyer_values,
+ context=context)
+ # check form result
+ tree = objectify.fromstring(res)
+ self.assertEqual(tree.get('action'), 'https://secure.ogone.com/ncol/test/orderstandard.asp', 'ogone: wrong form POST url')
+ for form_input in tree.input:
+ if form_input.get('name') in ['submit']:
+ continue
+ self.assertEqual(
+ form_input.get('value'),
+ form_values[form_input.get('name')],
+ 'ogone: wrong value for form: received %s instead of %s' % (form_input.get('value'), form_values[form_input.get('name')])
+ )
+ # resp = requests.post(tree.get('action'), data=form_values)
+
+ # create a new draft tx
+ tx_id = self.payment_transaction.create(
+ cr, uid, {
+ 'amount': 0.01,
+ 'acquirer_id': ogone_id,
+ 'currency_id': self.currency_euro_id,
+ 'reference': 'test_ref0',
+ 'partner_id': self.buyer_id,
+ }, context=context
+ )
+ # render the button
+ res = self.payment_acquirer.render(
+ cr, uid, ogone_id,
+ 'test_ref0', 0.01, self.currency_euro,
+ tx_id=tx_id,
+ partner_id=None,
+ partner_values=self.buyer_values,
+ context=context)
+ # check form result
+ tree = objectify.fromstring(res)
+ self.assertEqual(tree.get('action'), 'https://secure.ogone.com/ncol/test/orderstandard.asp', 'ogone: wrong form POST url')
+ for form_input in tree.input:
+ if form_input.get('name') in ['submit']:
+ continue
+ self.assertEqual(
+ form_input.get('value'),
+ form_values[form_input.get('name')],
+ 'ogone: wrong value for form input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')])
+ )
+
+ def test_21_ogone_s2s(self):
+ cr, uid = self.cr, self.uid
+ context = {}
+
+ model, ogone_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_ogone', 'ogone_acquirer_button')
+
+ # create a new ogone account
+ ogone_id = self.payment_acquirer.create(
+ cr, uid, {
+ 'name': 'ogone',
+ 'env': 'test',
+ 'view_template_id': ogone_view_id,
+ 'ogone_pspid': 'pinky',
+ 'ogone_userid': 'OOAPI',
+ 'ogone_password': 'R!ci/6Nu8a',
+ 'ogone_shakey_in': 'tINY4Yv14789gUix1130',
+ 'ogone_shakey_out': 'tINYj885Tfvd4P471464',
+ }, context=context
+ )
+
+ # create a new draft tx
+ tx_id = self.payment_transaction.create(
+ cr, uid, {
+ 'amount': 0.01,
+ 'acquirer_id': ogone_id,
+ 'currency_id': self.currency_euro_id,
+ 'reference': 'test_ogone_0',
+ 'partner_id': self.buyer_id,
+ 'type': 'server2server',
+ }, context=context
+ )
+
+ res = self.payment_transaction.ogone_s2s_create_alias(
+ cr, uid, tx_id, {
+ 'expiry_date_mm': '01',
+ 'expiry_date_yy': '2015',
+ 'holder_name': 'Norbert Poilu',
+ 'number': '4000000000000002',
+ 'brand': 'VISA',
+ }, context=context)
+ print res
+
+ res = self.payment_transaction.ogone_s2s_execute(cr, uid, tx_id, {}, context=context)
+ print res
+
+
+# {
+# 'orderID': u'reference',
+# 'STATUS': u'9',
+# 'CARDNO': u'XXXXXXXXXXXX0002',
+# 'PAYID': u'24998692',
+# 'CN': u'Norbert Poilu',
+# 'NCERROR': u'0',
+# 'TRXDATE': u'11/05/13',
+# 'IP': u'85.201.233.72',
+# 'BRAND': u'VISA',
+# 'ACCEPTANCE': u'test123',
+# 'currency': u'EUR',
+# 'amount': u'1.95',
+# 'SHASIGN': u'EFDC56879EF7DE72CCF4B397076B5C9A844CB0FA',
+# 'ED': u'0314',
+# 'PM': u'CreditCard'
+# }
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data noupdate="0">
+
+ <template id="ogone_acquirer_button">
+ <form t-if="acquirer" t-att-action="acquirer.ogone_standard_order_url" method="post" target="_self">
+ <!-- seller -->
+ <input type='hidden' name='PSPID' t-att-value='tx_values["PSPID"]'/>
+ <input type='hidden' name='ORDERID' t-att-value='tx_values["ORDERID"]'/>
+ <!-- cart -->
+ <input type='hidden' name='AMOUNT' t-att-value='tx_values["AMOUNT"]'/>
+ <input type='hidden' name='CURRENCY' t-att-value='tx_values["CURRENCY"]'/>
+ <!-- buyer -->
+ <input type='hidden' name='LANGUAGE' t-att-value='tx_values["LANGUAGE"]'/>
+ <input type='hidden' name='CN' t-att-value='tx_values["CN"]'/>
+ <input type='hidden' name='EMAIL' t-att-value='tx_values["EMAIL"]'/>
+ <input type='hidden' name='OWNERZIP' t-att-value='tx_values["OWNERZIP"]'/>
+ <input type='hidden' name='OWNERADDRESS' t-att-value='tx_values["OWNERADDRESS"]'/>
+ <input type='hidden' name='OWNERCTY' t-att-value='tx_values["OWNERCTY"]'/>
+ <input type='hidden' name='OWNERTOWN' t-att-value='tx_values["OWNERTOWN"]'/>
+ <input type='hidden' name='OWNERTELNO' t-att-value='tx_values["OWNERTELNO"]'/>
+ <!-- before payment verification -->
+ <input type='hidden' name='SHASIGN' t-att-value='tx_values["SHASIGN"]'/>
+ <!-- look and print -->
+ <!-- <input type='hidden' name='TITLE' t-att-value='tx_dict["currency_name"]'/>
+ <input type='hidden' name='BGCOLOR' t-att-value='tx_dict["currency_name"]'/>
+ <input type='hidden' name='TXTCOLOR' t-att-value='tx_dict["currency_name"]'/>
+ <input type='hidden' name='TBLBGCOLOR' t-att-value='tx_dict["currency_name"]'/>
+ <input type='hidden' name='TBLTXTCOLOR' t-att-value='tx_dict["currency_name"]'/>
+ <input type='hidden' name='BUTTONBGCOLOR' t-att-value='tx_dict["currency_name"]'/>
+ <input type='hidden' name='BUTTONTXTCOLOR' t-att-value='tx_dict["currency_name"]'/>
+ <input type='hidden' name='LOGO' t-att-value='tx_dict["currency_name"]'/>
+ <input type='hidden' name='FONTTYPE' t-att-value='tx_dict["currency_name"]'/> -->
+ <!-- redirection -->
+ <input type='hidden' name='ACCEPTURL' t-att-value='tx_values["ACCEPTURL"]'/>
+ <input type='hidden' name='DECLINEURL' t-att-value='tx_values["DECLINEURL"]'/>
+ <input type='hidden' name='EXCEPTIONURL' t-att-value='tx_values["EXCEPTIONURL"]'/>
+ <input type='hidden' name='CANCELURL' t-att-value='tx_values["CANCELURL"]'/>
+ <input type="image" name="submit" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
+ </form>
+ </template>
+
+ </data>
+</openerp>
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import models
+import controllers
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+{
+ 'name': 'Paypal Payment Acquirer',
+ 'category': 'Hidden',
+ 'summary': 'Paypal Payment Acquirer',
+ 'version': '0.1',
+ 'description': """Paypal Payment Acquirer""",
+ 'author': 'OpenERP SA',
+ 'depends': ['payment_acquirer'],
+ 'data': [
+ 'views/paypal.xml',
+ 'data/paypal.xml',
+ ],
+ 'installable': True,
+}
--- /dev/null
+import main
\ No newline at end of file
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.addons.web import http
+from openerp.addons.web.http import request
+# from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
+from openerp.addons.website.models import website
+
+import logging
+import requests
+from urllib import urlencode
+
+_logger = logging.getLogger(__name__)
+
+
+class PaypalController(http.Controller):
+ _notify_url = '/payment/paypal/ipn/'
+ _return_url = '/payment/paypal/dpn/'
+ _cancel_url = '/payment/paypal/cancel/'
+ # _ipn_url2 = '/payment/paypal/<int:acquirer_id>/ipn/'
+
+ @website.route('/payment/paypal/<int:acquirer_id>/ipn/', type='http', auth='admin')
+ def paypal_ipn(self, **post):
+ print 'Entering paypal_ipn with post', post
+ # step 1: return an empty HTTP 200 response -> will be done at the end by returning ''
+
+ # step 2: POST the complete, unaltered message back to Paypal (preceded by cmd=_notify-validate), with same encoding
+ paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"
+ post_url = '%s?cmd=_notify-validate&%s' % (paypal_url, urlencode(post))
+ resp = requests.post(post_url)
+ print '\tReceived response', resp, resp.text
+
+ # step 3: paypal send either VERIFIED or INVALID (single word)
+ if resp.text == 'VERIFIED':
+ # _logger.warning('')
+ cr, uid, context = request.cr, request.uid, request.context
+ # payment_transaction = request.registry['payment.transaction']
+ # payment_transaction.validate()
+ elif resp.text == 'INVALID':
+ # _logger.warning('')
+ pass
+ else:
+ # _logger.warning('') -> something went wrong
+ pass
+
+ return ''
+
+ @website.route([
+ '/payment/paypal/test/dpn',
+ ], type='http', auth="public")
+ def paypal_test_success(self, **post):
+ """ TODO
+ """
+ cr, uid, context = request.cr, request.uid, request.context
+ print post
+ return ''
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data noupdate="0">
+
+ <record id="payment_acquirer_paypal" model="payment.acquirer">
+ <field name="name">paypal</field>
+ <field name="view_template_id" ref="paypal_acquirer_button"/>
+ <field name="env">test</field>
+ <field name="paypal_tx_url">https://www.sandbox.paypal.com/cgi-bin/webscr</field>
+ <field name="paypal_email_id">tde+paypal-facilitator@openerp.com</field>
+ <field name="paypal_username">'tde+paypal-facilitator_api1.openerp.com</field>
+ </record>
+
+ </data>
+</openerp>
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import paypal
--- /dev/null
+# -*- coding: utf-'8' "-*-"
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
+from openerp.addons.payment_acquirer_paypal.controllers.main import PaypalController
+from openerp.osv import osv, fields
+
+import logging
+import requests
+import urlparse
+
+_logger = logging.getLogger(__name__)
+
+
+class AcquirerPaypal(osv.Model):
+ _inherit = 'payment.acquirer'
+
+ _columns = {
+ 'paypal_email_id': fields.char('Email ID', required_if_provider='paypal'),
+ 'paypal_username': fields.char('Username', required_if_provider='paypal'),
+ 'paypal_password': fields.char('Password'),
+ 'paypal_signature': fields.char('Signature'),
+ 'paypal_tx_url': fields.char('Transaction URL', required_if_provider='paypal'),
+ 'paypal_use_dpn': fields.boolean('Use DPN'),
+ 'paypal_use_ipn': fields.boolean('Use IPN'),
+ }
+
+ _defaults = {
+ 'paypal_use_dpn': True,
+ 'paypal_use_ipn': True,
+ 'paypal_tx_url': 'https://www.sandbox.paypal.com/cgi-bin/webscr',
+ }
+
+ def paypal_form_generate_values(self, cr, uid, id, reference, amount, currency, partner_id=False, partner_values=None, tx_custom_values=None, context=None):
+ if partner_values is None:
+ partner_values = {}
+ base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
+ acquirer = self.browse(cr, uid, id, context=context)
+ partner = None
+ if partner_id:
+ partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
+ tx_values = {
+ 'cmd': '_xclick',
+ 'business': acquirer.paypal_email_id,
+ 'item_name': reference,
+ 'item_number': reference,
+ 'amount': amount,
+ 'currency_code': currency and currency.name or 'EUR',
+ 'address1': partner and ' '.join((partner.street, partner.street2)).strip() or ' '.join((partner_values.get('street', ''), partner_values.get('street2', ''))).strip(),
+ 'city': partner and partner.city or partner_values.get('city', ''),
+ 'country': partner and partner.country_id and partner.country_id.name or partner_values.get('country_name', ''),
+ 'email': partner and partner.email or partner_values.get('email', ''),
+ 'zip': partner and partner.zip or partner_values.get('zip', ''),
+ 'first_name': partner and partner.name or partner_values.get('name', '').split()[-1:],
+ 'last_name': partner and partner.name or partner_values.get('name', '').split()[:-1],
+ 'return': '%s/%s' % (base_url, PaypalController._return_url),
+ 'notify_url': '%s/%s' % (base_url, PaypalController._notify_url),
+ 'cancel_return': '%s/%s' % (base_url, PaypalController._cancel_url),
+ }
+ if tx_custom_values:
+ tx_values.update(tx_custom_values)
+ return tx_values
+
+
+class TxPaypal(osv.Model):
+ _inherit = 'payment.transaction'
+
+ _columns = {
+ 'paypal_txn_id': fields.char('Transaction ID'),
+ }
+
+ # --------------------------------------------------
+ # FORM RELATED METHODS
+ # --------------------------------------------------
+
+ def paypal_form_generate_values(self, cr, uid, id, tx_custom_values=None, context=None):
+ tx = self.browse(cr, uid, id, context=context)
+
+ tx_data = {
+ 'item_name': tx.name,
+ 'first_name': tx.partner_name and tx.partner_name.split()[-1:],
+ 'last_name': tx.partner_name and tx.partner_name.split()[:-1],
+ 'email': tx.partner_email,
+ 'zip': tx.partner_zip,
+ 'address1': tx.partner_address,
+ 'city': tx.partner_city,
+ 'country': tx.partner_country_id and tx.partner_country_id.name or '',
+ }
+ if tx_custom_values:
+ tx_data.update(tx_custom_values)
+ return self.pool['payment.acquirer'].paypal_form_generate_values(
+ cr, uid, tx.acquirer_id.id,
+ tx.reference, tx.amount, tx.currency_id,
+ tx_custom_values=tx_data,
+ context=context
+ )
+
+
+
+ def validate_paypal_notification(self, cr, uid, url, context=None):
+ parsed_url = urlparse.urlparse(url)
+ query_parameters = parsed_url.query
+ parameters = urlparse.parse_qs(query_parameters)
+
+ invalid_parameters = []
+
+ # check tx effectively exists
+ txn_id = parameters.get('txn_id')[0]
+ tx_ids = self.search(cr, uid, [('paypal_txn_id', '=', txn_id)], context=context)
+ if not tx_ids:
+ _logger.warning(
+ 'Received a notification from Paypal for a tx %s that does not exists in database.' %
+ txn_id
+ )
+ return False
+ elif len(tx_ids) > 1:
+ _logger.warning(
+ 'Received a notification from Paypal for a tx %s that is duplicated in database.' %
+ txn_id
+ )
+
+ tx = self.browse(cr, uid, tx_ids[0], context=context)
+
+ if parameters.get('notify_version')[0] != '2.6':
+ _logger.warning(
+ 'Received a notification from Paypal with version %s instead of 2.6. This could lead to issues when managing it.' %
+ parameters.get('notify_version')
+ )
+ if parameters.get('test_ipn')[0]:
+ _logger.warning(
+ 'Received a notification from Paypal using sandbox'
+ ),
+ # check transaction
+ if parameters.get('payment_status')[0] != 'Completed':
+ invalid_parameters.append(('payment_status', 'Completed'))
+ # check what is buyed
+ if parameters.get('mc_gross')[0] != tx.amount:
+ invalid_parameters.append(('mc_gross', tx.amount))
+ if parameters.get('mc_currency')[0] != tx.currency_id.name:
+ invalid_parameters.append(('mc_currency', tx.currency_id.name))
+ # if parameters.get('payment_fee') != tx.payment_fee:
+ # invalid_parameters.append(('payment_fee', tx.payment_fee))
+ # if parameters.get('quantity') != tx.quantity:
+ # invalid_parameters.append(('mc_currency', tx.quantity))
+ # if parameters.get('shipping') != tx.shipping:
+ # invalid_parameters.append(('shipping', tx.shipping))
+ # check buyer
+ # if parameters.get('payer_id') != tx.payer_id:
+ # invalid_parameters.append(('mc_gross', tx.payer_id))
+ # if parameters.get('payer_email') != tx.payer_email:
+ # invalid_parameters.append(('payer_email', tx.payer_email))
+ # check seller
+ # if parameters.get('receiver_email') != tx.receiver_email:
+ # invalid_parameters.append(('receiver_email', tx.receiver_email))
+ # if parameters.get('receiver_id') != tx.receiver_id:
+ # invalid_parameters.append(('receiver_id', tx.receiver_id))
+
+ if not invalid_parameters:
+ self.write(cr, uid, [tx.id], {
+ 'payment_type': parameters.get('payment_type')[0],
+ 'date_validate': parameters.get('payment_date', [fields.datetime.now()])[0],
+ 'txn_type': parameters.get('express_checkout')[0],
+ }, context=context)
+ return tx.id
+ else:
+ _warn_message = 'The following transaction parameters are incorrect:\n'
+ for item in invalid_parameters:
+ _warn_message += '\t%s: received %s instead of %s\n' % (item[0], parameters.get(item[0])[0], item[1])
+ _logger.warning(_warn_message)
+
+ return False
+
+ def create_paypal_command(self, cr, uid, cmd, parameters):
+ parameters.update(cmd=cmd)
+ return requests.post(self._paypal_url, data=parameters)
+
+ def _validate_paypal(self, cr, uid, ids, context=None):
+ res = []
+ for tx in self.browse(cr, uid, ids, context=context):
+ parameters = {}
+ parameters.update(
+ cmd='_notify-validate',
+ business='tdelavallee-facilitator@gmail.com',
+ item_name="%s %s" % ('cacapoutch', tx.reference),
+ item_number=tx.reference,
+ amount=tx.amount,
+ currency_code=tx.currency_id.name,
+ )
+ print '\t', parameters
+ # paypal_url = "https://www.paypal.com/cgi-bin/webscr"
+ paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"
+ resp = requests.post(paypal_url, data=parameters)
+ print resp
+ print resp.url
+ print resp.text
+ response = urlparse.parse_qsl(resp)
+ print response
+ # transaction's unique id
+ # response["txn_id"]
+
+ # "Failed", "Reversed", "Refunded", "Canceled_Reversal", "Denied"
+ status = "refused"
+ retry_time = False
+
+ if response["payment_status"] == "Voided":
+ status = "refused"
+ elif response["payment_status"] in ("Completed", "Processed") and response["item_number"] == tx.reference and response["mc_gross"] == tx.amount:
+ status = "validated"
+ elif response["payment_status"] in ("Expired", "Pending"):
+ status = "pending"
+ retry_time = 60
+
+ res.append(
+ (status, retry_time, "payment_status=%s&pending_reason=%s&reason_code=%s" % (
+ response["payment_status"],
+ response.get("pending_reason"),
+ response.get("reason_code")))
+ )
+ return response
+
+ def _transaction_feedback_paypal(self, **values):
+ print values
+ return True
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from . import test_paypal
+
+checks = [
+ test_paypal,
+]
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
--- /dev/null
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.addons.payment_acquirer.tests.common import PaymentAcquirerCommon
+from openerp.osv.orm import except_orm
+
+from lxml import objectify
+# import requests
+# import urlparse
+
+
+class BasicPayment(PaymentAcquirerCommon):
+
+ def test_10_paypal_basic(self):
+ pass
+
+ def test_11_paypal_form(self):
+ cr, uid = self.cr, self.uid
+ context = {}
+ base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url')
+ # ogone_url = self.payment_acquirer._get_ogone_urls(cr, uid, [ogone_id], None, None)[ogone_id]['ogone_standard_order_url']
+
+ model, paypal_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_paypal', 'paypal_acquirer_button')
+
+ # forgot some mandatory fields: should crash
+ with self.assertRaises(except_orm):
+ paypal_id = self.payment_acquirer.create(
+ cr, uid, {
+ 'name': 'paypal',
+ 'env': 'test',
+ 'view_template_id': paypal_view_id,
+ 'paypal_email_id': 'tde+paypal-facilitator@openerp.com',
+ }, context=context
+ )
+ # tde+buyer@openerp.com
+
+ # create a new paypal account
+ paypal_id = self.payment_acquirer.create(
+ cr, uid, {
+ 'name': 'paypal',
+ 'env': 'test',
+ 'view_template_id': paypal_view_id,
+ 'paypal_email_id': 'tde+paypal-facilitator@openerp.com',
+ 'paypal_username': 'tde+paypal-facilitator_api1.openerp.com',
+ }, context=context
+ )
+ # verify acquirer data
+ paypal = self.payment_acquirer.browse(cr, uid, paypal_id, context)
+ self.assertEqual(paypal.env, 'test', 'test without test env')
+
+ # render the button
+ res = self.payment_acquirer.render(
+ cr, uid, paypal_id,
+ 'test_ref0', 0.01, self.currency_euro,
+ partner_id=None,
+ partner_values=self.buyer_values,
+ context=context)
+ print res
+
+ # # check some basic paypal methods
+ # res = self.payment_transaction.validate_paypal_notification(
+ # cr, uid,
+ # 'http://localhost/payment?mc_gross=19.95&protection_eligibility=Eligible&address_status=confirmed&payer_id=LPLWNMTBWMFAY&tax=0.00&address_street=1+Main+St&payment_date=20%3A12%3A59+Jan+13%2C+2009+PST&payment_status=Completed&charset=windows-1252&address_zip=95131&first_name=Test&mc_fee=0.88&address_country_code=US&address_name=Test+User¬ify_version=2.6&custom=&payer_status=verified&address_country=United+States&address_city=San+Jose&quantity=1&verify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtf&payer_email=gpmac_1231902590_per%40paypal.com&txn_id=61E67681CH3238416&payment_type=instant&last_name=User&address_state=CA&receiver_email=gpmac_1231902686_biz%40paypal.com&payment_fee=0.88&receiver_id=S8XGHLYDW9T3S&txn_type=express_checkout&item_name=&mc_currency=USD&item_number=&residence_country=US&test_ipn=1&handling_amount=0.00&transaction_subject=&payment_gross=19.95&shipping=0.00')
+ # self.assertEqual(res, False, 'payment: paypal validation on a txn_id that does not exists should return False')
+
+ # txn_id = self.payment_transaction.create(
+ # cr, uid, {
+ # 'amount': 0.01,
+ # 'acquirer_id': paypal_id,
+ # 'currency_id': currency_id,
+ # 'reference': 'test_reference',
+ # 'paypal_txn_id': '61E67681CH3238416',
+ # }, context=context
+ # )
+ # res = self.payment_transaction.validate_paypal_notification(
+ # cr, uid,
+ # 'http://localhost/payment?mc_gross=19.95&protection_eligibility=Eligible&address_status=confirmed&payer_id=LPLWNMTBWMFAY&tax=0.00&address_street=1+Main+St&payment_date=20%3A12%3A59+Jan+13%2C+2009+PST&payment_status=Completed&charset=windows-1252&address_zip=95131&first_name=Test&mc_fee=0.88&address_country_code=US&address_name=Test+User¬ify_version=2.6&custom=&payer_status=verified&address_country=United+States&address_city=San+Jose&quantity=1&verify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtf&payer_email=gpmac_1231902590_per%40paypal.com&txn_id=61E67681CH3238416&payment_type=instant&last_name=User&address_state=CA&receiver_email=gpmac_1231902686_biz%40paypal.com&payment_fee=0.88&receiver_id=S8XGHLYDW9T3S&txn_type=express_checkout&item_name=&mc_currency=USD&item_number=&residence_country=US&test_ipn=1&handling_amount=0.00&transaction_subject=&payment_gross=19.95&shipping=0.00')
+ # print res
+
+ # # user pays using Paypal
+ # resp = self.payment_transaction.create_paypal_command(
+ # cr, uid, cmd='_xclick', parameters={
+ # 'business': 'tdelavallee-facilitator@gmail.com',
+ # 'amount': 50,
+ # 'item_name': 'test_item',
+ # 'quantity': 1,
+ # 'currency_code': 'USD',
+ # 'return': 'http://www.example.com',
+ # })
+ # print resp
+ # print resp.url
+ # print resp.text
+
+ # self.payment_transaction.validate(cr, uid, [tx_id], context=context)
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data noupdate="0">
+
+ <template id="paypal_acquirer_button">
+ <form t-if="acquirer.paypal_email_id" t-att-action="acquirer.paypal_tx_url" method="post" target="_self">
+ <input type="hidden" name="cmd" value="tx_values['cmd']"/>
+ <input type="hidden" name="business" t-att-value="tx_values['business']"/>
+ <input type="hidden" name="item_name" t-attf-value="tx_values['item_name']"/>
+ <input type="hidden" name="item_number" t-att-value="tx_values['item_number']"/>
+ <input type="hidden" name="amount" t-att-value="tx_values['amount']"/>
+ <input type="hidden" name="currency_code" t-att-value="tx_values['currency_code']"/>
+ <!-- partner / address data -->
+ <input type="hidden" name="address1" t-att-value="tx_values['address1']"/>
+ <input type="hidden" name="city" t-att-value="tx_values['city']"/>
+ <input type="hidden" name="country" t-att-value="tx_values['country']"/>
+ <input type="hidden" name="email" t-att-value="tx_values['email']"/>
+ <input type="hidden" name="first_name" t-att-value="tx_values['first_name']"/>
+ <input type="hidden" name="last_name" t-att-value="tx_values['last_name']"/>
+ <input type="hidden" name="zip" t-att-value="tx_values['zip']"/>
+ <!-- URLs -->
+ <input t-if="acquirer.paypal_use_dpn" type='hidden' name='return'
+ t-att-value="tx_values['return']"/>
+ <input t-if="acquirer.paypal_use_ipn" type='hidden' name='notify_url'
+ t-att-value="tx_values['notify_url']"/>
+ <input t-if="tx_values['cancel_return']" type="hidden" name="cancel_return"
+ t-att-value="tx_values['cancel_return']"/>
+ <!-- button -->
+ <input type="image" name="submit" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
+ </form>
+ </template>
+
+ </data>
+</openerp>
'description': """
""",
'author': 'OpenERP SA',
- 'depends': ['website', 'payment_acquirer'],
+ 'depends': ['website', 'payment_acquirer', 'payment_acquirer_ogone', 'payment_acquirer_paypal'],
'data': [
'views/website_payment_templates.xml',
],
<?xml version="1.0" encoding="utf-8"?>
<openerp>
-<data>
+
<!-- Layout add nav and footer -->
- <template id="header_footer_custom" inherit_id="website.layout">
- <xpath expr="//header//ul[@id='top_menu']/li[@name='contactus']" position="before">
- <li><a t-attf-href="/payment/paypal/test">Test (Paypal)</a></li>
- </xpath>
- <xpath expr="//header//ul[@id='top_menu']/li[@name='contactus']" position="before">
- <li><a t-attf-href="/payment/ogone/test">Test (Ogone)</a></li>
- </xpath>
- </template>
+ <data noupdate="0">
+ <record id="menu_paypal_test" model="website.menu">
+ <field name="name">Paypal (Test)</field>
+ <field name="url">/payment/paypal/test</field>
+ <field name="parent_id" ref="website.main_menu"/>
+ <field name="sequence" type="int">50</field>
+ </record>
+ </data>
+ <data noupdate="0">
+ <record id="menu_paypal_ogone" model="website.menu">
+ <field name="name">Ogone (Test)</field>
+ <field name="url">/payment/ogone/test</field>
+ <field name="parent_id" ref="website.main_menu"/>
+ <field name="sequence" type="int">50</field>
+ </record>
+ </data>
<!-- Page -->
- <template id="index_paypal" name="Paypal (Test)" page="True">
- <t t-call="website.layout">
- <div id="wrap">
- <div class="container mt16 js_website_blog">
- <div class="row">
- Paypal payment
- <t t-raw="acquirer_form"/>
+ <data>
+ <template id="index_paypal" name="Paypal (Test)" page="True">
+ <t t-call="website.layout">
+ <div id="wrap">
+ <div class="container mt16 js_website_blog">
+ <div class="row">
+ Paypal payment
+ <t t-raw="acquirer_form"/>
+ </div>
</div>
</div>
- </div>
- </t>
- </template>
+ </t>
+ </template>
- <template id="index_ogone" name="Ogone (Test)" page="True">
- <t t-call="website.layout">
- <div id="wrap">
- <div class="container mt16 js_website_blog">
- <div class="row">
- Ogone payment
- <t t-raw="acquirer_form"/>
+ <template id="index_ogone" name="Ogone (Test)" page="True">
+ <t t-call="website.layout">
+ <div id="wrap">
+ <div class="container mt16 js_website_blog">
+ <div class="row">
+ Ogone payment
+ <t t-raw="acquirer_form"/>
+ </div>
</div>
</div>
- </div>
- </t>
- </template>
+ </t>
+ </template>
+ </data>
-</data>
</openerp>