PK!hhwirecard/__init__.pyfrom .wirecard import AccountHolder, Card, RequestedAmount, Wirecard # noqa F401 __version__ = '0.2.1' PK!Xwirecard/constants.py# Transaction Types CHECK_ENROLLMENT = 'check-enrollment' PURCHASE = 'purchase' # Transaction States SUCCESS = 'success' # Return Codes and Transaction Statuses # https://document-center.wirecard.com/display/PTD/Return+Codes+and+Transaction+Statuses CREATION_SUCCESS_ID = '201.0000' CREATION_SUCCESS = 'Creation Success' CARD_ELIGIBLE_3D_ID = '200.1077' CARD_ELIGIBLE_3D = 'Card/Cardholder eligible for 3-D authentication process' PK!swirecard/exceptions.pyclass WirecardFailedInit(Exception): pass class WirecardInvalidCard(Exception): pass class WirecardInvalidRequestedAmount(Exception): pass class WirecardFailedTransaction(Exception): def __init__(self, transaction_id, action, statuses): self.transaction_id = transaction_id self.action = action self.statuses = statuses super().__init__(transaction_id, action, statuses) PK!@@wirecard/wirecard.pyfrom base64 import b64encode from decimal import Decimal import os import uuid from glom import glom import requests from .constants import ( CARD_ELIGIBLE_3D_ID, CHECK_ENROLLMENT, CREATION_SUCCESS_ID, PURCHASE, SUCCESS, ) from .exceptions import ( WirecardFailedInit, WirecardFailedTransaction, WirecardInvalidCard, WirecardInvalidRequestedAmount, ) class Wirecard: def __init__(self, username=None, password=None, merchant_account_id=None, url=None): self.username = os.getenv('WIRECARD_USERNAME', username) self.password = os.getenv('WIRECARD_PASSWORD', password) self.merchant_account_id = os.getenv('WIRECARD_MERCHANT_ACCOUNT_ID', merchant_account_id) self.url = os.getenv('WIRECARD_API_URL', url) self.basic_authorization = None self.validate() def check_3d_enrollment(self, card, account_holder, requested_amount): data = { 'payment': { 'merchant-account-id': { 'value': self.merchant_account_id, }, 'request-id': self._generate_request_id(), 'transaction-type': CHECK_ENROLLMENT, 'requested-amount': requested_amount.as_dict(), 'account-holder': account_holder.as_dict(), 'card': card.as_dict(), }, } headers = self._make_headers() result = requests.post(self.url, json=data, headers=headers) response = result.json() statuses = glom(response, 'payment.statuses.status') statuses_codes = [status.get('code') for status in statuses] transaction_state = glom(response, 'payment.transaction-state') success_conditions = [ CREATION_SUCCESS_ID in statuses_codes, CARD_ELIGIBLE_3D_ID in statuses_codes, transaction_state == SUCCESS, ] if all(success_conditions): return response transaction_id = glom(response, 'payment.transaction-id', default='transaction_id not present') raise WirecardFailedTransaction(transaction_id, 'check_3d_enrollment', statuses) def payment_request_with_pares(self, pares, parent_transaction_id): data = { 'payment': { 'merchant-account-id': { 'value': self.merchant_account_id, }, 'request-id': self._generate_request_id(), 'transaction-type': PURCHASE, 'parent-transaction-id': parent_transaction_id, 'three-d': { 'pares': pares, }, }, } headers = self._make_headers() result = requests.post(self.url, json=data, headers=headers) response = result.json() statuses = glom(response, 'payment.statuses.status') statuses_codes = [status.get('code') for status in statuses] transaction_state = glom(response, 'payment.transaction-state') success_conditions = [ CREATION_SUCCESS_ID in statuses_codes, transaction_state == SUCCESS, ] if all(success_conditions): return response raise WirecardFailedTransaction( parent_transaction_id, 'payment_request_with_pares', statuses, ) def validate(self): failed_conditions = [ self.username is None, self.password is None, self.merchant_account_id is None, self.url is None, ] if any(failed_conditions): message = 'Parameters username, password, merchant_account_id and url are required' raise WirecardFailedInit(message) def _generate_request_id(self): return str(uuid.uuid4()) def _generate_basic_authorization(self): if self.basic_authorization: return self.basic_authorization username_password = f'{self.username}:{self.password}' basic_credentials = b64encode(bytes(username_password.encode())).decode() self.basic_authorization = f'Basic {basic_credentials}' return self.basic_authorization def _make_headers(self): return { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': self._generate_basic_authorization(), } class Card: def __init__(self, account_number, expiration_month, expiration_year, security_code, _type): self.account_number = account_number self.expiration_month = expiration_month self.expiration_year = expiration_year self.security_code = security_code self.type = _type self._clean() self.validate() def _clean(self): self.type = self.type.lower() self.account_number = self.account_number.replace(' ', '') def as_dict(self): return { 'account-number': self.account_number, 'expiration-month': self.expiration_month, 'expiration-year': self.expiration_year, 'card-security-code': self.security_code, 'card-type': self.type, } def validate(self): if len(self.expiration_month) != 2: raise WirecardInvalidCard('expiration_month length should be 2') if len(self.expiration_year) != 4: raise WirecardInvalidCard('expiration_year length should be 4') if len(self.security_code) != 3: raise WirecardInvalidCard('security_code length should be 3') class AccountHolder: def __init__(self, first_name, last_name, **kwargs): self.first_name = first_name self.last_name = last_name self.other_info = kwargs def as_dict(self): return { 'first-name': self.first_name, 'last-name': self.last_name, **self.other_info, } class RequestedAmount: def __init__(self, amount, currency): self.amount = Decimal(amount) self.currency = currency self.validate() def as_dict(self): return { 'value': str(self.amount), 'currency': self.currency, } def validate(self): if len(self.currency) != 3: raise WirecardInvalidRequestedAmount('currency length should be 3') integer_part, fractional_part = str(self.amount).split('.') if len(integer_part) > 18: raise WirecardInvalidRequestedAmount('integer_part length should be less than 18') if len(fractional_part) > 2: raise WirecardInvalidRequestedAmount('fractional_part length should be less than 2') PK!,, wirecard-0.2.1.dist-info/LICENSEMIT License Copyright (c) 2019 Flickswitch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK!HڽTUwirecard-0.2.1.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!H6*\!wirecard-0.2.1.dist-info/METADATAWs6Blp`󖦍lc@/ 4vVcK$Cn6!MW!VLy6NT5\};͒hQgh-p\ tWp`:Cе.yB/AnT*z}IU݀'1 嚪 o^р0 O@Gd~qHYqC_Kwn.]SÚ2-hignXJ_ $-f FW OһxloJetsyj[ Q'J嶚mM꾐@9+MH%U\lj>pz)”3ۤET1kfY'[iiHȃ,!RxSuZ֊nXA2KS.@*dxIHdvId kY?b1#0'5jQP\Z"&&xbYV7yI$kɝQIKE wӻIcK5^}w.8? q6EA>Th.q)ut%eEekϭPRSB@(E 3ϘqHD&y a7їb,1%,KDtF5Mk '9h^mFd3JxHg+Ww:J '4#2/6=P sn6܋B, 6H_bx ,BnoiF& /=}tao[ 4 ,LЬL͗no)qp+8(~9BbKQ :>SFYJ`&q` 1rDE~ەu֡/L_!NXcDc+1Ú0{ϑqG*qE7˄ c.h'I6P:$jb*I-"<BԐ6CgOW=KJ8z0G׈g=txkxd.{Luht>iݧ(y޳vv4DlEGwF=ې쨦őm>Hmհ7MڂPK!Hwl^wirecard-0.2.1.dist-info/RECORDuйvP>B cq d 3 ' 3hL]b5%i_"r;qµэ%^8IQO'4X;Su(ʛzz0"S G0(ˮ,i\K~\9[צCQ' .9lGC>iÁ.J08\'P3rb^aokp0dx έ |ZunQnI].]cX#vwT] ~/s|"v"VlrHYHe3'p`瘟.:A6e>F^*vW~ȥ85jOOxړbm#t"UyG8v+>]=2e#aPK!hhwirecard/__init__.pyPK!Xwirecard/constants.pyPK!swirecard/exceptions.pyPK!@@]wirecard/wirecard.pyPK!,, wirecard-0.2.1.dist-info/LICENSEPK!HڽTU9#wirecard-0.2.1.dist-info/WHEELPK!H6*\!#wirecard-0.2.1.dist-info/METADATAPK!Hwl^2*wirecard-0.2.1.dist-info/RECORDPKA+