braintree_python-3.57.1/0000755000175000017500000000000013545202423013265 5ustar hlehlebraintree_python-3.57.1/.pylintrc0000644000175000017500000001624213545202423015137 0ustar hlehle[MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Profiled execution. profile=no # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Pickle collected data for later comparisons. persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= [MESSAGES CONTROL] # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time. #enable= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). disable=C0111,C0103,C0301,E1101,E1103,R0903,R0904,W0401,W0614 [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html output-format=text # Include message's id in output include-ids=no # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells whether to display a full report or only the messages reports=yes # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Add a comment according to your evaluation note. This is used by the global # evaluation report (RP0004). comment=no [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). ignored-classes=SQLObject # When zope mode is activated, add a predefined set of Zope acquired attributes # to generated-members. zope=no # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E0201 when accessed. Python regular # expressions are accepted. generated-members=REQUEST,acl_users,aq_parent [BASIC] # Required attributes for module, separated by a comma required-attributes= # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter,apply,input # Regular expression which should only match correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression which should only match correct module level names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression which should only match correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Regular expression which should only match correct function names function-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct method names method-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct instance attribute names attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct variable names variable-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct list comprehension / # generator expression variable names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Regular expression which should only match functions or classes name which do # not require a docstring no-docstring-rgx=__.*__ [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the beginning of the name of dummy variables # (i.e. not used). dummy-variables-rgx=_|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= [FORMAT] # Maximum number of characters on a single line. max-line-length=80 # Maximum number of lines in a module max-module-lines=1000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' [DESIGN] # Maximum number of arguments for function / method max-args=5 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=15 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branchs=12 # Maximum number of statements in function / method body max-statements=50 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Minimum number of public methods for a class (see R0903). min-public-methods=2 # Maximum number of public methods for a class (see R0904). max-public-methods=20 [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=regsub,string,TERMIOS,Bastion,rexec # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= [CLASSES] # List of interface methods to ignore, separated by a comma. This is used for # instance to not check methods defines in Zope's Interface base class. ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception braintree_python-3.57.1/braintree/0000755000175000017500000000000013545202423015240 5ustar hlehlebraintree_python-3.57.1/braintree/local_payment.py0000644000175000017500000000014113545202423020435 0ustar hlehleimport braintree from braintree.resource import Resource class LocalPayment(Resource): pass braintree_python-3.57.1/braintree/attribute_getter.py0000644000175000017500000000162613545202423021174 0ustar hlehleclass AttributeGetter(object): """ Helper class for objects that define their attributes from dictionaries passed in during instantiation. Example: a = AttributeGetter({'foo': 'bar', 'baz': 5}) a.foo >> 'bar' a.baz >> 5 Typically inherited by subclasses instead of directly instantiated. """ def __init__(self, attributes={}): self._setattrs = [] for key, val in attributes.items(): setattr(self, key, val) self._setattrs.append(key) def __repr__(self, detail_list=None): if detail_list is None: detail_list = self._setattrs details = ", ".join("%s: %r" % (attr, getattr(self, attr)) for attr in detail_list if hasattr(self, attr)) return "<%s {%s} at %d>" % (self.__class__.__name__, details, id(self)) braintree_python-3.57.1/braintree/customer_gateway.py0000644000175000017500000001146313545202423021201 0ustar hlehleimport braintree from braintree.customer import Customer from braintree.error_result import ErrorResult from braintree.exceptions.not_found_error import NotFoundError from braintree.ids_search import IdsSearch from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult from braintree.transparent_redirect import TransparentRedirect class CustomerGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def all(self): response = self.config.http().post(self.config.base_merchant_path() + "/customers/advanced_search_ids") return ResourceCollection({}, response, self.__fetch) def confirm_transparent_redirect(self, query_string): id = self.gateway.transparent_redirect._parse_and_validate_query_string(query_string)["id"][0] return self._post("/customers/all/confirm_transparent_redirect_request", {"id": id}) def create(self, params={}): Resource.verify_keys(params, Customer.create_signature()) return self._post("/customers", {"customer": params}) def delete(self, customer_id): self.config.http().delete(self.config.base_merchant_path() + "/customers/" + customer_id) return SuccessfulResult() def find(self, customer_id, association_filter_id=None): try: if customer_id is None or customer_id.strip() == "": raise NotFoundError() query_params = "" if association_filter_id: query_params = "?association_filter_id=" + association_filter_id response = self.config.http().get(self.config.base_merchant_path() + "/customers/" + customer_id + query_params) return Customer(self.gateway, response["customer"]) except NotFoundError: raise NotFoundError("customer with id " + repr(customer_id) + " not found") def search(self, *query): if isinstance(query[0], list): query = query[0] response = self.config.http().post(self.config.base_merchant_path() + "/customers/advanced_search_ids", {"search": self.__criteria(query)}) return ResourceCollection(query, response, self.__fetch) def tr_data_for_create(self, tr_data, redirect_url): Resource.verify_keys(tr_data, [{"customer": Customer.create_signature()}]) tr_data["kind"] = TransparentRedirect.Kind.CreateCustomer return self.gateway.transparent_redirect.tr_data(tr_data, redirect_url) def tr_data_for_update(self, tr_data, redirect_url): Resource.verify_keys(tr_data, ["customer_id", {"customer": Customer.update_signature()}]) tr_data["kind"] = TransparentRedirect.Kind.UpdateCustomer return self.gateway.transparent_redirect.tr_data(tr_data, redirect_url) def transparent_redirect_create_url(self): return self.config.base_url() + self.config.base_merchant_path() + "/customers/all/create_via_transparent_redirect_request" def transparent_redirect_update_url(self): return self.config.base_url() + self.config.base_merchant_path() + "/customers/all/update_via_transparent_redirect_request" def update(self, customer_id, params={}): Resource.verify_keys(params, Customer.update_signature()) response = self.config.http().put(self.config.base_merchant_path() + "/customers/" + customer_id, {"customer": params}) if "customer" in response: return SuccessfulResult({"customer": Customer(self.gateway, response["customer"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def __criteria(self, query): criteria = {} for term in query: if criteria.get(term.name): criteria[term.name] = dict(list(criteria[term.name].items()) + list(term.to_param().items())) else: criteria[term.name] = term.to_param() return criteria def __fetch(self, query, ids): criteria = self.__criteria(query) criteria["ids"] = braintree.customer_search.CustomerSearch.ids.in_list(ids).to_param() response = self.config.http().post(self.config.base_merchant_path() + "/customers/advanced_search", {"search": criteria}) return [Customer(self.gateway, item) for item in ResourceCollection._extract_as_array(response["customers"], "customer")] def _post(self, url, params={}): response = self.config.http().post(self.config.base_merchant_path() + url, params) if "customer" in response: return SuccessfulResult({"customer": Customer(self.gateway, response["customer"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: pass braintree_python-3.57.1/braintree/webhook_notification_gateway.py0000644000175000017500000000501413545202423023537 0ustar hlehleimport re import sys if sys.version_info[0] == 2: from base64 import decodestring as decodebytes else: from base64 import decodebytes import sys from braintree.exceptions.invalid_signature_error import InvalidSignatureError from braintree.exceptions.invalid_challenge_error import InvalidChallengeError from braintree.util.crypto import Crypto from braintree.util.xml_util import XmlUtil from braintree.webhook_notification import WebhookNotification if sys.version_info[0] == 2: text_type = unicode else: text_type = str class WebhookNotificationGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def parse(self, signature, payload): if signature is None: raise InvalidSignatureError("signature cannot be blank") if payload is None: raise InvalidSignatureError("payload cannot be blank") if isinstance(payload, text_type): payload = payload.encode('ascii') if re.search(b"[^A-Za-z0-9+=/\n]", payload): raise InvalidSignatureError("payload contains illegal characters") self.__validate_signature(signature, payload) attributes = XmlUtil.dict_from_xml(decodebytes(payload)) return WebhookNotification(self.gateway, attributes['notification']) def verify(self, challenge): if not re.match("^[a-f0-9]{20,32}$", challenge): raise InvalidChallengeError("challenge contains non-hex characters") digest = Crypto.sha1_hmac_hash(self.config.private_key, challenge) return "%s|%s" % (self.config.public_key, digest) def __matching_signature(self, signature_pairs): for public_key, signature in signature_pairs: if public_key == self.config.public_key: return signature return None def __validate_signature(self, signature_string, payload): signature_pairs = [pair.split("|") for pair in signature_string.split("&") if "|" in pair] signature = self.__matching_signature(signature_pairs) if not signature: raise InvalidSignatureError("no matching public key") if not any(self.__payload_matches(signature, p) for p in [payload, payload + b"\n"]): raise InvalidSignatureError("signature does not match payload - one has been modified") def __payload_matches(self, signature, payload): payload_signature = Crypto.sha1_hmac_hash(self.config.private_key, payload) return Crypto.secure_compare(payload_signature, signature) braintree_python-3.57.1/braintree/dispute_details/0000755000175000017500000000000013545202423020422 5ustar hlehlebraintree_python-3.57.1/braintree/dispute_details/evidence.py0000644000175000017500000000035613545202423022562 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class DisputeEvidence(AttributeGetter): def __init__(self, attributes): attributes["tag"] = attributes.get("category") AttributeGetter.__init__(self, attributes) braintree_python-3.57.1/braintree/dispute_details/status_history.py0000644000175000017500000000027413545202423024103 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class DisputeStatusHistory(AttributeGetter): def __init__(self, attributes): AttributeGetter.__init__(self, attributes) braintree_python-3.57.1/braintree/dispute_details/__init__.py0000644000175000017500000000021113545202423022525 0ustar hlehlefrom braintree.dispute_details.evidence import DisputeEvidence from braintree.dispute_details.status_history import DisputeStatusHistory braintree_python-3.57.1/braintree/venmo_account.py0000644000175000017500000000065513545202423020460 0ustar hlehleimport braintree from braintree.resource import Resource class VenmoAccount(Resource): """ A class representing Braintree Venmo accounts. """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] braintree_python-3.57.1/braintree/us_bank_account_verification_gateway.py0000644000175000017500000000665613545202423025250 0ustar hlehlefrom braintree.us_bank_account_verification import UsBankAccountVerification from braintree.us_bank_account_verification_search import UsBankAccountVerificationSearch from braintree.exceptions.not_found_error import NotFoundError from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult from braintree.resource_collection import ResourceCollection class UsBankAccountVerificationGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def confirm_micro_transfer_amounts(self, verification_id, amounts): try: if verification_id is None or verification_id.strip() == "": raise NotFoundError() response = self.config.http().put( self.config.base_merchant_path() + "/us_bank_account_verifications/" + verification_id + "/confirm_micro_transfer_amounts", { "us_bank_account_verification": { "deposit_amounts": amounts, } } ) if "us_bank_account_verification" in response: return SuccessfulResult({ "us_bank_account_verification": UsBankAccountVerification(self.gateway, response["us_bank_account_verification"]) }) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) except NotFoundError: raise NotFoundError("UsBankAccountVerification with id " + repr(verification_id) + " not found") def find(self, verification_id): try: if verification_id is None or verification_id.strip() == "": raise NotFoundError() response = self.config.http().get( self.config.base_merchant_path() + "/us_bank_account_verifications/" + verification_id ) return UsBankAccountVerification(self.gateway, response["us_bank_account_verification"]) except NotFoundError: raise NotFoundError("UsBankAccountVerification with id " + repr(verification_id) + " not found") def search(self, *query): if isinstance(query[0], list): query = query[0] response = self.config.http().post( self.config.base_merchant_path() + "/us_bank_account_verifications/advanced_search_ids", {"search": self.__criteria(query)} ) return ResourceCollection(query, response, self.__fetch) def __criteria(self, query): criteria = {} for term in query: if criteria.get(term.name): criteria[term.name] = dict(list(criteria[term.name].items()) + list(term.to_param().items())) else: criteria[term.name] = term.to_param() return criteria def __fetch(self, query, ids): criteria = self.__criteria(query) criteria["ids"] = UsBankAccountVerificationSearch.ids.in_list(ids).to_param() response = self.config.http().post( self.config.base_merchant_path() + "/us_bank_account_verifications/advanced_search", {"search": criteria} ) collection_array = ResourceCollection._extract_as_array( response["us_bank_account_verifications"], "us_bank_account_verification" ) return [UsBankAccountVerification(self.gateway, item) for item in collection_array] braintree_python-3.57.1/braintree/unknown_payment_method.py0000644000175000017500000000031613545202423022406 0ustar hlehleimport braintree from braintree.resource import Resource class UnknownPaymentMethod(Resource): def image_url(self): return "https://assets.braintreegateway.com/payment_method_logo/unknown.png" braintree_python-3.57.1/braintree/client_token.py0000644000175000017500000000133013545202423020265 0ustar hlehleimport datetime import json import urllib from braintree.configuration import Configuration from braintree.signature_service import SignatureService from braintree.util.crypto import Crypto from braintree import exceptions class ClientToken(object): @staticmethod def generate(params={}, gateway=None): if gateway is None: gateway = Configuration.gateway().client_token return gateway.generate(params) @staticmethod def generate_signature(): return [ "customer_id", "proxy_merchant_id", "version", "merchant_account_id", {"options": ["make_default", "verify_card", "fail_on_duplicate_payment_method"]} ] braintree_python-3.57.1/braintree/credit_card.py0000644000175000017500000002611213545202423020057 0ustar hlehleimport braintree import warnings from braintree.resource import Resource from braintree.address import Address from braintree.configuration import Configuration from braintree.transparent_redirect import TransparentRedirect from braintree.credit_card_verification import CreditCardVerification class CreditCard(Resource): """ A class representing Braintree CreditCard objects. An example of creating an credit card with all available fields:: result = braintree.CreditCard.create({ "cardholder_name": "John Doe", "cvv": "123", "expiration_date": "12/2012", "number": "4111111111111111", "token": "my_token", "billing_address": { "first_name": "John", "last_name": "Doe", "company": "Braintree", "street_address": "111 First Street", "extended_address": "Unit 1", "locality": "Chicago", "postal_code": "60606", "region": "IL", "country_name": "United States of America" }, "options": { "verify_card": True, "verification_amount": "2.00" } }) print(result.credit_card.token) print(result.credit_card.masked_number) For more information on CreditCards, see https://developers.braintreepayments.com/reference/request/credit-card/create/python """ class CardType(object): """ Contants representing the type of the credit card. Available types are: * Braintree.CreditCard.AmEx * Braintree.CreditCard.CarteBlanche * Braintree.CreditCard.ChinaUnionPay * Braintree.CreditCard.DinersClubInternational * Braintree.CreditCard.Discover * Braintree.CreditCard.Electron * Braintree.CreditCard.Elo * Braintree.CreditCard.Hiper * Braintree.CreditCard.Hipercard * Braintree.CreditCard.JCB * Braintree.CreditCard.Laser * Braintree.CreditCard.UK_Maestro * Braintree.CreditCard.Maestro * Braintree.CreditCard.MasterCard * Braintree.CreditCard.Solo * Braintree.CreditCard.Switch * Braintree.CreditCard.Visa * Braintree.CreditCard.Unknown """ AmEx = "American Express" CarteBlanche = "Carte Blanche" ChinaUnionPay = "China UnionPay" DinersClubInternational = "Diners Club" Discover = "Discover" Electron = "Electron" Elo = "Elo" Hiper = "Hiper" Hipercard = "Hipercard" JCB = "JCB" Laser = "Laser" UK_Maestro = "UK Maestro" Maestro = "Maestro" MasterCard = "MasterCard" Solo = "Solo" Switch = "Switch" Visa = "Visa" Unknown = "Unknown" class CustomerLocation(object): """ Contants representing the issuer location of the credit card. Available locations are: * braintree.CreditCard.CustomerLocation.International * braintree.CreditCard.CustomerLocation.US """ International = "international" US = "us" class CardTypeIndicator(object): """ Constants representing the three states for the card type indicator attributes * braintree.CreditCard.CardTypeIndicator.Yes * braintree.CreditCard.CardTypeIndicator.No * braintree.CreditCard.CardTypeIndicator.Unknown """ Yes = "Yes" No = "No" Unknown = "Unknown" Commercial = DurbinRegulated = Debit = Healthcare = \ CountryOfIssuance = IssuingBank = Payroll = Prepaid = ProductId = CardTypeIndicator @staticmethod def confirm_transparent_redirect(query_string): """ Confirms a transparent redirect request. It expects the query string from the redirect request. The query string should _not_ include the leading "?" character. :: result = braintree.CreditCard.confirm_transparent_redirect_request("foo=bar&id=12345") """ warnings.warn("Please use TransparentRedirect.confirm instead", DeprecationWarning) return Configuration.gateway().credit_card.confirm_transparent_redirect(query_string) @staticmethod def create(params={}): """ Create a CreditCard. A number and expiration_date are required. :: result = braintree.CreditCard.create({ "number": "4111111111111111", "expiration_date": "12/2012" }) """ return Configuration.gateway().credit_card.create(params) @staticmethod def update(credit_card_token, params={}): """ Update an existing CreditCard By credit_card_id. The params are similar to create:: result = braintree.CreditCard.update("my_credit_card_id", { "cardholder_name": "John Doe" }) """ return Configuration.gateway().credit_card.update(credit_card_token, params) @staticmethod def delete(credit_card_token): """ Delete a credit card Given a credit_card_id:: result = braintree.CreditCard.delete("my_credit_card_id") """ return Configuration.gateway().credit_card.delete(credit_card_token) @staticmethod def expired(): """ Return a collection of expired credit cards. """ return Configuration.gateway().credit_card.expired() @staticmethod def expiring_between(start_date, end_date): """ Return a collection of credit cards expiring between the given dates. """ return Configuration.gateway().credit_card.expiring_between(start_date, end_date) @staticmethod def find(credit_card_token): """ Find a credit card, given a credit_card_id. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided credit_card_id is not found. :: credit_card = braintree.CreditCard.find("my_credit_card_token") """ return Configuration.gateway().credit_card.find(credit_card_token) @staticmethod def forward(credit_card_token, receiving_merchant_id): """ This method has been deprecated. Please consider the Grant API instead. """ return Configuration.gateway().credit_card.forward(credit_card_token, receiving_merchant_id) @staticmethod def from_nonce(nonce): """ Convert a payment method nonce into a CreditCard. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided credit_card_id is not found. :: credit_card = braintree.CreditCard.from_nonce("my_payment_method_nonce") """ return Configuration.gateway().credit_card.from_nonce(nonce) @staticmethod def create_signature(): return CreditCard.signature("create") @staticmethod def update_signature(): return CreditCard.signature("update") @staticmethod def signature(type): billing_address_params = [ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "first_name", "last_name", "locality", "postal_code", "region", "street_address" ] options = [ "make_default", "verification_merchant_account_id", "verify_card", "verification_amount", "verification_account_type", "venmo_sdk_session", "fail_on_duplicate_payment_method", { "adyen":[ "overwrite_brand", "selected_brand" ] } ] signature = [ "billing_address_id", "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", "device_session_id", "fraud_merchant_id", "number", "token", "venmo_sdk_payment_method_code", "device_data", "payment_method_nonce", { "billing_address": billing_address_params }, { "options": options } ] if type == "create": signature.append("customer_id") elif type == "update": billing_address_params.append({"options": ["update_existing"]}) elif type == "update_via_customer": options.append("update_existing_token") billing_address_params.append({"options": ["update_existing"]}) else: raise AttributeError return signature @staticmethod def transparent_redirect_create_url(): """ Returns the url to use for creating CreditCards through transparent redirect. """ warnings.warn("Please use TransparentRedirect.url instead", DeprecationWarning) return Configuration.gateway().credit_card.transparent_redirect_create_url() @staticmethod def tr_data_for_create(tr_data, redirect_url): """ Builds tr_data for CreditCard creation. """ return Configuration.gateway().credit_card.tr_data_for_create(tr_data, redirect_url) @staticmethod def tr_data_for_update(tr_data, redirect_url): """ Builds tr_data for CreditCard updating. """ return Configuration.gateway().credit_card.tr_data_for_update(tr_data, redirect_url) @staticmethod def transparent_redirect_update_url(): """ Returns the url to be used for updating CreditCards through transparent redirect. """ warnings.warn("Please use TransparentRedirect.url instead", DeprecationWarning) return Configuration.gateway().credit_card.transparent_redirect_update_url() def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.is_expired = self.expired if "billing_address" in attributes: self.billing_address = Address(gateway, self.billing_address) else: self.billing_address = None if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] if "verifications" in attributes: sorted_verifications = sorted(attributes["verifications"], key=lambda verification: verification["created_at"], reverse=True) if len(sorted_verifications) > 0: self.verification = CreditCardVerification(gateway, sorted_verifications[0]) @property def expiration_date(self): return self.expiration_month + "/" + self.expiration_year @property def masked_number(self): """ Returns the masked number of the CreditCard. """ return self.bin + "******" + self.last_4 braintree_python-3.57.1/braintree/test/0000755000175000017500000000000013545202423016217 5ustar hlehlebraintree_python-3.57.1/braintree/test/nonces.py0000644000175000017500000000671513545202423020067 0ustar hlehleclass Nonces(object): Transactable = "fake-valid-nonce" Consumed = "fake-consumed-nonce" PayPalOneTimePayment = "fake-paypal-one-time-nonce" PayPalFuturePayment = "fake-paypal-future-nonce" PayPalBillingAgreement = "fake-paypal-billing-agreement-nonce" ApplePayVisa = "fake-apple-pay-visa-nonce" ApplePayMasterCard = "fake-apple-pay-mastercard-nonce" ApplePayAmEx = "fake-apple-pay-amex-nonce" AbstractTransactable = "fake-abstract-transactable-nonce" Europe = "fake-europe-bank-account-nonce" Coinbase = "fake-coinbase-nonce" AndroidPayCard = "fake-android-pay-nonce" AndroidPayCardDiscover = "fake-android-pay-discover-nonce" AndroidPayCardVisa = "fake-android-pay-visa-nonce" AndroidPayCardMasterCard = "fake-android-pay-mastercard-nonce" AndroidPayCardAmEx = "fake-android-pay-amex-nonce" AmexExpressCheckoutCard = "fake-amex-express-checkout-nonce" VenmoAccount = "fake-venmo-account-nonce" VenmoAccountTokenIssuanceError = "fake-token-issuance-error-venmo-account-nonce" ThreeDSecureVisaFullAuthentication = "fake-three-d-secure-visa-full-authentication-nonce" TransactableVisa = "fake-valid-visa-nonce" TransactableAmEx = "fake-valid-amex-nonce" TransactableMasterCard = "fake-valid-mastercard-nonce" TransactableDiscover = "fake-valid-discover-nonce" TransactableJCB = "fake-valid-jcb-nonce" TransactableMaestro = "fake-valid-maestro-nonce" TransactableDinersClub = "fake-valid-dinersclub-nonce" TransactablePrepaid = "fake-valid-prepaid-nonce" TransactableCommercial = "fake-valid-commercial-nonce" TransactableDurbinRegulated = "fake-valid-durbin-regulated-nonce" TransactableHealthcare = "fake-valid-healthcare-nonce" TransactableDebit = "fake-valid-debit-nonce" TransactablePayroll = "fake-valid-payroll-nonce" TransactableNoIndicators = "fake-valid-no-indicators-nonce" TransactableUnknownIndicators = "fake-valid-unknown-indicators-nonce" TransactableCountryOfIssuanceUSA = "fake-valid-country-of-issuance-usa-nonce" TransactableCountryOfIssuanceCAD = "fake-valid-country-of-issuance-cad-nonce" TransactableIssuingBankNetworkOnly = "fake-valid-issuing-bank-network-only-nonce" ProcessorDeclinedVisa = "fake-processor-declined-visa-nonce" ProcessorDeclinedMasterCard = "fake-processor-declined-mastercard-nonce" ProcessorDeclinedAmEx = "fake-processor-declined-amex-nonce" ProcessorDeclinedDiscover = "fake-processor-declined-discover-nonce" ProcessorFailureJCB = "fake-processor-failure-jcb-nonce" LocalPayment = "fake-local-payment-method-nonce" LuhnInvalid = "fake-luhn-invalid-nonce" PayPalFuturePaymentRefreshToken = "fake-paypal-future-refresh-token-nonce" SEPA = "fake-sepa-bank-account-nonce" GatewayRejectedFraud = "fake-gateway-rejected-fraud-nonce" MasterpassAmEx = "fake-masterpass-amex-nonce" MasterpassDiscover = "fake-masterpass-discover-nonce" MasterpassMasterCard = "fake-masterpass-mastercard-nonce" MasterpassVisa = "fake-masterpass-visa-nonce" VisaCheckoutAmEx = "fake-visa-checkout-amex-nonce" VisaCheckoutDiscover = "fake-visa-checkout-discover-nonce" VisaCheckoutMasterCard = "fake-visa-checkout-mastercard-nonce" VisaCheckoutVisa = "fake-visa-checkout-visa-nonce" SamsungPayAmex = "tokensam_fake_american_express" SamsungPayDiscover = "tokensam_fake_american_express" SamsungPayMasterCard = "tokensam_fake_mastercard" SamsungPayVisa = "tokensam_fake_visa" braintree_python-3.57.1/braintree/test/venmo_sdk.py0000644000175000017500000000047013545202423020557 0ustar hlehledef generate_test_payment_method_code(number): return "stub-" + number VisaPaymentMethodCode = generate_test_payment_method_code("4111111111111111") InvalidPaymentMethodCode = generate_test_payment_method_code("invalid-payment-method-code") Session = "stub-session" InvalidSession = "stub-invalid-session" braintree_python-3.57.1/braintree/test/merchant_account.py0000644000175000017500000000037513545202423022113 0ustar hlehleApprove = "approve_me" InsufficientFundsContactUs = "insufficient_funds__contact" AccountNotAuthorizedContactUs = "account_not_authorized__contact" BankRejectedUpdateFundingInformation = "bank_rejected__update" BankRejectedNone = "bank_rejected__none" braintree_python-3.57.1/braintree/test/__init__.py0000644000175000017500000000000013545202423020316 0ustar hlehlebraintree_python-3.57.1/braintree/test/credit_card_defaults.py0000644000175000017500000000014113545202423022717 0ustar hlehleclass CreditCardDefaults(object): CountryOfIssuance = "USA" IssuingBank = "NETWORK ONLY" braintree_python-3.57.1/braintree/test/credit_card_numbers.py0000644000175000017500000000243413545202423022572 0ustar hlehleclass CreditCardNumbers(object): class CardTypeIndicators(object): Commercial = "4111111111131010" DurbinRegulated = "4111161010101010" Debit = "4117101010101010" Healthcare = "4111111510101010" Payroll = "4111111114101010" Prepaid = "4111111111111210" IssuingBank = "4111111141010101" CountryOfIssuance = "4111111111121102" No = "4111111111310101" Unknown = "4111111111112101" Maestro = "6304000000000000" # :nodoc: MasterCard = "5555555555554444" MasterCardInternational = "5105105105105100" # :nodoc: Visa = "4012888888881881" VisaInternational = "4009348888881881" # :nodoc: VisaPrepaid = "4500600000000061" Discover = "6011111111111117" Elo = "5066991111111118" Hiper = "6370950000000005" Hipercard = "6062820524845321" class FailsSandboxVerification(object): AmEx = "378734493671000" Discover = "6011000990139424" MasterCard = "5105105105105100" Visa = "4000111111111115" class AmexPayWithPoints(object): Success = "371260714673002" IneligibleCard = "378267515471109" InsufficientPoints = "371544868764018" class Disputes(object): Chargeback = "4023898493988028" braintree_python-3.57.1/braintree/add_on_gateway.py0000644000175000017500000000100213545202423020550 0ustar hlehleimport braintree from braintree.add_on import AddOn from braintree.resource_collection import ResourceCollection class AddOnGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def all(self): response = self.config.http().get(self.config.base_merchant_path() + "/add_ons/") add_ons = {"add_on": response["add_ons"]} return [AddOn(self.gateway, item) for item in ResourceCollection._extract_as_array(add_ons, "add_on")] braintree_python-3.57.1/braintree/europe_bank_account.py0000644000175000017500000000141413545202423021620 0ustar hlehleimport braintree from braintree.resource import Resource from braintree.configuration import Configuration class EuropeBankAccount(Resource): class MandateType(object): """ Constants representing the type of the mandate. Available type: * Braintree.EuropeBankAccount.MandateType.Business * Braintree.EuropeBankAccount.MandateType.Consumer """ Business = "business" Consumer = "consumer" @staticmethod def signature(): signature = [ "billing_address", "customer_id", "token", "masked_iban", "bic", "mandate_reference_number", "mandate_accepted_at", "account_holder_name" ] return signature braintree_python-3.57.1/braintree/webhook_testing.py0000644000175000017500000000043513545202423021007 0ustar hlehleimport braintree from braintree.configuration import Configuration class WebhookTesting(object): @staticmethod def sample_notification(kind, id, source_merchant_id=None): return Configuration.gateway().webhook_testing.sample_notification(kind, id, source_merchant_id) braintree_python-3.57.1/braintree/credit_card_verification_gateway.py0000644000175000017500000000577613545202423024357 0ustar hlehlefrom braintree.credit_card_verification import CreditCardVerification from braintree.credit_card_verification_search import CreditCardVerificationSearch from braintree.exceptions.not_found_error import NotFoundError from braintree.ids_search import IdsSearch from braintree.resource_collection import ResourceCollection from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult class CreditCardVerificationGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def find(self, verification_id): try: if verification_id is None or verification_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/verifications/" + verification_id) return CreditCardVerification(self.gateway, response["verification"]) except NotFoundError: raise NotFoundError("Verification with id " + repr(verification_id) + " not found") def __criteria(self, query): criteria = {} for term in query: if criteria.get(term.name): criteria[term.name] = dict(list(criteria[term.name].items()) + list(term.to_param().items())) else: criteria[term.name] = term.to_param() return criteria def __fetch(self, query, ids): criteria = self.__criteria(query) criteria["ids"] = CreditCardVerificationSearch.ids.in_list(ids).to_param() response = self.config.http().post(self.config.base_merchant_path() + "/verifications/advanced_search", {"search": criteria}) return [CreditCardVerification(self.gateway, item) for item in ResourceCollection._extract_as_array(response["credit_card_verifications"], "verification")] def search(self, *query): if isinstance(query[0], list): query = query[0] response = self.config.http().post(self.config.base_merchant_path() + "/verifications/advanced_search_ids", {"search": self.__criteria(query)}) return ResourceCollection(query, response, self.__fetch) def __fetch_verifications(self, query, verification_ids): criteria = {} criteria["ids"] = IdsSearch.ids.in_list(verification_ids).to_param() response = self.config.http().post(self.config.base_merchant_path() + "/verifications/advanced_search", {"search": criteria}) return [CreditCardVerification(self.gateway, item) for item in ResourceCollection._extract_as_array(response["credit_card_verifications"], "verification")] def create(self, params): response = self.config.http().post(self.config.base_merchant_path() + "/verifications", {"verification": params}) if "verification" in response: return SuccessfulResult({"verification": CreditCardVerification(self.gateway, response["verification"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) braintree_python-3.57.1/braintree/add_on.py0000644000175000017500000000032313545202423017034 0ustar hlehlefrom braintree.configuration import Configuration from braintree.modification import Modification class AddOn(Modification): @staticmethod def all(): return Configuration.gateway().add_on.all() braintree_python-3.57.1/braintree/granted_payment_instrument_update.py0000644000175000017500000000041413545202423024624 0ustar hlehlefrom braintree.resource import Resource class GrantedPaymentInstrumentUpdate(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.payment_method_nonce = attributes["payment_method_nonce"]["nonce"] braintree_python-3.57.1/braintree/util/0000755000175000017500000000000013545202423016215 5ustar hlehlebraintree_python-3.57.1/braintree/util/generator.py0000644000175000017500000000502213545202423020554 0ustar hlehleimport datetime import sys from decimal import Decimal if sys.version_info[0] == 2: integer_types = int, long text_type = unicode binary_type = str else: integer_types = int, text_type = str binary_type = bytes class Generator(object): def __init__(self, dict): self.dict = dict def generate(self): return self.__generate_dict(self.dict) def __escape(self, value): return value.replace("&", "&").replace("<", "<").replace(">", ">").replace("'", "'").replace('"', """) def __generate_boolean(self, value): return str(value).lower() def __generate_datetime(self, value): return value.strftime("%Y-%m-%dT%H:%M:%SZ") def __generate_dict(self, dictionary): xml = "" for key, val in dictionary.items(): xml += self.__generate_node(key, val) return xml def __generate_list(self, list): xml = "" for item in list: xml += self.__generate_node("item", item) return xml def __generate_node(self, key, value): open_tag = "<" + self.__escape(key) + ">" close_tag = "" if isinstance(value, text_type): return open_tag + self.__escape(value).encode('ascii', 'xmlcharrefreplace').decode('utf-8') + close_tag elif isinstance(value, binary_type): return open_tag + self.__escape(value) + close_tag elif isinstance(value, Decimal): return open_tag + str(value) + close_tag elif isinstance(value, dict): return open_tag + self.__generate_dict(value) + close_tag elif isinstance(value, list): open_tag = "<" + key + " type=\"array\">" return open_tag + self.__generate_list(value) + close_tag elif isinstance(value, bool): open_tag = "<" + key + " type=\"boolean\">" return open_tag + self.__generate_boolean(value) + close_tag elif isinstance(value, integer_types) and not isinstance(value, bool): open_tag = "<" + key + " type=\"integer\">" return open_tag + str(value) + close_tag elif isinstance(value, type(None)): return open_tag + close_tag elif isinstance(value, datetime.datetime) or isinstance(value, datetime.date): open_tag = "<" + key + " type=\"datetime\">" return open_tag + self.__generate_datetime(value) + close_tag else: raise RuntimeError("Unexpected XML node type: " + str(type(value))) braintree_python-3.57.1/braintree/util/http.py0000644000175000017500000001631013545202423017547 0ustar hlehleimport sys import requests if sys.version_info[0] == 2: from base64 import encodestring as encodebytes else: from base64 import encodebytes import json import braintree from braintree import version from braintree.environment import Environment from braintree.util.xml_util import XmlUtil from braintree.exceptions.authentication_error import AuthenticationError from braintree.exceptions.authorization_error import AuthorizationError from braintree.exceptions.down_for_maintenance_error import DownForMaintenanceError from braintree.exceptions.not_found_error import NotFoundError from braintree.exceptions.server_error import ServerError from braintree.exceptions.too_many_requests_error import TooManyRequestsError from braintree.exceptions.upgrade_required_error import UpgradeRequiredError from braintree.exceptions.unexpected_error import UnexpectedError from braintree.exceptions.http.connection_error import ConnectionError from braintree.exceptions.http.invalid_response_error import InvalidResponseError from braintree.exceptions.http.timeout_error import TimeoutError from braintree.exceptions.http.timeout_error import ConnectTimeoutError from braintree.exceptions.http.timeout_error import ReadTimeoutError class Http(object): class ContentType(object): Xml = "application/xml" Multipart = "multipart/form-data" Json = "application/json" @staticmethod def is_error_status(status): return status not in [200, 201, 422] @staticmethod def raise_exception_from_status(status, message=None): if status == 401: raise AuthenticationError() elif status == 403: raise AuthorizationError(message) elif status == 404: raise NotFoundError() elif status == 426: raise UpgradeRequiredError() elif status == 429: raise TooManyRequestsError() elif status == 500: raise ServerError() elif status == 503: raise DownForMaintenanceError() else: raise UnexpectedError("Unexpected HTTP_RESPONSE " + str(status)) def __init__(self, config, environment=None): self.config = config self.environment = environment or self.config.environment def post(self, path, params=None): return self._make_request("POST", path, Http.ContentType.Xml, params) def delete(self, path): return self._make_request("DELETE", path, Http.ContentType.Xml) def get(self, path): return self._make_request("GET", path, Http.ContentType.Xml) def put(self, path, params=None): return self._make_request("PUT", path, Http.ContentType.Xml, params) def post_multipart(self, path, files, params=None): return self._make_request("POST", path, Http.ContentType.Multipart, params, files) def _make_request(self, http_verb, path, content_type, params=None, files=None, header_overrides=None): http_strategy = self.config.http_strategy() headers = self.__headers(content_type, header_overrides) request_body = self.__request_body(content_type, params, files) full_path = path if path.startswith(self.config.base_url()) or path.startswith(self.config.graphql_base_url()) else (self.config.base_url() + path) try: status, response_body = http_strategy.http_do(http_verb, full_path, headers, request_body) except Exception as e: if self.config.wrap_http_exceptions: http_strategy.handle_exception(e) else: raise if Http.is_error_status(status): Http.raise_exception_from_status(status) else: if len(response_body.strip()) == 0: return {} else: if content_type == Http.ContentType.Json: return json.loads(response_body) else: return XmlUtil.dict_from_xml(response_body) def http_do(self, http_verb, path, headers, request_body): data = request_body files = None if type(request_body) is tuple: data = request_body[0] files = request_body[1] if (self.config.environment == Environment.Development): verify = False else: verify = self.environment.ssl_certificate response = self.__request_function(http_verb)( path if path.startswith(self.config.base_url()) or path.startswith(self.config.graphql_base_url()) else (self.config.base_url() + path), headers=headers, data=data, files=files, verify=verify, timeout=self.config.timeout ) return [response.status_code, response.text] def handle_exception(self, exception): if isinstance(exception, requests.exceptions.ReadTimeout): raise ReadTimeoutError(exception) elif isinstance(exception, requests.exceptions.ConnectTimeout): raise ConnectTimeoutError(exception) elif isinstance(exception, requests.exceptions.ConnectionError): raise ConnectionError(exception) elif isinstance(exception, requests.exceptions.HTTPError): raise InvalidResponseError(exception) elif isinstance(exception, requests.exceptions.Timeout): raise TimeoutError(exception) else: raise UnexpectedError(exception) def __request_function(self, method): if method == "GET": return requests.get elif method == "POST": return requests.post elif method == "PUT": return requests.put elif method == "DELETE": return requests.delete def __authorization_header(self): if self.config.has_client_credentials(): return b"Basic " + encodebytes( self.config.client_id.encode('ascii') + b":" + self.config.client_secret.encode('ascii') ).replace(b"\n", b"").strip() elif self.config.has_access_token(): return b"Bearer " + self.config.access_token.encode('ascii') else: return b"Basic " + encodebytes( self.config.public_key.encode('ascii') + b":" + self.config.private_key.encode('ascii') ).replace(b"\n", b"").strip() def __headers(self, content_type, header_overrides=None): headers = { "Accept": "application/xml", "Authorization": self.__authorization_header(), "User-Agent": "Braintree Python " + version.Version, "Accept-Encoding": "gzip", "X-ApiVersion": braintree.configuration.Configuration.api_version() } if content_type == Http.ContentType.Xml: headers["Content-type"] = Http.ContentType.Xml headers.update(header_overrides or {}) return headers def __request_body(self, content_type, params, files): if content_type == Http.ContentType.Xml: request_body = XmlUtil.xml_from_dict(params) if params else '' return request_body elif files == None: return params else: return (params, files) braintree_python-3.57.1/braintree/util/constants.py0000644000175000017500000000027013545202423020602 0ustar hlehleclass Constants(object): @staticmethod def get_all_constant_values_from_class(klass): return [klass.__dict__[item] for item in dir(klass) if not item.startswith("__")] braintree_python-3.57.1/braintree/util/datetime_parser.py0000644000175000017500000000204713545202423021742 0ustar hlehleimport re from datetime import datetime from datetime import timedelta _OFFSET_REGEX = re.compile(r'(\+|\-)(\d\d):(\d\d)$') _SYMBOLS_REGEX = re.compile(r'[-:Z]') def parse_datetime(timestamp): offset_matches = _OFFSET_REGEX.findall(timestamp) if len(offset_matches) == 0: timestamp = _SYMBOLS_REGEX.sub('', timestamp) without_seconds = datetime.strptime(timestamp[:13], '%Y%m%dT%H%M') seconds = timedelta(seconds=float(timestamp[13:])) return without_seconds + seconds else: time_without_offset = parse_datetime(timestamp[:-6]) try: offset_matches = offset_matches[0] offset_is_negative = offset_matches[0] == '-' offset_hours = int(offset_matches[1]) offset_minutes = int(offset_matches[2]) except IndexError: pass offset = timedelta(hours=offset_hours, minutes=offset_minutes) if offset_is_negative: return time_without_offset + offset else: return time_without_offset - offset braintree_python-3.57.1/braintree/util/xml_util.py0000644000175000017500000000043313545202423020424 0ustar hlehlefrom braintree.util.parser import Parser from braintree.util.generator import Generator class XmlUtil(object): @staticmethod def xml_from_dict(dict): return Generator(dict).generate() @staticmethod def dict_from_xml(xml): return Parser(xml).parse() braintree_python-3.57.1/braintree/util/__init__.py0000644000175000017500000000047113545202423020330 0ustar hlehlefrom braintree.util.constants import Constants from braintree.util.crypto import Crypto from braintree.util.generator import Generator from braintree.util.http import Http from braintree.util.graphql_client import GraphQLClient from braintree.util.parser import Parser from braintree.util.xml_util import XmlUtil braintree_python-3.57.1/braintree/util/crypto.py0000644000175000017500000000240713545202423020112 0ustar hlehleimport hashlib import hmac import sys if sys.version_info[0] == 2: text_type = unicode else: text_type = str class Crypto: @staticmethod def sha1_hmac_hash(secret_key, content): if isinstance(secret_key, text_type): secret_key = secret_key.encode('ascii') if isinstance(content, text_type): content = content.encode('ascii') return hmac.new(hashlib.sha1(secret_key).digest(), content, hashlib.sha1).hexdigest() @staticmethod def sha256_hmac_hash(secret_key, content): if isinstance(secret_key, text_type): secret_key = secret_key.encode('ascii') if isinstance(content, text_type): content = content.encode('ascii') return hmac.new(hashlib.sha256(secret_key).digest(), content, hashlib.sha256).hexdigest() @staticmethod def secure_compare(left, right): if left is None or right is None: return False left_bytes = [ord(char) for char in left] right_bytes = [ord(char) for char in right] if len(left_bytes) != len(right_bytes): return False result = 0 for left_byte, right_byte in zip(left_bytes, right_bytes): result |= left_byte ^ right_byte return result == 0 braintree_python-3.57.1/braintree/util/parser.py0000644000175000017500000000642113545202423020066 0ustar hlehlefrom xml.dom import minidom from datetime import datetime from braintree.util.datetime_parser import parse_datetime import re import sys if sys.version_info[0] == 2: binary_type = str else: binary_type = bytes class Parser(object): def __init__(self, xml): if isinstance(xml, binary_type): xml = xml.decode('utf-8') self.doc = minidom.parseString("><".join(re.split(">\s+<", xml)).strip()) def parse(self): return {self.__underscored(self.doc.documentElement.tagName): self.__parse_node(self.doc.documentElement)} def __parse_node(self, root): child = root.firstChild if self.__get_node_attribute(root, "type") == "array": return self.__build_list(child) elif not child: return self.__node_content(root, None) elif (child.nodeType == minidom.Node.TEXT_NODE): return self.__node_content(root, child.nodeValue) else: return self.__build_dict(child) def __convert_to_boolean(self, value): if value == "true" or value == "1": return True else: return False def __convert_to_date(self, value): return datetime.strptime(value, "%Y-%m-%d").date() def __convert_to_datetime(self, value): return parse_datetime(value) def __convert_to_list(self, dict, key): val = dict[key] if not isinstance(val, list): dict[key] = [val] def __build_list(self, child): l = [] while child is not None: if (child.nodeType == minidom.Node.ELEMENT_NODE): l.append(self.__parse_node(child)) child = child.nextSibling return l def __build_dict(self, child): d = {} while child is not None: if (child.nodeType == minidom.Node.ELEMENT_NODE): child_tag = self.__underscored(child.tagName) if self.__get_node_attribute(child, "type") == "array" or child.firstChild and child.firstChild.nodeType == minidom.Node.TEXT_NODE: d[child_tag] = self.__parse_node(child) else: if not d.get(child_tag): d[child_tag] = self.__parse_node(child) else: self.__convert_to_list(d, child_tag) d[child_tag].append(self.__parse_node(child)) child = child.nextSibling return d def __get_node_attribute(self, node, attribute): attribute_node = node.attributes.get(attribute) return attribute_node and attribute_node.value def __node_content(self, parent, content): parent_type = self.__get_node_attribute(parent, "type") parent_nil = self.__get_node_attribute(parent, "nil") if parent_type == "integer": return int(content) elif parent_type == "boolean": return self.__convert_to_boolean(content) elif parent_type == "datetime": return self.__convert_to_datetime(content) elif parent_type == "date": return self.__convert_to_date(content) elif parent_nil == "true": return None else: return content or "" def __underscored(self, string): return string.replace("-", "_") braintree_python-3.57.1/braintree/util/graphql_client.py0000644000175000017500000000545513545202423021574 0ustar hlehleimport json from braintree.exceptions.authentication_error import AuthenticationError from braintree.exceptions.authorization_error import AuthorizationError from braintree.exceptions.down_for_maintenance_error import DownForMaintenanceError from braintree.exceptions.not_found_error import NotFoundError from braintree.exceptions.server_error import ServerError from braintree.exceptions.too_many_requests_error import TooManyRequestsError from braintree.exceptions.unexpected_error import UnexpectedError from braintree.exceptions.upgrade_required_error import UpgradeRequiredError from braintree.util.http import Http class GraphQLClient(Http): @staticmethod def raise_exception_for_graphql_error(response): if "errors" not in response: return for error in response["errors"]: if "extensions" in error and "errorClass" in error["extensions"]: error_type = error["extensions"]["errorClass"] if error_type == "VALIDATION": continue elif error_type == "AUTHENTICATION": raise AuthenticationError(error["message"]) elif error_type == "AUTHORIZATION": raise AuthorizationError(error["message"]) elif error_type == "NOT_FOUND": raise NotFoundError elif error_type == "UNSUPPORTED_CLIENT": raise UpgradeRequiredError("Please upgrade your client library.") elif error_type == "RESOURCE_LIMIT": raise TooManyRequestsError elif error_type == "INTERNAL": raise ServerError elif error_type == "SERVICE_AVAILABILITY": raise DownForMaintenanceError else: raise UnexpectedError("Unexpected Response: " + error["message"]) def __init__(self, config=None, environment=None): Http.__init__(self, config, environment) self.graphql_headers = { "Accept": "application/json", "Braintree-Version": config.graphql_api_version(), "Content-Type": "application/json" } def query(self, definition, variables=None, operation_name=None): graphql_request = { "query": definition } if variables is not None: graphql_request["variables"] = variables if operation_name is not None: graphql_request["operationName"] = operation_name response = self._make_request("POST", self.config.graphql_base_url(), Http.ContentType.Json, json.dumps(graphql_request), header_overrides=self.graphql_headers) self.raise_exception_for_graphql_error(response) return response braintree_python-3.57.1/braintree/paypal_here.py0000644000175000017500000000027113545202423020103 0ustar hlehleimport braintree from braintree.resource import Resource class PayPalHere(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-3.57.1/braintree/resource.py0000644000175000017500000000504213545202423017442 0ustar hlehleimport re import string import sys from braintree.attribute_getter import AttributeGetter text_type = unicode if sys.version_info[0] == 2 else str raw_type = str if sys.version_info[0] == 2 else bytes class Resource(AttributeGetter): @staticmethod def verify_keys(params, signature): allowed_keys = Resource.__flattened_signature(signature) params_keys = Resource.__flattened_params_keys(params) invalid_keys = [key for key in params_keys if key not in allowed_keys] invalid_keys = Resource.__remove_wildcard_keys(allowed_keys, invalid_keys) if len(invalid_keys) > 0: keys_string = ", ".join(invalid_keys) raise KeyError("Invalid keys: " + keys_string) @staticmethod def __flattened_params_keys(params, parent=None): if isinstance(params, text_type) or isinstance(params, raw_type): return [ "%s[%s]" % (parent, params) ] else: keys = [] for key, val in params.items(): full_key = "%s[%s]" % (parent, key) if parent else key if isinstance(val, dict): keys += Resource.__flattened_params_keys(val, full_key) elif isinstance(val, list): for item in val: keys += Resource.__flattened_params_keys(item, full_key) else: keys.append(full_key) return keys @staticmethod def __flattened_signature(signature, parent=None): flat_sig = [] for item in signature: if isinstance(item, dict): for key, val in item.items(): full_key = '{0}[{1}]'.format(parent, key) if parent else key flat_sig += Resource.__flattened_signature(val, full_key) else: full_key = '{0}[{1}]'.format(parent, item) if parent else item flat_sig.append(full_key) return flat_sig @staticmethod def __remove_wildcard_keys(allowed_keys, invalid_keys): wildcard_keys = [re.sub("(?<=[^\\\\])_", "\\_", re.escape(key)).replace("\\[\\_\\_any\\_key\\_\\_\\]", "\\[[\w-]+\\]") for key in allowed_keys if re.search("\\[__any_key__\\]", key)] new_keys = [] for key in invalid_keys: if len([match for match in wildcard_keys if re.match("\A" + match + "\Z", key)]) == 0: new_keys.append(key) return new_keys def __init__(self, gateway, attributes): AttributeGetter.__init__(self, attributes) self.gateway = gateway braintree_python-3.57.1/braintree/credit_card_verification_search.py0000644000175000017500000000236113545202423024146 0ustar hlehlefrom braintree.credit_card import CreditCard from braintree.credit_card_verification import CreditCardVerification from braintree.search import Search from braintree.util import Constants class CreditCardVerificationSearch: credit_card_cardholder_name = Search.TextNodeBuilder("credit_card_cardholder_name") id = Search.TextNodeBuilder("id") credit_card_expiration_date = Search.EqualityNodeBuilder("credit_card_expiration_date") credit_card_number = Search.PartialMatchNodeBuilder("credit_card_number") credit_card_card_type = Search.MultipleValueNodeBuilder("credit_card_card_type", Constants.get_all_constant_values_from_class(CreditCard.CardType)) ids = Search.MultipleValueNodeBuilder("ids") created_at = Search.RangeNodeBuilder("created_at") status = Search.MultipleValueNodeBuilder("status", Constants.get_all_constant_values_from_class(CreditCardVerification.Status)) billing_postal_code = Search.TextNodeBuilder("billing_address_details_postal_code") customer_email = Search.TextNodeBuilder("customer_email") customer_id = Search.TextNodeBuilder("customer_id") braintree_python-3.57.1/braintree/ids_search.py0000644000175000017500000000014713545202423017720 0ustar hlehlefrom braintree.search import Search class IdsSearch: ids = Search.MultipleValueNodeBuilder("ids") braintree_python-3.57.1/braintree/credentials_parser.py0000644000175000017500000000375213545202423021472 0ustar hlehleimport os import sys import braintree from braintree.exceptions.configuration_error import ConfigurationError from braintree.environment import Environment class CredentialsParser(object): def __init__(self, client_id=None, client_secret=None, access_token=None): self.client_id = client_id self.client_secret = client_secret self.access_token = access_token def parse_client_credentials(self): if self.client_id is None and self.client_secret is not None: raise ConfigurationError("Missing client_id when constructing BraintreeGateway") if self.client_secret is None and self.client_id is not None: raise ConfigurationError("Missing client_secret when constructing BraintreeGateway") if not self.client_id.startswith("client_id"): raise ConfigurationError("Value passed for client_id is not a client_id") if not self.client_secret.startswith("client_secret"): raise ConfigurationError("Value passed for client_secret is not a client_secret") client_id_environment = self.get_environment(self.client_id) client_secret_environment = self.get_environment(self.client_secret) if client_id_environment is client_secret_environment: self.environment = client_id_environment else: raise ConfigurationError(" ".join([ "Mismatched credential environments: client_id environment is:", str(client_id_environment), "and client_secret environment is:", str(client_secret_environment) ])) def parse_access_token(self): self.environment = self.get_environment(self.access_token) self.merchant_id = self.get_merchant_id(self.access_token) def get_environment(self, credential): parts = credential.split("$") return Environment.All.get(parts[1]) def get_merchant_id(self, credential): parts = credential.split("$") return parts[2] braintree_python-3.57.1/braintree/credit_card_verification.py0000644000175000017500000000661513545202423022627 0ustar hlehlefrom decimal import Decimal from braintree.attribute_getter import AttributeGetter from braintree.configuration import Configuration from braintree.risk_data import RiskData from braintree.three_d_secure_info import ThreeDSecureInfo from braintree.resource import Resource class CreditCardVerification(AttributeGetter): class Status(object): """ Constants representing transaction statuses. Available statuses are: * braintree.CreditCardVerification.Status.Failed * braintree.CreditCardVerification.Status.GatewayRejected * braintree.CreditCardVerification.Status.ProcessorDeclined * braintree.CreditCardVerification.Status.Unrecognized * braintree.CreditCardVerification.Status.Verified """ Failed = "failed" GatewayRejected = "gateway_rejected" ProcessorDeclined = "processor_declined" Unrecognized = "unrecognized" Verified = "verified" def __init__(self, gateway, attributes): AttributeGetter.__init__(self, attributes) if "amount" in attributes and self.amount: self.amount = Decimal(self.amount) else: self.amount = None if "currency_iso_code" not in attributes: self.currency_iso_code = None if "processor_response_code" not in attributes: self.processor_response_code = None if "processor_response_text" not in attributes: self.processor_response_text = None if "network_response_code" not in attributes: self.network_response_code = None if "network_response_text" not in attributes: self.network_response_text = None if "risk_data" in attributes: self.risk_data = RiskData(attributes["risk_data"]) else: self.risk_data = None if "three_d_secure_info" in attributes and not attributes["three_d_secure_info"] is None: self.three_d_secure_info = ThreeDSecureInfo(attributes["three_d_secure_info"]) else: self.three_d_secure_info = None @staticmethod def find(verification_id): return Configuration.gateway().verification.find(verification_id) @staticmethod def search(*query): return Configuration.gateway().verification.search(*query) @staticmethod def create(params): Resource.verify_keys(params, CreditCardVerification.create_signature()) return Configuration.gateway().verification.create(params) @staticmethod def create_signature(): billing_address_params = [ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "first_name", "last_name", "locality", "postal_code", "region", "street_address" ] credit_card_params = [ "number", "cvv", "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", {"billing_address": billing_address_params} ] options_params = [ "account_type", "amount", "merchant_account_id" ] return [{"credit_card": credit_card_params}, {"options": options_params}] def __eq__(self, other): if not isinstance(other, CreditCardVerification): return False return self.id == other.id braintree_python-3.57.1/braintree/paginated_collection.py0000644000175000017500000000156213545202423021765 0ustar hlehleimport braintree class PaginatedCollection(object): """ A class representing results from a paginated list. Supports the iterator protocol:: results = braintree.MerchantAccount.all() for merchant_account in results.items: print merchant_account.id """ def __init__(self, method): self.__method = method @property def items(self): """ Returns a generator allowing iteration over all of the results. """ current_page = 0 total_items = 0 while True: current_page += 1 results = self.__method(current_page) total_items = results.total_items for item in results.current_page: yield item if current_page * results.page_size >= total_items: break def __iter__(self): return self.items braintree_python-3.57.1/braintree/masterpass_card.py0000644000175000017500000000150613545202423020767 0ustar hlehleimport braintree from braintree.address import Address from braintree.resource import Resource class MasterpassCard(Resource): """ A class representing Masterpass card """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "billing_address" in attributes: self.billing_address = Address(gateway, self.billing_address) else: self.billing_address = None if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] @property def expiration_date(self): return self.expiration_month + "/" + self.expiration_year @property def masked_number(self): return self.bin + "******" + self.last_4 braintree_python-3.57.1/braintree/payment_method_nonce.py0000644000175000017500000000204413545202423022011 0ustar hlehleimport braintree from braintree.resource import Resource from braintree.configuration import Configuration from braintree.three_d_secure_info import ThreeDSecureInfo from braintree.bin_data import BinData class PaymentMethodNonce(Resource): @staticmethod def create(payment_method_token): return Configuration.gateway().payment_method_nonce.create(payment_method_token) @staticmethod def find(payment_method_nonce): return Configuration.gateway().payment_method_nonce.find(payment_method_nonce) def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "three_d_secure_info" in attributes and not attributes["three_d_secure_info"] is None: self.three_d_secure_info = ThreeDSecureInfo(attributes["three_d_secure_info"]) else: self.three_d_secure_info = None if "bin_data" in attributes and not attributes["bin_data"] is None: self.bin_data = BinData(attributes["bin_data"]) else: self.bin_data = None braintree_python-3.57.1/braintree/oauth_credentials.py0000644000175000017500000000012413545202423021304 0ustar hlehlefrom braintree.resource import Resource class OAuthCredentials(Resource): pass braintree_python-3.57.1/braintree/processor_response_types.py0000644000175000017500000000032513545202423022773 0ustar hlehleclass ProcessorResponseTypes(object): """ A set of constants representing processor response types. """ Approved = "approved" SoftDeclined = "soft_declined" HardDeclined = "hard_declined" braintree_python-3.57.1/braintree/merchant_account_gateway.py0000644000175000017500000001441513545202423022655 0ustar hlehlefrom braintree.error_result import ErrorResult from braintree.merchant_account import MerchantAccount from braintree.paginated_collection import PaginatedCollection from braintree.paginated_result import PaginatedResult from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult from braintree.exceptions.not_found_error import NotFoundError class MerchantAccountGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create(self, params={}): Resource.verify_keys(params, MerchantAccountGateway._detect_signature(params)) return self._post("/merchant_accounts/create_via_api", {"merchant_account": params}) def update(self, merchant_account_id, params={}): Resource.verify_keys(params, MerchantAccountGateway._update_signature()) return self._put("/merchant_accounts/%s/update_via_api" % merchant_account_id, {"merchant_account": params}) def find(self, merchant_account_id): try: if merchant_account_id is None or merchant_account_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/merchant_accounts/" + merchant_account_id) return MerchantAccount(self.gateway, response["merchant_account"]) except NotFoundError: raise NotFoundError("merchant account with id " + repr(merchant_account_id) + " not found") def create_for_currency(self, params={}): return self._post("/merchant_accounts/create_for_currency", {"merchant_account": params}) def all(self): pc = PaginatedCollection(self._fetch_merchant_accounts) return SuccessfulResult({"merchant_accounts": pc}) def _fetch_merchant_accounts(self, current_page): response = self.config.http().get(self.config.base_merchant_path() + "/merchant_accounts/?page=" + str(current_page)) body = response["merchant_accounts"] merchant_accounts = [MerchantAccount(self.gateway, merchant_account) for merchant_account in ResourceCollection._extract_as_array(body, "merchant_account")] return PaginatedResult(body["total_items"], body["page_size"], merchant_accounts) def _post(self, url, params={}): response = self.config.http().post(self.config.base_merchant_path() + url, params) if "response" in response: response = response["response"] if "merchant_account" in response: return SuccessfulResult({"merchant_account": MerchantAccount(self.gateway, response["merchant_account"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def _put(self, url, params={}): response = self.config.http().put(self.config.base_merchant_path() + url, params) if "merchant_account" in response: return SuccessfulResult({"merchant_account": MerchantAccount(self.gateway, response["merchant_account"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) @staticmethod def _detect_signature(attributes): if 'applicant_details' in attributes: # Warn deprecated return MerchantAccountGateway._create_deprecated_signature() else: return MerchantAccountGateway._create_signature() @staticmethod def _create_deprecated_signature(): return [ {'applicant_details': [ 'company_name', 'first_name', 'last_name', 'email', 'phone', 'date_of_birth', 'ssn', 'tax_id', 'routing_number', 'account_number', {'address': [ 'street_address', 'postal_code', 'locality', 'region']} ] }, 'tos_accepted', 'master_merchant_account_id', 'id' ] @staticmethod def _create_signature(): return [ {'individual': [ 'first_name', 'last_name', 'email', 'phone', 'date_of_birth', 'ssn', {'address': [ 'street_address', 'postal_code', 'locality', 'region']} ] }, {'business': [ 'dba_name', 'legal_name', 'tax_id', {'address': [ 'street_address', 'postal_code', 'locality', 'region']} ] }, {'funding': [ 'routing_number', 'account_number', 'destination', 'email', 'mobile_phone', 'descriptor', ] }, 'tos_accepted', 'master_merchant_account_id', 'id' ] @staticmethod def _update_signature(): return [ {'individual': [ 'first_name', 'last_name', 'email', 'phone', 'date_of_birth', 'ssn', {'address': [ 'street_address', 'postal_code', 'locality', 'region']} ] }, {'business': [ 'dba_name', 'legal_name', 'tax_id', {'address': [ 'street_address', 'postal_code', 'locality', 'region']} ] }, {'funding': [ 'routing_number', 'account_number', 'destination', 'email', 'mobile_phone', 'descriptor', ] }, 'master_merchant_account_id', 'id' ] braintree_python-3.57.1/braintree/ach_mandate.py0000644000175000017500000000036313545202423020040 0ustar hlehleimport braintree from braintree.util.datetime_parser import parse_datetime from braintree.resource import Resource class AchMandate(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-3.57.1/braintree/android_pay_card.py0000644000175000017500000000142513545202423021076 0ustar hlehleimport braintree from braintree.resource import Resource class AndroidPayCard(Resource): """ A class representing Braintree Android Pay card objects. """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if hasattr(self, 'expired'): self.is_expired = self.expired if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] @property def expiration_date(self): return self.expiration_month + "/" + self.expiration_year @property def last_4(self): return self.virtual_card_last_4 @property def card_type(self): return self.virtual_card_type braintree_python-3.57.1/braintree/us_bank_account.py0000644000175000017500000000275713545202423020763 0ustar hlehleimport braintree from braintree.resource import Resource from braintree.configuration import Configuration from braintree.ach_mandate import AchMandate from braintree.us_bank_account_verification import UsBankAccountVerification class UsBankAccount(Resource): @staticmethod def find(token): return Configuration.gateway().us_bank_account.find(token) @staticmethod def sale(token, transactionRequest): transactionRequest["payment_method_token"] = token if not "options" in transactionRequest: transactionRequest["options"] = {} transactionRequest["options"]["submit_for_settlement"] = True return Configuration.gateway().transaction.sale(transactionRequest) @staticmethod def signature(): signature = [ "routing_number", "last_4", "account_type", "account_holder_name", "token", "image_url", "bank_name", "ach_mandate" ] return signature def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if attributes.get("ach_mandate") is not None: self.ach_mandate = AchMandate(gateway, self.ach_mandate) else: self.ach_mandate = None if attributes.get("verifications") is not None: self.verifications = [UsBankAccountVerification(gateway, v) for v in self.verifications] else: self.verifications = None braintree_python-3.57.1/braintree/iban_bank_account.py0000644000175000017500000000012313545202423021226 0ustar hlehlefrom braintree.resource import Resource class IbanBankAccount(Resource): pass braintree_python-3.57.1/braintree/testing_gateway.py0000644000175000017500000000526013545202423021013 0ustar hlehleimport braintree from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult from braintree.transaction import Transaction from braintree.exceptions.test_operation_performed_in_production_error import TestOperationPerformedInProductionError class TestingGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def make_past_due(self, subscription_id, number_of_days_past_due=1): self.__check_environment() self.config.http().put(self.config.base_merchant_path() + "/subscriptions/%s/make_past_due?days_past_due=%s" % (subscription_id, number_of_days_past_due)) def escrow_transaction(self, transaction_id): self.__check_environment() self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/escrow") def settle_transaction(self, transaction_id): self.__check_environment() return self.__create_result(self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/settle")) def settlement_confirm_transaction(self, transaction_id): self.__check_environment() return self.__create_result(self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/settlement_confirm")) def settlement_decline_transaction(self, transaction_id): self.__check_environment() return self.__create_result(self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/settlement_decline")) def settlement_pending_transaction(self, transaction_id): self.__check_environment() return self.__create_result(self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/settlement_pending")) def create_3ds_verification(self, merchant_account_id, params): self.__check_environment() response = self.config.http().post(self.config.base_merchant_path() + "/three_d_secure/create_verification/" + merchant_account_id, { "three_d_secure_verification": params }) return response["three_d_secure_verification"]["three_d_secure_token"] def __create_result(self, response): if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def __check_environment(self): if self.config.environment == braintree.Environment.Production: raise TestOperationPerformedInProductionError() braintree_python-3.57.1/braintree/document_upload.py0000644000175000017500000000257713545202423021007 0ustar hlehleimport mimetypes from braintree.successful_result import SuccessfulResult from braintree.resource import Resource from braintree.configuration import Configuration class DocumentUpload(Resource): """ A class representing a DocumentUpload. An example of creating a document upload with all available fields: result = braintree.DocumentUpload.create( { "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": open("path/to/file", "rb"), } ) For more information on DocumentUploads, see https://developers.braintreepayments.com/reference/request/document_upload/create """ class Kind(object): EvidenceDocument = "evidence_document" @staticmethod def create(params={}): """ Create a DocumentUpload File and Kind are required: result = braintree.DocumentUpload.create( { "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": open("path/to/file", "rb"), } ) """ return Configuration.gateway().document_upload.create(params) @staticmethod def create_signature(): return [ "kind", "file", ] def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-3.57.1/braintree/transaction_search.py0000644000175000017500000001263513545202423021473 0ustar hlehlefrom braintree.credit_card import CreditCard from braintree.search import Search from braintree.transaction import Transaction from braintree.util import Constants class TransactionSearch: billing_first_name = Search.TextNodeBuilder("billing_first_name") billing_company = Search.TextNodeBuilder("billing_company") billing_country_name = Search.TextNodeBuilder("billing_country_name") billing_extended_address = Search.TextNodeBuilder("billing_extended_address") billing_first_name = Search.TextNodeBuilder("billing_first_name") billing_last_name = Search.TextNodeBuilder("billing_last_name") billing_locality = Search.TextNodeBuilder("billing_locality") billing_postal_code = Search.TextNodeBuilder("billing_postal_code") billing_region = Search.TextNodeBuilder("billing_region") billing_street_address = Search.TextNodeBuilder("billing_street_address") credit_card_cardholder_name = Search.TextNodeBuilder("credit_card_cardholder_name") currency = Search.TextNodeBuilder("currency") customer_company = Search.TextNodeBuilder("customer_company") customer_email = Search.TextNodeBuilder("customer_email") customer_fax = Search.TextNodeBuilder("customer_fax") customer_first_name = Search.TextNodeBuilder("customer_first_name") customer_id = Search.TextNodeBuilder("customer_id") customer_last_name = Search.TextNodeBuilder("customer_last_name") customer_phone = Search.TextNodeBuilder("customer_phone") customer_website = Search.TextNodeBuilder("customer_website") id = Search.TextNodeBuilder("id") order_id = Search.TextNodeBuilder("order_id") payment_method_token = Search.TextNodeBuilder("payment_method_token") processor_authorization_code = Search.TextNodeBuilder("processor_authorization_code") europe_bank_account_iban = Search.TextNodeBuilder("europe_bank_account_iban") settlement_batch_id = Search.TextNodeBuilder("settlement_batch_id") shipping_company = Search.TextNodeBuilder("shipping_company") shipping_country_name = Search.TextNodeBuilder("shipping_country_name") shipping_extended_address = Search.TextNodeBuilder("shipping_extended_address") shipping_first_name = Search.TextNodeBuilder("shipping_first_name") shipping_last_name = Search.TextNodeBuilder("shipping_last_name") shipping_locality = Search.TextNodeBuilder("shipping_locality") shipping_postal_code = Search.TextNodeBuilder("shipping_postal_code") shipping_region = Search.TextNodeBuilder("shipping_region") shipping_street_address = Search.TextNodeBuilder("shipping_street_address") paypal_payer_email = Search.TextNodeBuilder("paypal_payer_email") paypal_payment_id = Search.TextNodeBuilder("paypal_payment_id") paypal_authorization_id = Search.TextNodeBuilder("paypal_authorization_id") credit_card_unique_identifier = Search.TextNodeBuilder("credit_card_unique_identifier") credit_card_expiration_date = Search.EqualityNodeBuilder("credit_card_expiration_date") credit_card_number = Search.PartialMatchNodeBuilder("credit_card_number") user = Search.MultipleValueNodeBuilder("user") ids = Search.MultipleValueNodeBuilder("ids") merchant_account_id = Search.MultipleValueNodeBuilder("merchant_account_id") payment_instrument_type = Search.MultipleValueNodeBuilder("payment_instrument_type") created_using = Search.MultipleValueNodeBuilder( "created_using", Constants.get_all_constant_values_from_class(Transaction.CreatedUsing) ) credit_card_card_type = Search.MultipleValueNodeBuilder( "credit_card_card_type", Constants.get_all_constant_values_from_class(CreditCard.CardType) ) credit_card_customer_location = Search.MultipleValueNodeBuilder( "credit_card_customer_location", Constants.get_all_constant_values_from_class(CreditCard.CustomerLocation) ) source = Search.MultipleValueNodeBuilder("source") status = Search.MultipleValueNodeBuilder( "status", Constants.get_all_constant_values_from_class(Transaction.Status) ) type = Search.MultipleValueNodeBuilder( "type", Constants.get_all_constant_values_from_class(Transaction.Type) ) refund = Search.KeyValueNodeBuilder("refund") amount = Search.RangeNodeBuilder("amount") authorization_expired_at = Search.RangeNodeBuilder("authorization_expired_at") authorized_at = Search.RangeNodeBuilder("authorized_at") created_at = Search.RangeNodeBuilder("created_at") disbursement_date = Search.RangeNodeBuilder("disbursement_date") dispute_date = Search.RangeNodeBuilder("dispute_date") failed_at = Search.RangeNodeBuilder("failed_at") gateway_rejected_at = Search.RangeNodeBuilder("gateway_rejected_at") processor_declined_at = Search.RangeNodeBuilder("processor_declined_at") settled_at = Search.RangeNodeBuilder("settled_at") submitted_for_settlement_at = Search.RangeNodeBuilder("submitted_for_settlement_at") voided_at = Search.RangeNodeBuilder("voided_at") braintree_python-3.57.1/braintree/exceptions/0000755000175000017500000000000013545202423017421 5ustar hlehlebraintree_python-3.57.1/braintree/exceptions/authentication_error.py0000644000175000017500000000062413545202423024225 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class AuthenticationError(BraintreeError): """ Raised when the client library cannot authenticate with the gateway. This generally means the public_key/private key are incorrect, or the user is not active. See https://developers.braintreepayments.com/reference/general/exceptions/python#authentication-error """ pass braintree_python-3.57.1/braintree/exceptions/authorization_error.py0000644000175000017500000000050513545202423024104 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class AuthorizationError(BraintreeError): """ Raised when the user does not have permission to complete the requested operation. See https://developers.braintreepayments.com/reference/general/exceptions/python#authorization-error """ pass braintree_python-3.57.1/braintree/exceptions/server_error.py0000644000175000017500000000050213545202423022507 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class ServerError(BraintreeError): """ Raised when the gateway raises an error. Please contant support at support@getbraintree.com. See https://developers.braintreepayments.com/reference/general/exceptions/python#server-error """ pass braintree_python-3.57.1/braintree/exceptions/configuration_error.py0000644000175000017500000000016713545202423024057 0ustar hlehlefrom braintree.exceptions.unexpected_error import UnexpectedError class ConfigurationError(UnexpectedError): pass braintree_python-3.57.1/braintree/exceptions/too_many_requests_error.py0000644000175000017500000000030413545202423024761 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class TooManyRequestsError(BraintreeError): """ Raised when the rate limit request threshold is exceeded. """ pass braintree_python-3.57.1/braintree/exceptions/down_for_maintenance_error.py0000644000175000017500000000045113545202423025363 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class DownForMaintenanceError(BraintreeError): """ Raised when the gateway is down for maintenance. See https://developers.braintreepayments.com/reference/general/exceptions/python#down-for-maintenance """ pass braintree_python-3.57.1/braintree/exceptions/http/0000755000175000017500000000000013545202423020400 5ustar hlehlebraintree_python-3.57.1/braintree/exceptions/http/timeout_error.py0000644000175000017500000000032613545202423023652 0ustar hlehlefrom braintree.exceptions.unexpected_error import UnexpectedError class TimeoutError(UnexpectedError): pass class ConnectTimeoutError(TimeoutError): pass class ReadTimeoutError(TimeoutError): pass braintree_python-3.57.1/braintree/exceptions/http/invalid_response_error.py0000644000175000017500000000017113545202423025526 0ustar hlehlefrom braintree.exceptions.unexpected_error import UnexpectedError class InvalidResponseError(UnexpectedError): pass braintree_python-3.57.1/braintree/exceptions/http/connection_error.py0000644000175000017500000000016413545202423024323 0ustar hlehlefrom braintree.exceptions.unexpected_error import UnexpectedError class ConnectionError(UnexpectedError): pass braintree_python-3.57.1/braintree/exceptions/http/__init__.py0000644000175000017500000000033213545202423022507 0ustar hlehlefrom braintree.exceptions.http.connection_error import ConnectionError from braintree.exceptions.http.invalid_response_error import InvalidResponseError from braintree.exceptions.http.timeout_error import TimeoutError braintree_python-3.57.1/braintree/exceptions/invalid_challenge_error.py0000644000175000017500000000016713545202423024640 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class InvalidChallengeError(BraintreeError): pass braintree_python-3.57.1/braintree/exceptions/not_found_error.py0000644000175000017500000000050213545202423023174 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class NotFoundError(BraintreeError): """ Raised when an object is not found in the gateway, such as a Transaction.find("bad_id"). See https://developers.braintreepayments.com/reference/general/exceptions/python#not-found-error """ pass braintree_python-3.57.1/braintree/exceptions/__init__.py0000644000175000017500000000175213545202423021537 0ustar hlehlefrom braintree.exceptions.authentication_error import AuthenticationError from braintree.exceptions.authorization_error import AuthorizationError from braintree.exceptions.down_for_maintenance_error import DownForMaintenanceError from braintree.exceptions.forged_query_string_error import ForgedQueryStringError from braintree.exceptions.invalid_challenge_error import InvalidChallengeError from braintree.exceptions.invalid_signature_error import InvalidSignatureError from braintree.exceptions.not_found_error import NotFoundError from braintree.exceptions.server_error import ServerError from braintree.exceptions.too_many_requests_error import TooManyRequestsError from braintree.exceptions.unexpected_error import UnexpectedError from braintree.exceptions.upgrade_required_error import UpgradeRequiredError from braintree.exceptions.test_operation_performed_in_production_error import TestOperationPerformedInProductionError from braintree.exceptions.configuration_error import ConfigurationError braintree_python-3.57.1/braintree/exceptions/invalid_signature_error.py0000644000175000017500000000016713545202423024717 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class InvalidSignatureError(BraintreeError): pass braintree_python-3.57.1/braintree/exceptions/unexpected_error.py0000644000175000017500000000024613545202423023352 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class UnexpectedError(BraintreeError): """ Raised for unknown or unexpected errors. """ pass braintree_python-3.57.1/braintree/exceptions/forged_query_string_error.py0000644000175000017500000000052313545202423025265 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class ForgedQueryStringError(BraintreeError): """ Raised when the query string has been forged or tampered with during a transparent redirect. See https://developers.braintreepayments.com/reference/general/exceptions/python#forged-query-string """ pass braintree_python-3.57.1/braintree/exceptions/braintree_error.py0000644000175000017500000000005213545202423023154 0ustar hlehleclass BraintreeError(Exception): pass braintree_python-3.57.1/braintree/exceptions/upgrade_required_error.py0000644000175000017500000000044713545202423024540 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class UpgradeRequiredError(BraintreeError): """ Raised for unsupported client library versions. See https://developers.braintreepayments.com/reference/general/exceptions/python#upgrade-required-error """ pass braintree_python-3.57.1/braintree/exceptions/test_operation_performed_in_production_error.py0000644000175000017500000000037213545202423031244 0ustar hlehlefrom braintree.exceptions.braintree_error import BraintreeError class TestOperationPerformedInProductionError(BraintreeError): """ Raised when an operation that should be used for testing is used in a production environment """ pass braintree_python-3.57.1/braintree/subscription_gateway.py0000644000175000017500000001023313545202423022056 0ustar hlehleimport re import braintree from braintree.subscription import Subscription from braintree.error_result import ErrorResult from braintree.exceptions.not_found_error import NotFoundError from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult from braintree.transaction import Transaction class SubscriptionGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def cancel(self, subscription_id): response = self.config.http().put(self.config.base_merchant_path() + "/subscriptions/" + subscription_id + "/cancel") if "subscription" in response: return SuccessfulResult({"subscription": Subscription(self.gateway, response["subscription"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def create(self, params={}): Resource.verify_keys(params, Subscription.create_signature()) response = self.config.http().post(self.config.base_merchant_path() + "/subscriptions", {"subscription": params}) if "subscription" in response: return SuccessfulResult({"subscription": Subscription(self.gateway, response["subscription"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def find(self, subscription_id): try: if subscription_id is None or subscription_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/subscriptions/" + subscription_id) return Subscription(self.gateway, response["subscription"]) except NotFoundError: raise NotFoundError("subscription with id " + repr(subscription_id) + " not found") def retry_charge(self, subscription_id, amount=None, submit_for_settlement=False): response = self.config.http().post(self.config.base_merchant_path() + "/transactions", {"transaction": { "amount": amount, "subscription_id": subscription_id, "type": Transaction.Type.Sale, "options": {"submit_for_settlement": submit_for_settlement} }}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def search(self, *query): if isinstance(query[0], list): query = query[0] response = self.config.http().post(self.config.base_merchant_path() + "/subscriptions/advanced_search_ids", {"search": self.__criteria(query)}) return ResourceCollection(query, response, self.__fetch) def update(self, subscription_id, params={}): Resource.verify_keys(params, Subscription.update_signature()) response = self.config.http().put(self.config.base_merchant_path() + "/subscriptions/" + subscription_id, {"subscription": params}) if "subscription" in response: return SuccessfulResult({"subscription": Subscription(self.gateway, response["subscription"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def __criteria(self, query): criteria = {} for term in query: if criteria.get(term.name): criteria[term.name] = dict(list(criteria[term.name].items()) + list(term.to_param().items())) else: criteria[term.name] = term.to_param() return criteria def __fetch(self, query, ids): criteria = self.__criteria(query) criteria["ids"] = braintree.subscription_search.SubscriptionSearch.ids.in_list(ids).to_param() response = self.config.http().post(self.config.base_merchant_path() + "/subscriptions/advanced_search", {"search": criteria}) return [Subscription(self.gateway, item) for item in ResourceCollection._extract_as_array(response["subscriptions"], "subscription")] braintree_python-3.57.1/braintree/facilitated_details.py0000644000175000017500000000015413545202423021570 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class FacilitatedDetails(AttributeGetter): pass braintree_python-3.57.1/braintree/address.py0000644000175000017500000000664013545202423017245 0ustar hlehlefrom braintree.successful_result import SuccessfulResult from braintree.error_result import ErrorResult from braintree.resource import Resource from braintree.configuration import Configuration class Address(Resource): """ A class representing Braintree Address objects. An example of creating an address with all available fields:: customer = braintree.Customer.create().customer result = braintree.Address.create({ "customer_id": customer.id, "first_name": "John", "last_name": "Doe", "company": "Braintree", "street_address": "111 First Street", "extended_address": "Apartment 1", "locality": "Chicago", "region": "IL", "postal_code": "60606", "country_name": "United States of America" }) print(result.customer.first_name) print(result.customer.last_name) """ def __repr__(self): detail_list = [ "customer_id", "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "first_name", "last_name", "locality", "postal_code", "region", "street_address", ] return super(Address, self).__repr__(detail_list) @staticmethod def create(params={}): """ Create an Address. A customer_id is required:: customer = braintree.Customer.create().customer result = braintree.Address.create({ "customer_id": customer.id, "first_name": "John", ... }) """ return Configuration.gateway().address.create(params) @staticmethod def delete(customer_id, address_id): """ Delete an address Given a customer_id and address_id:: result = braintree.Address.delete("my_customer_id", "my_address_id") """ return Configuration.gateway().address.delete(customer_id, address_id) @staticmethod def find(customer_id, address_id): """ Find an address, given a customer_id and address_id. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided customer_id/address_id are not found. :: address = braintree.Address.find("my_customer_id", "my_address_id") """ return Configuration.gateway().address.find(customer_id, address_id) @staticmethod def update(customer_id, address_id, params={}): """ Update an existing Address. A customer_id and address_id are required:: result = braintree.Address.update("my_customer_id", "my_address_id", { "first_name": "John" }) """ return Configuration.gateway().address.update(customer_id, address_id, params) @staticmethod def create_signature(): return ["company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "customer_id", "extended_address", "first_name", "last_name", "locality", "postal_code", "region", "street_address"] @staticmethod def update_signature(): return Address.create_signature() braintree_python-3.57.1/braintree/subscription_search.py0000644000175000017500000000165013545202423021665 0ustar hlehlefrom braintree.util import Constants from braintree import Subscription from braintree.search import Search class SubscriptionSearch: billing_cycles_remaining = Search.RangeNodeBuilder("billing_cycles_remaining") created_at = Search.RangeNodeBuilder("created_at") days_past_due = Search.RangeNodeBuilder("days_past_due") id = Search.TextNodeBuilder("id") ids = Search.MultipleValueNodeBuilder("ids") in_trial_period = Search.MultipleValueNodeBuilder("in_trial_period") merchant_account_id = Search.MultipleValueNodeBuilder("merchant_account_id") next_billing_date = Search.RangeNodeBuilder("next_billing_date") plan_id = Search.MultipleValueOrTextNodeBuilder("plan_id") price = Search.RangeNodeBuilder("price") status = Search.MultipleValueNodeBuilder("status", Constants.get_all_constant_values_from_class(Subscription.Status)) transaction_id = Search.TextNodeBuilder("transaction_id") braintree_python-3.57.1/braintree/dispute_search.py0000644000175000017500000000230313545202423020612 0ustar hlehlefrom braintree.search import Search class DisputeSearch: amount_disputed = Search.RangeNodeBuilder("amount_disputed") amount_won = Search.RangeNodeBuilder("amount_won") case_number = Search.TextNodeBuilder("case_number") customer_id = Search.TextNodeBuilder("customer_id") disbursement_date = Search.RangeNodeBuilder("disbursement_date") effective_date = Search.RangeNodeBuilder("effective_date") id = Search.TextNodeBuilder("id") kind = Search.MultipleValueNodeBuilder("kind") merchant_account_id = Search.MultipleValueNodeBuilder("merchant_account_id") reason = Search.MultipleValueNodeBuilder("reason") reason_code = Search.MultipleValueNodeBuilder("reason_code") received_date = Search.RangeNodeBuilder("received_date") reference_number = Search.TextNodeBuilder("reference_number") reply_by_date = Search.RangeNodeBuilder("reply_by_date") status = Search.MultipleValueNodeBuilder("status") transaction_id = Search.TextNodeBuilder("transaction_id") transaction_source = Search.MultipleValueNodeBuilder("transaction_source") braintree_python-3.57.1/braintree/us_bank_account_gateway.py0000644000175000017500000000153213545202423022472 0ustar hlehleimport braintree from braintree.us_bank_account import UsBankAccount from braintree.exceptions.not_found_error import NotFoundError class UsBankAccountGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def find(self, us_bank_account_token): try: if us_bank_account_token is None or us_bank_account_token.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_methods/us_bank_account/" + us_bank_account_token) if "us_bank_account" in response: return UsBankAccount(self.gateway, response["us_bank_account"]) except NotFoundError: raise NotFoundError("US bank account with token " + repr(us_bank_account_token) + " not found") braintree_python-3.57.1/braintree/paypal_account.py0000644000175000017500000000175713545202423020626 0ustar hlehleimport braintree from braintree.resource import Resource from braintree.configuration import Configuration class PayPalAccount(Resource): @staticmethod def find(paypal_account_token): return Configuration.gateway().paypal_account.find(paypal_account_token) @staticmethod def delete(paypal_account_token): return Configuration.gateway().paypal_account.delete(paypal_account_token) @staticmethod def update(paypal_account_token, params={}): return Configuration.gateway().paypal_account.update(paypal_account_token, params) @staticmethod def signature(): signature = [ "token", {"options": ["make_default"]} ] return signature def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] braintree_python-3.57.1/braintree/settlement_batch_summary.py0000644000175000017500000000115713545202423022720 0ustar hlehlefrom braintree.util.http import Http import braintree import warnings from braintree.exceptions.not_found_error import NotFoundError from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult from braintree.error_result import ErrorResult from braintree.resource import Resource from braintree.configuration import Configuration class SettlementBatchSummary(Resource): @staticmethod def generate(settlement_date, group_by_custom_field=None): return Configuration.gateway().settlement_batch_summary.generate(settlement_date, group_by_custom_field) braintree_python-3.57.1/braintree/validation_error.py0000644000175000017500000000071113545202423021154 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class ValidationError(AttributeGetter): """ A validation error returned from the server, with information about the error: * **attribute**: The field which had an error. * **code**: A numeric error code. See :class:`ErrorCodes ` * **message**: A description of the error. Note: error messages may change, but the code will not. """ pass braintree_python-3.57.1/braintree/samsung_pay_card.py0000644000175000017500000000141413545202423021131 0ustar hlehleimport braintree from braintree.address import Address from braintree.resource import Resource class SamsungPayCard(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "billing_address" in attributes: self.billing_address = Address(gateway, self.billing_address) else: self.billing_address = None if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] @property def expiration_date(self): return self.expiration_month + "/" + self.expiration_year @property def masked_number(self): return self.bin + "******" + self.last_4 braintree_python-3.57.1/braintree/customer.py0000644000175000017500000002537113545202423017463 0ustar hlehleimport warnings from braintree.util.http import Http from braintree.successful_result import SuccessfulResult from braintree.error_result import ErrorResult from braintree.resource import Resource from braintree.apple_pay_card import ApplePayCard from braintree.android_pay_card import AndroidPayCard from braintree.amex_express_checkout_card import AmexExpressCheckoutCard from braintree.credit_card import CreditCard from braintree.paypal_account import PayPalAccount from braintree.europe_bank_account import EuropeBankAccount from braintree.us_bank_account import UsBankAccount from braintree.coinbase_account import CoinbaseAccount from braintree.venmo_account import VenmoAccount from braintree.visa_checkout_card import VisaCheckoutCard from braintree.masterpass_card import MasterpassCard from braintree.address import Address from braintree.configuration import Configuration from braintree.ids_search import IdsSearch from braintree.exceptions.not_found_error import NotFoundError from braintree.resource_collection import ResourceCollection from braintree.transparent_redirect import TransparentRedirect from braintree.samsung_pay_card import SamsungPayCard class Customer(Resource): """ A class representing a customer. An example of creating an customer with all available fields:: result = braintree.Customer.create({ "id": "my_customer_id", "company": "Some company", "email": "john.doe@example.com", "fax": "123-555-1212", "first_name": "John", "last_name": "Doe", "phone": "123-555-1221", "website": "http://www.example.com", "credit_card": { "cardholder_name": "John Doe", "cvv": "123", "expiration_date": "12/2012", "number": "4111111111111111", "token": "my_token", "billing_address": { "first_name": "John", "last_name": "Doe", "company": "Braintree", "street_address": "111 First Street", "extended_address": "Unit 1", "locality": "Chicago", "postal_code": "60606", "region": "IL", "country_name": "United States of America" }, "options": { "verify_card": True, "verification_amount": "2.00" } }, "custom_fields": { "my_key": "some value" } }) print(result.customer.id) print(result.customer.first_name) For more information on Customers, see https://developers.braintreepayments.com/reference/request/customer/create/python """ def __repr__(self): detail_list = [ "id", "company", "created_at", "email", "fax", "first_name", "last_name", "merchant_id", "phone", "updated_at", "website", ] return super(Customer, self).__repr__(detail_list) @staticmethod def all(): """ Return a collection of all customers. """ return Configuration.gateway().customer.all() @staticmethod def confirm_transparent_redirect(query_string): """ Confirms a transparent redirect request. It expects the query string from the redirect request. The query string should _not_ include the leading "?" character. :: result = braintree.Customer.confirm_transparent_redirect_request("foo=bar&id=12345") """ warnings.warn("Please use TransparentRedirect.confirm instead", DeprecationWarning) return Configuration.gateway().customer.confirm_transparent_redirect(query_string) @staticmethod def create(params={}): """ Create a Customer No field is required:: result = braintree.Customer.create({ "company": "Some company", "first_name": "John" }) """ return Configuration.gateway().customer.create(params) @staticmethod def delete(customer_id): """ Delete a customer Given a customer_id:: result = braintree.Customer.delete("my_customer_id") """ return Configuration.gateway().customer.delete(customer_id) @staticmethod def find(customer_id, association_filter_id=None): """ Find an customer, given a customer_id. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided customer_id is not found. :: customer = braintree.Customer.find("my_customer_id") """ return Configuration.gateway().customer.find(customer_id, association_filter_id) @staticmethod def search(*query): return Configuration.gateway().customer.search(*query) @staticmethod def tr_data_for_create(tr_data, redirect_url): """ Builds tr_data for creating a Customer. """ return Configuration.gateway().customer.tr_data_for_create(tr_data, redirect_url) @staticmethod def tr_data_for_update(tr_data, redirect_url): """ Builds tr_data for updating a Customer. """ return Configuration.gateway().customer.tr_data_for_update(tr_data, redirect_url) @staticmethod def transparent_redirect_create_url(): """ Returns the url to use for creating Customers through transparent redirect. """ warnings.warn("Please use TransparentRedirect.url instead", DeprecationWarning) return Configuration.gateway().customer.transparent_redirect_create_url() @staticmethod def transparent_redirect_update_url(): """ Returns the url to use for updating Customers through transparent redirect. """ warnings.warn("Please use TransparentRedirect.url instead", DeprecationWarning) return Configuration.gateway().customer.transparent_redirect_update_url() @staticmethod def update(customer_id, params={}): """ Update an existing Customer By customer_id. The params are similar to create:: result = braintree.Customer.update("my_customer_id", { "last_name": "Smith" }) """ return Configuration.gateway().customer.update(customer_id, params) @staticmethod def create_signature(): return [ "company", "email", "fax", "first_name", "id", "last_name", "phone", "website", "device_data", "device_session_id", "fraud_merchant_id", "payment_method_nonce", {"risk_data": ["customer_browser", "customer_ip"]}, {"credit_card": CreditCard.create_signature()}, {"custom_fields": ["__any_key__"]}, {"options": [{"paypal": [ "payee_email", "order_id", "custom_field", "description", "amount", { "shipping": Address.create_signature() } ]}]}, ] @staticmethod def update_signature(): return [ "company", "email", "fax", "first_name", "id", "last_name", "phone", "website", "device_data", "device_session_id", "fraud_merchant_id", "payment_method_nonce", "default_payment_method_token", {"credit_card": CreditCard.signature("update_via_customer")}, {"custom_fields": ["__any_key__"]}, {"options": [{"paypal": [ "payee_email", "order_id", "custom_field", "description", "amount", { "shipping": Address.create_signature() } ]}]}, ] def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.payment_methods = [] if "credit_cards" in attributes: self.credit_cards = [CreditCard(gateway, credit_card) for credit_card in self.credit_cards] self.payment_methods += self.credit_cards if "addresses" in attributes: self.addresses = [Address(gateway, address) for address in self.addresses] if "paypal_accounts" in attributes: self.paypal_accounts = [PayPalAccount(gateway, paypal_account) for paypal_account in self.paypal_accounts] self.payment_methods += self.paypal_accounts if "apple_pay_cards" in attributes: self.apple_pay_cards = [ApplePayCard(gateway, apple_pay_card) for apple_pay_card in self.apple_pay_cards] self.payment_methods += self.apple_pay_cards if "android_pay_cards" in attributes: self.android_pay_cards = [AndroidPayCard(gateway, android_pay_card) for android_pay_card in self.android_pay_cards] self.payment_methods += self.android_pay_cards if "amex_express_checkout_cards" in attributes: self.amex_express_checkout_cards = [AmexExpressCheckoutCard(gateway, amex_express_checkout_card) for amex_express_checkout_card in self.amex_express_checkout_cards] self.payment_methods += self.amex_express_checkout_cards if "europe_bank_accounts" in attributes: self.europe_bank_accounts = [EuropeBankAccount(gateway, europe_bank_account) for europe_bank_account in self.europe_bank_accounts] self.payment_methods += self.europe_bank_accounts if "coinbase_accounts" in attributes: self.coinbase_accounts = [CoinbaseAccount(gateway, coinbase_account) for coinbase_account in self.coinbase_accounts] self.payment_methods += self.coinbase_accounts if "venmo_accounts" in attributes: self.venmo_accounts = [VenmoAccount(gateway, venmo_account) for venmo_account in self.venmo_accounts] self.payment_methods += self.venmo_accounts if "us_bank_accounts" in attributes: self.us_bank_accounts = [UsBankAccount(gateway, us_bank_account) for us_bank_account in self.us_bank_accounts] self.payment_methods += self.us_bank_accounts if "visa_checkout_cards" in attributes: self.visa_checkout_cards = [VisaCheckoutCard(gateway, visa_checkout_card) for visa_checkout_card in self.visa_checkout_cards] self.payment_methods += self.visa_checkout_cards if "masterpass_cards" in attributes: self.masterpass_cards = [MasterpassCard(gateway, masterpass_card) for masterpass_card in self.masterpass_cards] self.payment_methods += self.masterpass_cards if "samsung_pay_cards" in attributes: self.samsung_pay_cards = [SamsungPayCard(gateway, samsung_pay_card) for samsung_pay_card in self.samsung_pay_cards] self.payment_methods += self.samsung_pay_cards braintree_python-3.57.1/braintree/discount_gateway.py0000644000175000017500000000103113545202423021156 0ustar hlehleimport braintree from braintree.discount import Discount from braintree.resource_collection import ResourceCollection class DiscountGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def all(self): response = self.config.http().get(self.config.base_merchant_path() + "/discounts/") discounts = {"discount": response["discounts"]} return [Discount(self.gateway, item) for item in ResourceCollection._extract_as_array(discounts, "discount")] braintree_python-3.57.1/braintree/environment.py0000644000175000017500000000622013545202423020156 0ustar hlehleimport os import inspect from braintree.exceptions.configuration_error import ConfigurationError class Environment(object): """ A class representing which environment the client library is using. Pass in one of the following values as the first argument to :class:`braintree.Configuration.configure() ` :: braintree.Environment.Sandbox braintree.Environment.Production """ def __init__(self, name, server, port, auth_url, is_ssl, ssl_certificate, graphql_server="", graphql_port=""): self.__name__ = name self.__server = server self.__port = port self.is_ssl = is_ssl self.ssl_certificate = ssl_certificate self.__auth_url = auth_url self.__graphql_server = graphql_server self.__graphql_port = graphql_port @property def base_url(self): return "%s%s:%s" % (self.protocol, self.server, self.port) @property def port(self): return int(self.__port) @property def auth_url(self): return self.__auth_url @property def protocol(self): return self.__port == "443" and "https://" or "http://" @property def server(self): return self.__server @property def server_and_port(self): return self.__server + ":" + self.__port @property def graphql_server(self): return self.__graphql_server @property def graphql_port(self): return self.__graphql_port @property def graphql_server_and_port(self): return self.__graphql_server + ":" + self.__graphql_port @staticmethod def parse_environment(environment): if isinstance(environment, Environment) or environment is None: return environment try: return Environment.All[environment] except KeyError as e: raise ConfigurationError("Unable to process supplied environment") @staticmethod def braintree_root(): return os.path.dirname(inspect.getfile(Environment)) def __str__(self): return self.__name__ Environment.Development = Environment("development", "localhost", os.getenv("GATEWAY_PORT") or "3000", "http://auth.venmo.dev:9292", False, None, "graphql.bt.local", "8080") Environment.QA = Environment("qa", "gateway.qa.braintreepayments.com", "443", "http://auth.qa.venmo.com", True, Environment.braintree_root() + "/ssl/api_braintreegateway_com.ca.crt", "payments-qa.dev.braintree-api.com", "443") Environment.Sandbox = Environment("sandbox", "api.sandbox.braintreegateway.com", "443", "https://auth.sandbox.venmo.com", True, Environment.braintree_root() + "/ssl/api_braintreegateway_com.ca.crt", "payments.sandbox.braintree-api.com", "443") Environment.Production = Environment("production", "api.braintreegateway.com", "443", "https://auth.venmo.com", True, Environment.braintree_root() + "/ssl/api_braintreegateway_com.ca.crt", "payments.braintree-api.com", "443") Environment.All = { "development": Environment.Development, "integration": Environment.Development, "qa": Environment.QA, "sandbox": Environment.Sandbox, "production": Environment.Production } braintree_python-3.57.1/braintree/plan.py0000644000175000017500000000133213545202423016543 0ustar hlehlefrom braintree.util.http import Http import braintree from braintree.add_on import AddOn from braintree.configuration import Configuration from braintree.discount import Discount from braintree.resource_collection import ResourceCollection from braintree.resource import Resource class Plan(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "add_ons" in attributes: self.add_ons = [AddOn(gateway, add_on) for add_on in self.add_ons] if "discounts" in attributes: self.discounts = [Discount(gateway, discount) for discount in self.discounts] @staticmethod def all(): return Configuration.gateway().plan.all() braintree_python-3.57.1/braintree/us_bank_account_verification_search.py0000644000175000017500000000242713545202423025044 0ustar hlehlefrom braintree.us_bank_account import UsBankAccount from braintree.us_bank_account_verification import UsBankAccountVerification from braintree.search import Search from braintree.util import Constants class UsBankAccountVerificationSearch: # Text fields account_holder_name = Search.TextNodeBuilder("account_holder_name") customer_email = Search.TextNodeBuilder("customer_email") customer_id = Search.TextNodeBuilder("customer_id") id = Search.TextNodeBuilder("id") payment_method_token = Search.TextNodeBuilder("payment_method_token") routing_number = Search.TextNodeBuilder("routing_number") # Multiple value fields ids = Search.MultipleValueNodeBuilder("ids") status = Search.MultipleValueNodeBuilder( "status", Constants.get_all_constant_values_from_class(UsBankAccountVerification.Status) ) verification_method = Search.MultipleValueNodeBuilder( "verification_method", Constants.get_all_constant_values_from_class(UsBankAccountVerification.VerificationMethod) ) # Range fields created_at = Search.RangeNodeBuilder("created_at") # Equality fields account_type = Search.EqualityNodeBuilder("account_type") # Ends-with fieds account_number = Search.EndsWithNodeBuilder("account_number") braintree_python-3.57.1/braintree/signature_service.py0000644000175000017500000000101113545202423021324 0ustar hlehleimport urllib from braintree.util.crypto import Crypto class SignatureService(object): def __init__(self, private_key, hashfunc=Crypto.sha1_hmac_hash): self.private_key = private_key self.hmac_hash = hashfunc def sign(self, data): equalities = ['%s=%s' % (str(key), str(data[key])) for key in data] data_string = '&'.join(equalities) return "%s|%s" % (self.hash(data_string), data_string) def hash(self, data): return self.hmac_hash(self.private_key, data) braintree_python-3.57.1/braintree/descriptor.py0000644000175000017500000000024713545202423017773 0ustar hlehlefrom braintree.resource import Resource class Descriptor(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-3.57.1/braintree/us_bank_account_verification.py0000644000175000017500000000501013545202423023506 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter from braintree.configuration import Configuration import braintree.us_bank_account class UsBankAccountVerification(AttributeGetter): class Status(object): """ Constants representing transaction statuses. Available statuses are: * braintree.UsBankAccountVerification.Status.Failed * braintree.UsBankAccountVerification.Status.GatewayRejected * braintree.UsBankAccountVerification.Status.ProcessorDeclined * braintree.UsBankAccountVerification.Status.Unrecognized * braintree.UsBankAccountVerification.Status.Verified * braintree.UsBankAccountVerification.Status.Pending """ Failed = "failed" GatewayRejected = "gateway_rejected" ProcessorDeclined = "processor_declined" Unrecognized = "unrecognized" Verified = "verified" Pending = "pending" class VerificationMethod(object): """ Constants representing transaction statuses. Available statuses are: * braintree.UsBankAccountVerification.VerificationMethod.NetworkCheck * braintree.UsBankAccountVerification.VerificationMethod.IndependentCheck * braintree.UsBankAccountVerification.VerificationMethod.TokenizedCheck * braintree.UsBankAccountVerification.VerificationMethod.MicroTransfers """ NetworkCheck = "network_check" IndependentCheck = "independent_check" TokenizedCheck = "tokenized_check" MicroTransfers = "micro_transfers" def __init__(self, gateway, attributes): AttributeGetter.__init__(self, attributes) if attributes.get("us_bank_account") is not None: self.us_bank_account = braintree.us_bank_account.UsBankAccount(gateway, self.us_bank_account) else: self.us_bank_account = None @staticmethod def confirm_micro_transfer_amounts(verification_id, amounts): return Configuration.gateway().us_bank_account_verification.confirm_micro_transfer_amounts(verification_id, amounts) @staticmethod def find(verification_id): return Configuration.gateway().us_bank_account_verification.find(verification_id) @staticmethod def search(*query): return Configuration.gateway().us_bank_account_verification.search(*query) def __eq__(self, other): if not isinstance(other, UsBankAccountVerification): return False return self.id == other.id braintree_python-3.57.1/braintree/payment_method_gateway.py0000644000175000017500000001417413545202423022357 0ustar hlehleimport braintree from braintree.apple_pay_card import ApplePayCard from braintree.credit_card import CreditCard from braintree.payment_method import PaymentMethod from braintree.paypal_account import PayPalAccount from braintree.europe_bank_account import EuropeBankAccount from braintree.coinbase_account import CoinbaseAccount from braintree.android_pay_card import AndroidPayCard from braintree.amex_express_checkout_card import AmexExpressCheckoutCard from braintree.venmo_account import VenmoAccount from braintree.us_bank_account import UsBankAccount from braintree.visa_checkout_card import VisaCheckoutCard from braintree.masterpass_card import MasterpassCard from braintree.samsung_pay_card import SamsungPayCard from braintree.unknown_payment_method import UnknownPaymentMethod from braintree.error_result import ErrorResult from braintree.exceptions.not_found_error import NotFoundError from braintree.ids_search import IdsSearch from braintree.payment_method_nonce import PaymentMethodNonce from braintree.payment_method_parser import parse_payment_method from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult import sys if sys.version_info[0] == 2: from urllib import urlencode else: from urllib.parse import urlencode class PaymentMethodGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create(self, params={}): Resource.verify_keys(params, PaymentMethod.create_signature()) return self._post("/payment_methods", {"payment_method": params}) def find(self, payment_method_token): try: if payment_method_token is None or payment_method_token.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_methods/any/" + payment_method_token) return parse_payment_method(self.gateway, response) except NotFoundError: raise NotFoundError("payment method with token " + repr(payment_method_token) + " not found") def update(self, payment_method_token, params): Resource.verify_keys(params, PaymentMethod.update_signature()) try: if payment_method_token is None or payment_method_token.strip() == "": raise NotFoundError() return self._put( "/payment_methods/any/" + payment_method_token, {"payment_method": params} ) except NotFoundError: raise NotFoundError("payment method with token " + repr(payment_method_token) + " not found") def delete(self, payment_method_token, options={}): Resource.verify_keys(options, PaymentMethod.delete_signature()) query_param = "" if options: if 'revoke_all_grants' in options: options['revoke_all_grants'] = str(options['revoke_all_grants']).lower() query_param = "?" + urlencode(options) self.config.http().delete(self.config.base_merchant_path() + "/payment_methods/any/" + payment_method_token + query_param) return SuccessfulResult() def grant(self, payment_method_token, options=None): if payment_method_token is None or not str(payment_method_token).strip(): raise ValueError("payment method token cannot be empty or blank") try: if isinstance(options, bool): options = { "allow_vaulting": options } elif options is None: options = {} self.options = options params = { "payment_method": { "shared_payment_method_token": payment_method_token } } params["payment_method"].update(options), return self._post( "/payment_methods/grant", params, "payment_method_nonce" ) except NotFoundError: raise NotFoundError("payment method with payment_method_token " + repr(payment_method_token) + " not found") def revoke(self, payment_method_token): if payment_method_token is None or not str(payment_method_token).strip(): raise ValueError try: return self._post( "/payment_methods/revoke", { "payment_method": { "shared_payment_method_token": payment_method_token } }, "revoke" ) except NotFoundError: raise NotFoundError("payment method with payment_method_token " + repr(payment_method_token) + " not found") def _post(self, url, params={}, result_key="payment_method"): response = self.config.http().post(self.config.base_merchant_path() + url, params) if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) elif result_key is "revoke" and response.get("success", False): return SuccessfulResult() elif result_key is "payment_method_nonce": payment_method_nonce = self._parse_payment_method_nonce(response) return SuccessfulResult({result_key: payment_method_nonce}) else: payment_method = parse_payment_method(self.gateway, response) return SuccessfulResult({result_key: payment_method}) return response def _put(self, url, params={}): response = self.config.http().put(self.config.base_merchant_path() + url, params) if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: payment_method = parse_payment_method(self.gateway, response) return SuccessfulResult({"payment_method": payment_method}) def _parse_payment_method_nonce(self, response): if "payment_method_nonce" in response: return PaymentMethodNonce(self.gateway, response["payment_method_nonce"]) raise ValueError("payment_method_nonce not present in response") braintree_python-3.57.1/braintree/credit_card_gateway.py0000644000175000017500000001326513545202423021605 0ustar hlehleimport braintree from braintree.credit_card import CreditCard from braintree.error_result import ErrorResult from braintree.exceptions.not_found_error import NotFoundError from braintree.ids_search import IdsSearch from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult from braintree.transparent_redirect import TransparentRedirect class CreditCardGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def confirm_transparent_redirect(self, query_string): id = self.gateway.transparent_redirect._parse_and_validate_query_string(query_string)["id"][0] return self._post("/payment_methods/all/confirm_transparent_redirect_request", {"id": id}) def create(self, params={}): Resource.verify_keys(params, CreditCard.create_signature()) return self._post("/payment_methods", {"credit_card": params}) def delete(self, credit_card_token): self.config.http().delete(self.config.base_merchant_path() + "/payment_methods/credit_card/" + credit_card_token) return SuccessfulResult() def expired(self): response = self.config.http().post(self.config.base_merchant_path() + "/payment_methods/all/expired_ids") return ResourceCollection(None, response, self.__fetch_expired) def expiring_between(self, start_date, end_date): formatted_start_date = start_date.strftime("%m%Y") formatted_end_date = end_date.strftime("%m%Y") query = "start=%s&end=%s" % (formatted_start_date, formatted_end_date) response = self.config.http().post(self.config.base_merchant_path() + "/payment_methods/all/expiring_ids?" + query) return ResourceCollection(query, response, self.__fetch_existing_between) def find(self, credit_card_token): try: if credit_card_token is None or credit_card_token.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_methods/credit_card/" + credit_card_token) return CreditCard(self.gateway, response["credit_card"]) except NotFoundError: raise NotFoundError("payment method with token " + repr(credit_card_token) + " not found") def forward(self, credit_card_token, receiving_merchant_id): raise NotFoundError("This method of forwarding payment methods is no longer supported. Please consider the Grant API for similar functionality.") def from_nonce(self, nonce): try: if nonce is None or nonce.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_methods/from_nonce/" + nonce) return CreditCard(self.gateway, response["credit_card"]) except NotFoundError: raise NotFoundError("payment method with nonce " + repr(nonce) + " locked, consumed or not found") def tr_data_for_create(self, tr_data, redirect_url): Resource.verify_keys(tr_data, [{"credit_card": CreditCard.create_signature()}]) tr_data["kind"] = TransparentRedirect.Kind.CreatePaymentMethod return self.gateway.transparent_redirect.tr_data(tr_data, redirect_url) def tr_data_for_update(self, tr_data, redirect_url): Resource.verify_keys(tr_data, ["payment_method_token", {"credit_card": CreditCard.update_signature()}]) tr_data["kind"] = TransparentRedirect.Kind.UpdatePaymentMethod return self.gateway.transparent_redirect.tr_data(tr_data, redirect_url) def transparent_redirect_create_url(self): return self.config.base_url() + self.config.base_merchant_path() + "/payment_methods/all/create_via_transparent_redirect_request" def transparent_redirect_update_url(self): return self.config.base_url() + self.config.base_merchant_path() + "/payment_methods/all/update_via_transparent_redirect_request" def update(self, credit_card_token, params={}): Resource.verify_keys(params, CreditCard.update_signature()) response = self.config.http().put(self.config.base_merchant_path() + "/payment_methods/credit_card/" + credit_card_token, {"credit_card": params}) if "credit_card" in response: return SuccessfulResult({"credit_card": CreditCard(self.gateway, response["credit_card"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def __fetch_expired(self, query, ids): criteria = {} criteria["ids"] = IdsSearch.ids.in_list(ids).to_param() response = self.config.http().post(self.config.base_merchant_path() + "/payment_methods/all/expired", {"search": criteria}) return [CreditCard(self.gateway, item) for item in ResourceCollection._extract_as_array(response["payment_methods"], "credit_card")] def __fetch_existing_between(self, query, ids): criteria = {} criteria["ids"] = IdsSearch.ids.in_list(ids).to_param() response = self.config.http().post(self.config.base_merchant_path() + "/payment_methods/all/expiring?" + query, {"search": criteria}) return [CreditCard(self.gateway, item) for item in ResourceCollection._extract_as_array(response["payment_methods"], "credit_card")] def _post(self, url, params={}): response = self.config.http().post(self.config.base_merchant_path() + url, params) if "credit_card" in response: return SuccessfulResult({"credit_card": CreditCard(self.gateway, response["credit_card"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) braintree_python-3.57.1/braintree/settlement_batch_summary_gateway.py0000644000175000017500000000206213545202423024435 0ustar hlehleimport braintree from braintree.resource import Resource from braintree.settlement_batch_summary import SettlementBatchSummary from braintree.successful_result import SuccessfulResult from braintree.error_result import ErrorResult class SettlementBatchSummaryGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def generate(self, settlement_date, group_by_custom_field=None): criteria = {"settlement_date": settlement_date} if group_by_custom_field: criteria["group_by_custom_field"] = group_by_custom_field response = self.config.http().post(self.config.base_merchant_path() + '/settlement_batch_summary', {"settlement_batch_summary": criteria}) if "settlement_batch_summary" in response: return SuccessfulResult({"settlement_batch_summary": SettlementBatchSummary(self.gateway, response["settlement_batch_summary"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) braintree_python-3.57.1/braintree/dispute_gateway.py0000644000175000017500000001577013545202423021022 0ustar hlehleimport braintree import re import warnings from braintree.dispute import Dispute from braintree.dispute_details import DisputeEvidence from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult from braintree.exceptions.not_found_error import NotFoundError from braintree.paginated_result import PaginatedResult from braintree.paginated_collection import PaginatedCollection from braintree.resource_collection import ResourceCollection class DisputeGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def accept(self, dispute_id): try: if dispute_id is None or dispute_id.strip() == "": raise NotFoundError() response = self.config.http().put(self.config.base_merchant_path() + "/disputes/" + dispute_id + "/accept") if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: return SuccessfulResult() except NotFoundError: raise NotFoundError("dispute with id " + repr(dispute_id) + " not found") def add_file_evidence(self, dispute_id, document_upload_id_or_request): request = document_upload_id_or_request if isinstance(document_upload_id_or_request, dict) else { "document_id": document_upload_id_or_request } try: if dispute_id is None or dispute_id.strip() == "": raise NotFoundError() if request.get("category") is not None and not isinstance(request["category"], str): raise ValueError("category must be a string") if request.get("document_id") is None or request["document_id"].strip() == "": raise ValueError("document_id cannot be blank") response = self.config.http().post(self.config.base_merchant_path() + "/disputes/" + dispute_id + "/evidence", { "evidence": { "document_upload_id": request.get("document_id"), "category": request.get("category") } }) if "evidence" in response: return SuccessfulResult({ "evidence": DisputeEvidence(response["evidence"]) }) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) except NotFoundError: raise NotFoundError("dispute with id " + repr(dispute_id) + " not found") def add_text_evidence(self, dispute_id, content_or_request): request = content_or_request if isinstance(content_or_request, dict) else { "content": content_or_request } if dispute_id is None or dispute_id.strip() == "": raise NotFoundError("dispute_id cannot be blank") if request.get("content") is None or request["content"].strip() == "": raise ValueError("content cannot be blank") try: if request.get("sequence_number") is not None: request["sequence_number"] = int(request["sequence_number"]) except ValueError: raise ValueError("sequence_number must be an integer") category = request.get("category", request.get("tag")) if "tag" in request.keys(): warnings.warn("Please use category instead", DeprecationWarning) if category is not None and not isinstance(category, str): raise ValueError("category must be a string") try: response = self.config.http().post(self.config.base_merchant_path() + "/disputes/" + dispute_id + "/evidence", { "evidence": { "comments": request.get("content"), "category": category, "sequence_number": request.get("sequence_number") } }) if "evidence" in response: return SuccessfulResult({ "evidence": DisputeEvidence(response["evidence"]) }) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) except NotFoundError: raise NotFoundError("Dispute with ID " + repr(dispute_id) + " not found") def finalize(self, dispute_id): try: if dispute_id is None or dispute_id.strip() == "": raise NotFoundError() response = self.config.http().put(self.config.base_merchant_path() + "/disputes/" + dispute_id + "/finalize") if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: return SuccessfulResult() except NotFoundError: raise NotFoundError("dispute with id " + repr(dispute_id) + " not found") def find(self, dispute_id): try: if dispute_id is None or dispute_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/disputes/" + dispute_id) return Dispute(response["dispute"]) except NotFoundError: raise NotFoundError("dispute with id " + repr(dispute_id) + " not found") def remove_evidence(self, dispute_id, evidence_id): try: if dispute_id is None or dispute_id.strip() == "": raise NotFoundError() if evidence_id is None or evidence_id.strip() == "": raise NotFoundError() response = self.config.http().delete(self.config.base_merchant_path() + "/disputes/" + dispute_id + "/evidence/" + evidence_id) if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: return SuccessfulResult() except NotFoundError: raise NotFoundError("evidence with id " + repr(evidence_id) + " for dispute with id " + repr(dispute_id) + " not found") def search(self, *query): if isinstance(query[0], list): query = query[0] self.search_criteria = self.__criteria(query) pc = PaginatedCollection(self.__fetch_disputes) return SuccessfulResult({"disputes": pc}) def __fetch_disputes(self, page): response = self.config.http().post(self.config.base_merchant_path() + "/disputes/advanced_search?page=" + str(page), {"search": self.search_criteria}) body = response["disputes"] disputes = [Dispute(item) for item in ResourceCollection._extract_as_array(response["disputes"], "dispute")] return PaginatedResult(body["total_items"], body["page_size"], disputes) def __criteria(self, query): criteria = {} for term in query: if criteria.get(term.name): criteria[term.name] = dict(list(criteria[term.name].items()) + list(term.to_param().items())) else: criteria[term.name] = term.to_param() return criteria braintree_python-3.57.1/braintree/risk_data.py0000644000175000017500000000014213545202423017550 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class RiskData(AttributeGetter): pass braintree_python-3.57.1/braintree/transaction_gateway.py0000644000175000017500000002252413545202423021665 0ustar hlehleimport braintree from braintree.error_result import ErrorResult from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult from braintree.transaction import Transaction from braintree.transparent_redirect import TransparentRedirect from braintree.exceptions.not_found_error import NotFoundError from braintree.exceptions.down_for_maintenance_error import DownForMaintenanceError class TransactionGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def clone_transaction(self, transaction_id, params): Resource.verify_keys(params, Transaction.clone_signature()) return self._post("/transactions/" + transaction_id + "/clone", {"transaction-clone": params}) def cancel_release(self, transaction_id): response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/cancel_release", {}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def confirm_transparent_redirect(self, query_string): id = self.gateway.transparent_redirect._parse_and_validate_query_string(query_string)["id"][0] return self._post("/transactions/all/confirm_transparent_redirect_request", {"id": id}) def create(self, params): Resource.verify_keys(params, Transaction.create_signature()) return self._post("/transactions", {"transaction": params}) def find(self, transaction_id): try: if transaction_id is None or transaction_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/transactions/" + transaction_id) return Transaction(self.gateway, response["transaction"]) except NotFoundError: raise NotFoundError("transaction with id " + repr(transaction_id) + " not found") def hold_in_escrow(self, transaction_id): """ Holds an existing submerchant transaction for escrow. It expects a transaction_id. :: result = braintree.Transaction.hold_in_escrow("my_transaction_id") """ response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/hold_in_escrow", {}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def refund(self, transaction_id, amount_or_options=None): """ Refunds an existing transaction. It expects a transaction_id. :: result = braintree.Transaction.refund("my_transaction_id") """ if isinstance(amount_or_options, dict): options = amount_or_options else: options = { "amount": amount_or_options } Resource.verify_keys(options, Transaction.refund_signature()) response = self.config.http().post(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/refund", {"transaction": options}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def sale(self, params): params.update({"type": "sale"}) return self.create(params) def search(self, *query): if isinstance(query[0], list): query = query[0] response = self.config.http().post(self.config.base_merchant_path() + "/transactions/advanced_search_ids", {"search": self.__criteria(query)}) if "search_results" in response: return ResourceCollection(query, response, self.__fetch) else: raise DownForMaintenanceError("search timeout") def release_from_escrow(self, transaction_id): response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/release_from_escrow", {}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def submit_for_settlement(self, transaction_id, amount=None, params={}): Resource.verify_keys(params, Transaction.submit_for_settlement_signature()) transaction_params = {"amount": amount} transaction_params.update(params) response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/submit_for_settlement", {"transaction": transaction_params}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def update_details(self, transaction_id, params={}): Resource.verify_keys(params, Transaction.update_details_signature()) response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/update_details", {"transaction": params}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def submit_for_partial_settlement(self, transaction_id, amount, params={}): Resource.verify_keys(params, Transaction.submit_for_settlement_signature()) transaction_params = {"amount": amount} transaction_params.update(params) response = self.config.http().post(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/submit_for_partial_settlement", {"transaction": transaction_params}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def tr_data_for_credit(self, tr_data, redirect_url): if "transaction" not in tr_data: tr_data["transaction"] = {} tr_data["transaction"]["type"] = Transaction.Type.Credit Resource.verify_keys(tr_data, [{"transaction": Transaction.create_signature()}]) tr_data["kind"] = TransparentRedirect.Kind.CreateTransaction return self.gateway.transparent_redirect.tr_data(tr_data, redirect_url) def tr_data_for_sale(self, tr_data, redirect_url): if "transaction" not in tr_data: tr_data["transaction"] = {} tr_data["transaction"]["type"] = Transaction.Type.Sale Resource.verify_keys(tr_data, [{"transaction": Transaction.create_signature()}]) tr_data["kind"] = TransparentRedirect.Kind.CreateTransaction return self.gateway.transparent_redirect.tr_data(tr_data, redirect_url) def transparent_redirect_create_url(self): return self.config.base_url() + self.config.base_merchant_path() + "/transactions/all/create_via_transparent_redirect_request" def void(self, transaction_id): response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/void") if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def __fetch(self, query, ids): criteria = self.__criteria(query) criteria["ids"] = braintree.transaction_search.TransactionSearch.ids.in_list(ids).to_param() response = self.config.http().post(self.config.base_merchant_path() + "/transactions/advanced_search", {"search": criteria}) if "credit_card_transactions" in response: return [Transaction(self.gateway, item) for item in ResourceCollection._extract_as_array(response["credit_card_transactions"], "transaction")] else: raise DownForMaintenanceError("search timeout") def __criteria(self, query): criteria = {} for term in query: if criteria.get(term.name): criteria[term.name] = dict(list(criteria[term.name].items()) + list(term.to_param().items())) else: criteria[term.name] = term.to_param() return criteria def _post(self, url, params={}): response = self.config.http().post(self.config.base_merchant_path() + url, params) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) braintree_python-3.57.1/braintree/ideal_payment_gateway.py0000644000175000017500000000200713545202423022145 0ustar hlehleimport braintree from braintree.ideal_payment import IdealPayment from braintree.exceptions.not_found_error import NotFoundError # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. class IdealPaymentGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def find(self, ideal_payment_id): try: if ideal_payment_id is None or ideal_payment_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/ideal_payments/" + ideal_payment_id) if "ideal_payment" in response: return IdealPayment(self.gateway, response["ideal_payment"]) except NotFoundError: raise NotFoundError("iDEAL payment with token" + repr(ideal_payment_id) + " not found") braintree_python-3.57.1/braintree/bin_data.py0000644000175000017500000000014113545202423017347 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class BinData(AttributeGetter): pass braintree_python-3.57.1/braintree/transparent_redirect_gateway.py0000644000175000017500000000631213545202423023557 0ustar hlehleimport cgi from datetime import datetime import braintree from braintree.util.crypto import Crypto from braintree.error_result import ErrorResult from braintree.exceptions.forged_query_string_error import ForgedQueryStringError from braintree.util.http import Http from braintree.signature_service import SignatureService from braintree.successful_result import SuccessfulResult from braintree.transparent_redirect import TransparentRedirect class TransparentRedirectGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def confirm(self, query_string): """ Confirms a transparent redirect request. It expects the query string from the redirect request. The query string should _not_ include the leading "?" character. :: result = braintree.TransparentRedirect.confirm("foo=bar&id=12345") """ parsed_query_string = self._parse_and_validate_query_string(query_string) confirmation_gateway = { TransparentRedirect.Kind.CreateCustomer: "customer", TransparentRedirect.Kind.UpdateCustomer: "customer", TransparentRedirect.Kind.CreatePaymentMethod: "credit_card", TransparentRedirect.Kind.UpdatePaymentMethod: "credit_card", TransparentRedirect.Kind.CreateTransaction: "transaction" }[parsed_query_string["kind"][0]] return getattr(self.gateway, confirmation_gateway)._post("/transparent_redirect_requests/" + parsed_query_string["id"][0] + "/confirm") def tr_data(self, data, redirect_url): data = self.__flatten_dictionary(data) date_string = datetime.utcnow().strftime("%Y%m%d%H%M%S") data["time"] = date_string data["redirect_url"] = redirect_url data["public_key"] = self.config.public_key data["api_version"] = self.config.api_version() return SignatureService(self.config.private_key).sign(data) def url(self): """ Returns the url for POSTing Transparent Redirect HTML forms """ return self.config.base_url() + self.config.base_merchant_path() + "/transparent_redirect_requests" def _parse_and_validate_query_string(self, query_string): query_params = cgi.parse_qs(query_string) http_status = int(query_params["http_status"][0]) message = query_params.get("bt_message") if message is not None: message = message[0] if Http.is_error_status(http_status): Http.raise_exception_from_status(http_status, message) if not self._is_valid_tr_query_string(query_string): raise ForgedQueryStringError return query_params def _is_valid_tr_query_string(self, query_string): content, hash = query_string.split("&hash=") return hash == Crypto.sha1_hmac_hash(self.config.private_key, content) def __flatten_dictionary(self, params, parent=None): data = {} for key, val in params.items(): full_key = parent + "[" + key + "]" if parent else key if isinstance(val, dict): data.update(self.__flatten_dictionary(val, full_key)) else: data[full_key] = val return data braintree_python-3.57.1/braintree/apple_pay_card.py0000644000175000017500000000176413545202423020565 0ustar hlehleimport braintree from braintree.resource import Resource class ApplePayCard(Resource): """ A class representing Braintree Apple Pay card objects. """ class CardType(object): """ Contants representing the type of the credit card. Available types are: * Braintree.ApplePayCard.AmEx * Braintree.ApplePayCard.MasterCard * Braintree.ApplePayCard.Visa """ AmEx = "Apple Pay - American Express" MasterCard = "Apple Pay - MasterCard" Visa = "Apple Pay - Visa" def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if hasattr(self, 'expired'): self.is_expired = self.expired if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] @property def expiration_date(self): return self.expiration_month + "/" + self.expiration_year braintree_python-3.57.1/braintree/subscription_details.py0000644000175000017500000000015513545202423022044 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class SubscriptionDetails(AttributeGetter): pass braintree_python-3.57.1/braintree/transaction_amounts.py0000644000175000017500000000034313545202423021705 0ustar hlehleclass TransactionAmounts(object): """ A class of constants for transaction amounts that will cause different statuses. """ Authorize = "1000.00" Decline = "2000.00" HardDecline = "2015.00" Fail = "3000.00" braintree_python-3.57.1/braintree/discount.py0000644000175000017500000000033213545202423017440 0ustar hlehlefrom braintree.modification import Modification from braintree.configuration import Configuration class Discount(Modification): @staticmethod def all(): return Configuration.gateway().discount.all() braintree_python-3.57.1/braintree/client_token_gateway.py0000644000175000017500000000211013545202423022003 0ustar hlehleimport braintree from braintree.resource import Resource from braintree.client_token import ClientToken from braintree import exceptions class ClientTokenGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def generate(self, params={}): if "options" in params and not "customer_id" in params: for option in ["verify_card", "make_default", "fail_on_duplicate_payment_method"]: if option in params["options"]: raise exceptions.InvalidSignatureError("cannot specify %s without a customer_id" % option) if "version" not in params: params["version"] = 2 Resource.verify_keys(params, ClientToken.generate_signature()) params = {'client_token': params} response = self.config.http().post(self.config.base_merchant_path() + "/client_token", params) if "client_token" in response: return response["client_token"]["value"] else: raise ValueError(response["api_error_response"]["message"]) braintree_python-3.57.1/braintree/dispute.py0000644000175000017500000001566113545202423017300 0ustar hlehlefrom decimal import Decimal from braintree.attribute_getter import AttributeGetter from braintree.transaction_details import TransactionDetails from braintree.dispute_details import DisputeEvidence, DisputeStatusHistory from braintree.configuration import Configuration class Dispute(AttributeGetter): class Status(object): """ Constants representing dispute statuses. Available types are: * braintree.Dispute.Status.Accepted * braintree.Dispute.Status.Disputed * braintree.Dispute.Status.Open * braintree.Dispute.Status.Won * braintree.Dispute.Status.Lost """ Accepted = "accepted" Disputed = "disputed" Expired = "expired" Open = "open" Won = "won" Lost = "lost" class Reason(object): """ Constants representing dispute reasons. Available types are: * braintree.Dispute.Reason.CancelledRecurringTransaction * braintree.Dispute.Reason.CreditNotProcessed * braintree.Dispute.Reason.Duplicate * braintree.Dispute.Reason.Fraud * braintree.Dispute.Reason.General * braintree.Dispute.Reason.InvalidAccount * braintree.Dispute.Reason.NotRecognized * braintree.Dispute.Reason.ProductNotReceived * braintree.Dispute.Reason.ProductUnsatisfactory * braintree.Dispute.Reason.Retrieval * braintree.Dispute.Reason.TransactionAmountDiffers """ CancelledRecurringTransaction = "cancelled_recurring_transaction" CreditNotProcessed = "credit_not_processed" Duplicate = "duplicate" Fraud = "fraud" General = "general" InvalidAccount = "invalid_account" NotRecognized = "not_recognized" ProductNotReceived = "product_not_received" ProductUnsatisfactory = "product_unsatisfactory" Retrieval = "retrieval" TransactionAmountDiffers = "transaction_amount_differs" class Kind(object): """ Constants representing dispute kinds. Available types are: * braintree.Dispute.Kind.Chargeback * braintree.Dispute.Kind.PreArbitration * braintree.Dispute.Kind.Retrieval """ Chargeback = "chargeback" PreArbitration = "pre_arbitration" Retrieval = "retrieval" @staticmethod def accept(id): """ Accept a dispute, given a dispute_id. This will raise a :class:`NotFoundError ` if the provided dispute_id is not found. :: result = braintree.Dispute.accept("my_dispute_id") """ return Configuration.gateway().dispute.accept(id) @staticmethod def add_file_evidence(dispute_id, document_upload_id): """ Adds file evidence to a dispute, given a dispute_id and a document_upload_id. This will raise a :class:`NotFoundError ` if the provided dispute_id is not found. :: document = braintree.DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": open("/path/to/evidence.pdf", "rb") }) result = braintree.Dispute.add_file_evidence("my_dispute_id", document.id) """ return Configuration.gateway().dispute.add_file_evidence(dispute_id, document_upload_id) @staticmethod def add_text_evidence(id, content_or_request): """ Adds text evidence to a dispute, given a dispute_id. This will raise a :class:`NotFoundError ` if the provided dispute_id is not found. :: result = braintree.Dispute.add_text_evidence("my_dispute_id", "my_evidence") or result = braintree.Dispute.add_text_evidence("my_dispute_id", { "content": "UPS", "tag": "CARRIER_NAME", "sequence_number": "1" }) """ return Configuration.gateway().dispute.add_text_evidence(id, content_or_request) @staticmethod def finalize(id): """ Finalize a dispute, given a dispute_id. This will raise a :class:`NotFoundError ` if the provided dispute_id is not found. :: result = braintree.Dispute.finalize("my_dispute_id") """ return Configuration.gateway().dispute.finalize(id) @staticmethod def find(id): """ Find an dispute, given a dispute_id. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided dispute_id is not found. :: dispute = braintree.Dispute.find("my_dispute_id") """ return Configuration.gateway().dispute.find(id) @staticmethod def remove_evidence(id, evidence_id): """ Remove evidence on a dispute. This will raise a :class:`NotFoundError ` if the provided dispute_id or evidence_id is not found. :: result = braintree.Dispute.remove_evidence("my_dispute_id", "my_evidence_id") """ return Configuration.gateway().dispute.remove_evidence(id, evidence_id) @staticmethod def search(*query): """ Searches for disputes, given a DisputeSearch query. collection = braintree.Dispute.search([ braintree.DisputeSearch.id == "the_dispute_id" ]) for dispute in collection.items: print dispute.id """ return Configuration.gateway().dispute.search(*query) def __init__(self, attributes): AttributeGetter.__init__(self, attributes) if "amount" in attributes and self.amount is not None: self.amount = Decimal(self.amount) if "amount_disputed" in attributes and self.amount_disputed is not None: self.amount_disputed = Decimal(self.amount_disputed) if "amount_won" in attributes and self.amount_won is not None: self.amount_won = Decimal(self.amount_won) if "transaction" in attributes: self.transaction_details = TransactionDetails(attributes.pop("transaction")) self.transaction = self.transaction_details if "evidence" in attributes and self.evidence is not None: self.evidence = [DisputeEvidence(evidence) for evidence in self.evidence] if "status_history" in attributes and self.status_history is not None: self.status_history = [DisputeStatusHistory(status_history) for status_history in self.status_history] if "processor_comments" in attributes and self.processor_comments is not None: self.forwarded_comments = self.processor_comments braintree_python-3.57.1/braintree/plan_gateway.py0000644000175000017500000000124213545202423020264 0ustar hlehleimport re import braintree from braintree.plan import Plan from braintree.error_result import ErrorResult from braintree.exceptions.not_found_error import NotFoundError from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult class PlanGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def all(self): response = self.config.http().get(self.config.base_merchant_path() + "/plans/") return [Plan(self.gateway, item) for item in ResourceCollection._extract_as_array(response, "plans")] braintree_python-3.57.1/braintree/revoked_payment_method_metadata.py0000644000175000017500000000062013545202423024204 0ustar hlehlefrom braintree.payment_method_parser import parse_payment_method from braintree.resource import Resource class RevokedPaymentMethodMetadata(Resource): def __init__(self, gateway, attributes): self.revoked_payment_method = parse_payment_method(gateway, attributes) self.customer_id = self.revoked_payment_method.customer_id self.token = self.revoked_payment_method.token braintree_python-3.57.1/braintree/amex_express_checkout_card.py0000644000175000017500000000107513545202423023176 0ustar hlehleimport braintree from braintree.resource import Resource class AmexExpressCheckoutCard(Resource): """ A class representing Braintree Amex Express Checkout card objects. """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] @property def expiration_date(self): return self.expiration_month + "/" + self.expiration_year braintree_python-3.57.1/braintree/merchant_gateway.py0000644000175000017500000000216513545202423021140 0ustar hlehlefrom braintree.error_result import ErrorResult from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult from braintree.exceptions.not_found_error import NotFoundError from braintree.merchant import Merchant from braintree.oauth_credentials import OAuthCredentials class MerchantGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create(self, params): return self.__create_merchant(params) def __create_merchant(self, params={}): response = self.config.http().post("/merchants/create_via_api", { "merchant": params }) if "response" in response and "merchant" in response["response"]: return SuccessfulResult({ "merchant": Merchant(self.gateway, response["response"]["merchant"]), "credentials": OAuthCredentials(self.gateway, response["response"]["credentials"]) }) else: return ErrorResult(self.gateway, response["api_error_response"]) braintree_python-3.57.1/braintree/validation_error_collection.py0000644000175000017500000000564413545202423023401 0ustar hlehlefrom braintree.validation_error import ValidationError class ValidationErrorCollection(object): """ A class representing a collection of validation errors. For more information on ValidationErrors, see https://developers.braintreepayments.com/reference/general/validation-errors/overview/python """ def __init__(self, data={"errors": []}): self.data = data @property def deep_errors(self): """ Return all :class:`ValidationErrors `, including nested errors. """ result = [] result.extend(self.errors) for nested_error in self.__nested_errors.values(): result.extend(nested_error.deep_errors) return result def for_index(self, index): return self.for_object("index_%s" % index) def for_object(self, nested_key): """ Returns a :class:`ValidationErrorCollection ` It represents the errors at the nested level::: error_result = Transaction.sale({"credit_card": {"number": "invalid"}}) print error_result.errors.for_object("transaction").for_object("credit_card").on("number")[0].code """ return self.__get_nested_errors(nested_key) def on(self, attribute): """ Returns the list of errors Restricted to a given attribute:: error_result = Transaction.sale({"credit_card": {"number": "invalid"}}) print [ error.code for error in error_result.errors.for_object("transaction").for_object("credit_card").on("number") ] """ return [error for error in self.errors if error.attribute == attribute] @property def deep_size(self): """Returns the number of errors on this object and any nested objects.""" size = len(self.errors) for error in self.__nested_errors.values(): size += error.deep_size return size @property def errors(self): """Returns a list of :class:`ValidationError ` objects.""" return [ValidationError(error) for error in self.data["errors"]] @property def size(self): """Returns the number of errors on this object, without counting nested errors.""" return len(self.errors) def __get_nested_errors(self, nested_key): if nested_key in self.__nested_errors: return self.__nested_errors[nested_key] else: return ValidationErrorCollection() def __getitem__(self, index): return self.errors[index] def __len__(self): return self.size @property def __nested_errors(self): nested_errors = {} for key in self.data: if key == "errors": continue nested_errors[key] = ValidationErrorCollection(self.data[key]) return nested_errors braintree_python-3.57.1/braintree/ideal_payment.py0000644000175000017500000000230513545202423020425 0ustar hlehleimport braintree from braintree.resource import Resource from braintree.configuration import Configuration from braintree.iban_bank_account import IbanBankAccount # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. class IdealPayment(Resource): @staticmethod def find(ideal_payment_id): return Configuration.gateway().ideal_payment.find(ideal_payment_id) @staticmethod def sale(ideal_payment_id, transactionRequest): request = transactionRequest.copy() request["payment_method_nonce"] = ideal_payment_id if not "options" in request: request["options"] = {} request["options"]["submit_for_settlement"] = True return Configuration.gateway().transaction.sale(request) def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if attributes.get('iban_bank_account') is not None: self.iban_bank_account = IbanBankAccount(gateway, self.iban_bank_account) else: self.iban_bank_account = None braintree_python-3.57.1/braintree/webhook_notification.py0000644000175000017500000001625713545202423022031 0ustar hlehlefrom braintree.resource import Resource from braintree.configuration import Configuration from braintree.subscription import Subscription from braintree.merchant_account import MerchantAccount from braintree.transaction import Transaction from braintree.partner_merchant import PartnerMerchant from braintree.oauth_access_revocation import OAuthAccessRevocation from braintree.disbursement import Disbursement from braintree.dispute import Dispute from braintree.account_updater_daily_report import AccountUpdaterDailyReport from braintree.error_result import ErrorResult from braintree.validation_error_collection import ValidationErrorCollection from braintree.connected_merchant_paypal_status_changed import ConnectedMerchantPayPalStatusChanged from braintree.connected_merchant_status_transitioned import ConnectedMerchantStatusTransitioned # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. from braintree.ideal_payment import IdealPayment from braintree.granted_payment_instrument_update import GrantedPaymentInstrumentUpdate from braintree.revoked_payment_method_metadata import RevokedPaymentMethodMetadata from braintree.local_payment_completed import LocalPaymentCompleted class WebhookNotification(Resource): class Kind(object): AccountUpdaterDailyReport = "account_updater_daily_report" Check = "check" ConnectedMerchantStatusTransitioned = "connected_merchant_status_transitioned" ConnectedMerchantPayPalStatusChanged = "connected_merchant_paypal_status_changed" PartnerMerchantConnected = "partner_merchant_connected" PartnerMerchantDisconnected = "partner_merchant_disconnected" PartnerMerchantDeclined = "partner_merchant_declined" OAuthAccessRevoked = "oauth_access_revoked" SubscriptionCanceled = "subscription_canceled" SubscriptionChargedSuccessfully = "subscription_charged_successfully" SubscriptionChargedUnsuccessfully = "subscription_charged_unsuccessfully" SubscriptionExpired = "subscription_expired" SubscriptionTrialEnded = "subscription_trial_ended" SubscriptionWentActive = "subscription_went_active" SubscriptionWentPastDue = "subscription_went_past_due" SubMerchantAccountApproved = "sub_merchant_account_approved" SubMerchantAccountDeclined = "sub_merchant_account_declined" TransactionDisbursed = "transaction_disbursed" TransactionSettled = "transaction_settled" TransactionSettlementDeclined = "transaction_settlement_declined" DisbursementException = "disbursement_exception" Disbursement = "disbursement" DisputeOpened = "dispute_opened" DisputeLost = "dispute_lost" DisputeWon = "dispute_won" # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. IdealPaymentComplete = "ideal_payment_complete" IdealPaymentFailed = "ideal_payment_failed" # NEXT_MAJOR_VERSION remove GrantedPaymentInstrumentUpdate. Kind is not sent by Braintree Gateway. # Kind will either be GrantorUpdatedGrantedPaymentMethod or RecipientUpdatedGrantedPaymentMethod. GrantedPaymentInstrumentUpdate = "granted_payment_instrument_update" GrantorUpdatedGrantedPaymentMethod = "grantor_updated_granted_payment_method" RecipientUpdatedGrantedPaymentMethod = "recipient_updated_granted_payment_method" GrantedPaymentMethodRevoked = "granted_payment_method_revoked" PaymentMethodRevokedByCustomer = "payment_method_revoked_by_customer" LocalPaymentCompleted = "local_payment_completed" @staticmethod def parse(signature, payload): return Configuration.gateway().webhook_notification.parse(signature, payload) @staticmethod def verify(challenge): return Configuration.gateway().webhook_notification.verify(challenge) def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "source_merchant_id" not in attributes: self.source_merchant_id = None if "api_error_response" in attributes["subject"]: node_wrapper = attributes["subject"]["api_error_response"] else: node_wrapper = attributes["subject"] if "subscription" in node_wrapper: self.subscription = Subscription(gateway, node_wrapper['subscription']) elif "merchant_account" in node_wrapper: self.merchant_account = MerchantAccount(gateway, node_wrapper['merchant_account']) elif "transaction" in node_wrapper: self.transaction = Transaction(gateway, node_wrapper['transaction']) elif "connected_merchant_status_transitioned" in node_wrapper: self.connected_merchant_status_transitioned = ConnectedMerchantStatusTransitioned(gateway, node_wrapper['connected_merchant_status_transitioned']) elif "connected_merchant_paypal_status_changed" in node_wrapper: self.connected_merchant_paypal_status_changed = ConnectedMerchantPayPalStatusChanged(gateway, node_wrapper['connected_merchant_paypal_status_changed']) elif "partner_merchant" in node_wrapper: self.partner_merchant = PartnerMerchant(gateway, node_wrapper['partner_merchant']) elif "oauth_application_revocation" in node_wrapper: self.oauth_access_revocation = OAuthAccessRevocation(node_wrapper["oauth_application_revocation"]) elif "disbursement" in node_wrapper: self.disbursement = Disbursement(gateway, node_wrapper['disbursement']) elif "dispute" in node_wrapper: self.dispute = Dispute(node_wrapper['dispute']) elif "account_updater_daily_report" in node_wrapper: self.account_updater_daily_report = AccountUpdaterDailyReport(gateway, node_wrapper['account_updater_daily_report']) # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. elif "ideal_payment" in node_wrapper: self.ideal_payment = IdealPayment(gateway, node_wrapper['ideal_payment']) elif "granted_payment_instrument_update" in node_wrapper: self.granted_payment_instrument_update = GrantedPaymentInstrumentUpdate(gateway, node_wrapper["granted_payment_instrument_update"]) elif attributes["kind"] in [WebhookNotification.Kind.GrantedPaymentMethodRevoked, WebhookNotification.Kind.PaymentMethodRevokedByCustomer]: self.revoked_payment_method_metadata = RevokedPaymentMethodMetadata(gateway, node_wrapper) elif "local_payment" in node_wrapper: self.local_payment_completed = LocalPaymentCompleted(gateway, node_wrapper["local_payment"]) if "errors" in node_wrapper: self.errors = ValidationErrorCollection(node_wrapper['errors']) self.message = node_wrapper['message'] braintree_python-3.57.1/braintree/__init__.py0000644000175000017500000001053313545202423017353 0ustar hlehlefrom braintree.ach_mandate import AchMandate from braintree.add_on import AddOn from braintree.add_on_gateway import AddOnGateway from braintree.address import Address from braintree.address_gateway import AddressGateway from braintree.amex_express_checkout_card import AmexExpressCheckoutCard from braintree.android_pay_card import AndroidPayCard from braintree.apple_pay_card import ApplePayCard from braintree.braintree_gateway import BraintreeGateway from braintree.client_token import ClientToken from braintree.configuration import Configuration from braintree.connected_merchant_status_transitioned import ConnectedMerchantStatusTransitioned from braintree.connected_merchant_paypal_status_changed import ConnectedMerchantPayPalStatusChanged from braintree.credentials_parser import CredentialsParser from braintree.credit_card import CreditCard from braintree.credit_card_gateway import CreditCardGateway from braintree.credit_card_verification import CreditCardVerification from braintree.credit_card_verification_search import CreditCardVerificationSearch from braintree.customer import Customer from braintree.customer_gateway import CustomerGateway from braintree.customer_search import CustomerSearch from braintree.descriptor import Descriptor from braintree.disbursement import Disbursement from braintree.document_upload import DocumentUpload from braintree.document_upload_gateway import DocumentUploadGateway from braintree.discount import Discount from braintree.discount_gateway import DiscountGateway from braintree.dispute import Dispute from braintree.dispute_search import DisputeSearch from braintree.environment import Environment from braintree.error_codes import ErrorCodes from braintree.error_result import ErrorResult from braintree.errors import Errors from braintree.europe_bank_account import EuropeBankAccount from braintree.us_bank_account import UsBankAccount from braintree.ideal_payment import IdealPayment from braintree.merchant import Merchant from braintree.merchant_account import MerchantAccount from braintree.merchant_account_gateway import MerchantAccountGateway from braintree.oauth_access_revocation import OAuthAccessRevocation from braintree.partner_merchant import PartnerMerchant from braintree.payment_instrument_type import PaymentInstrumentType from braintree.payment_method import PaymentMethod from braintree.payment_method_nonce import PaymentMethodNonce from braintree.payment_method_parser import parse_payment_method from braintree.paypal_account import PayPalAccount from braintree.plan import Plan from braintree.plan_gateway import PlanGateway from braintree.processor_response_types import ProcessorResponseTypes from braintree.resource_collection import ResourceCollection from braintree.risk_data import RiskData from braintree.samsung_pay_card import SamsungPayCard from braintree.search import Search from braintree.settlement_batch_summary import SettlementBatchSummary from braintree.signature_service import SignatureService from braintree.status_event import StatusEvent from braintree.subscription import Subscription from braintree.subscription_gateway import SubscriptionGateway from braintree.subscription_search import SubscriptionSearch from braintree.subscription_status_event import SubscriptionStatusEvent from braintree.successful_result import SuccessfulResult from braintree.testing_gateway import TestingGateway from braintree.three_d_secure_info import ThreeDSecureInfo from braintree.transaction import Transaction from braintree.transaction_amounts import TransactionAmounts from braintree.transaction_details import TransactionDetails from braintree.transaction_gateway import TransactionGateway from braintree.transaction_line_item import TransactionLineItem from braintree.transaction_search import TransactionSearch from braintree.transparent_redirect import TransparentRedirect from braintree.transparent_redirect_gateway import TransparentRedirectGateway from braintree.unknown_payment_method import UnknownPaymentMethod from braintree.validation_error_collection import ValidationErrorCollection from braintree.venmo_account import VenmoAccount from braintree.version import Version from braintree.webhook_notification import WebhookNotification from braintree.webhook_notification_gateway import WebhookNotificationGateway from braintree.webhook_testing import WebhookTesting from braintree.webhook_testing_gateway import WebhookTestingGateway braintree_python-3.57.1/braintree/configuration.py0000644000175000017500000001177513545202423020474 0ustar hlehleimport braintree from braintree.credentials_parser import CredentialsParser from braintree.environment import Environment from braintree.exceptions.configuration_error import ConfigurationError from braintree.util.graphql_client import GraphQLClient class Configuration(object): """ A class representing the configuration of your Braintree account. You must call configure before any other Braintree operations. :: braintree.Configuration.configure( braintree.Environment.Sandbox, "your_merchant_id", "your_public_key", "your_private_key" ) """ @staticmethod def configure(environment, merchant_id, public_key, private_key, **kwargs): Configuration.environment = Environment.parse_environment(environment) Configuration.merchant_id = merchant_id Configuration.public_key = public_key Configuration.private_key = private_key Configuration.default_http_strategy = kwargs.get("http_strategy", None) Configuration.timeout = kwargs.get("timeout", 60) Configuration.wrap_http_exceptions = kwargs.get("wrap_http_exceptions", False) @staticmethod def for_partner(environment, partner_id, public_key, private_key, **kwargs): return Configuration( environment=environment, merchant_id=partner_id, public_key=public_key, private_key=private_key, http_strategy=kwargs.get("http_strategy", None), timeout=kwargs.get("timeout", 60), wrap_http_exceptions=kwargs.get("wrap_http_exceptions", False) ) @staticmethod def gateway(): return braintree.braintree_gateway.BraintreeGateway(config=Configuration.instantiate()) @staticmethod def instantiate(): return Configuration( environment=Configuration.environment, merchant_id=Configuration.merchant_id, public_key=Configuration.public_key, private_key=Configuration.private_key, http_strategy=Configuration.default_http_strategy, timeout=Configuration.timeout, wrap_http_exceptions=Configuration.wrap_http_exceptions ) @staticmethod def api_version(): return "5" @staticmethod def graphql_api_version(): return "2018-09-10" def __init__(self, environment=None, merchant_id=None, public_key=None, private_key=None, client_id=None, client_secret=None, access_token=None, *args, **kwargs): if len(args) == 2: public_key, private_key = args parser = CredentialsParser(client_id=client_id, client_secret=client_secret, access_token=access_token) if parser.access_token is not None: parser.parse_access_token() self.environment = parser.environment self.merchant_id = parser.merchant_id elif parser.client_id is not None or parser.client_secret is not None: parser.parse_client_credentials() self.environment = parser.environment self.merchant_id = merchant_id else: self.environment = Environment.parse_environment(environment) if merchant_id == "": raise ConfigurationError("Missing merchant_id") else: self.merchant_id = merchant_id if public_key == "": raise ConfigurationError("Missing public_key") else: self.public_key = public_key if private_key == "": raise ConfigurationError("Missing private_key") else: self.private_key = private_key self.client_id = parser.client_id self.client_secret = parser.client_secret self.access_token = parser.access_token self.timeout = kwargs.get("timeout", 60) self.wrap_http_exceptions = kwargs.get("wrap_http_exceptions", False) http_strategy = kwargs.get("http_strategy", None) if http_strategy: self._http_strategy = http_strategy(self, self.environment) else: self._http_strategy = self.http() def base_merchant_path(self): return "/merchants/" + self.merchant_id def base_url(self): return self.environment.protocol + self.environment.server_and_port def graphql_base_url(self): return self.environment.protocol + self.environment.graphql_server_and_port + "/graphql" def http(self): return braintree.util.http.Http(self) def graphql_client(self): return GraphQLClient(self) def http_strategy(self): return self._http_strategy def has_client_credentials(self): return self.client_secret is not None and self.client_id is not None def assert_has_client_credentials(self): if not self.has_client_credentials(): raise ConfigurationError("client_id and client_secret are required") def has_access_token(self): return self.access_token is not None braintree_python-3.57.1/braintree/transparent_redirect.py0000644000175000017500000000224213545202423022034 0ustar hlehleimport braintree from braintree.configuration import Configuration class TransparentRedirect: """ A class used for Transparent Redirect operations """ class Kind(object): CreateCustomer = "create_customer" UpdateCustomer = "update_customer" CreatePaymentMethod = "create_payment_method" UpdatePaymentMethod = "update_payment_method" CreateTransaction = "create_transaction" @staticmethod def confirm(query_string): """ Confirms a transparent redirect request. It expects the query string from the redirect request. The query string should _not_ include the leading "?" character. :: result = braintree.TransparentRedirect.confirm("foo=bar&id=12345") """ return Configuration.gateway().transparent_redirect.confirm(query_string) @staticmethod def tr_data(data, redirect_url): return Configuration.gateway().transparent_redirect.tr_data(data, redirect_url) @staticmethod def url(): """ Returns the url for POSTing Transparent Redirect HTML forms """ return Configuration.gateway().transparent_redirect.url() braintree_python-3.57.1/braintree/successful_result.py0000644000175000017500000000116713545202423021374 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class SuccessfulResult(AttributeGetter): """ An instance of this class is returned from most operations when the request is successful. Call the name of the resource (eg, customer, credit_card, etc) to get the object:: result = Transaction.sale({..}) if result.is_success: transaction = result.transaction else: print [error.code for error in result.errors.all] """ @property def is_success(self): """ Returns whether the result from the gateway is a successful response. """ return True braintree_python-3.57.1/braintree/disbursement.py0000644000175000017500000000205113545202423020314 0ustar hlehlefrom decimal import Decimal from braintree.resource import Resource from braintree.transaction_search import TransactionSearch from braintree.merchant_account import MerchantAccount class Disbursement(Resource): class Type(object): """ """ Credit = "credit" Debit = "debit" def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.amount = Decimal(self.amount) self.merchant_account = MerchantAccount(gateway, attributes["merchant_account"]) def __repr__(self): detail_list = ["amount", "disbursement_date", "exception_message", "follow_up_action", "id", "success", "retry"] return super(Disbursement, self).__repr__(detail_list) def transactions(self): return self.gateway.transaction.search([TransactionSearch.ids.in_list(self.transaction_ids)]) def is_credit(self): return self.disbursement_type == Disbursement.Type.Credit def is_debit(self): return self.disbursement_type == Disbursement.Type.Debit braintree_python-3.57.1/braintree/error_codes.py0000644000175000017500000007647013545202423020136 0ustar hlehleclass ErrorCodes(object): """ A set of constants representing validation errors. Validation error messages can change, but the codes will not. See the source for a list of all errors codes. Codes can be used to check for specific validation errors:: result = Transaction.sale({}) assert(result.is_success == False) assert(result.errors.for_object("transaction").on("amount")[0].code == ErrorCodes.Transaction.AmountIsRequired) """ class Address(object): CannotBeBlank = "81801" CompanyIsInvalid = "91821" CompanyIsTooLong = "81802" CountryCodeAlpha2IsNotAccepted = "91814" CountryCodeAlpha3IsNotAccepted = "91816" CountryCodeNumericIsNotAccepted = "91817" CountryNameIsNotAccepted = "91803" ExtedAddressIsTooLong = "81804" # Deprecated ExtendedAddressIsInvalid = "91823" ExtendedAddressIsTooLong = "81804" FirstNameIsInvalid = "91819" FirstNameIsTooLong = "81805" InconsistentCountry = "91815" IsInvalid = "91828" LastNameIsInvalid = "91820" LastNameIsTooLong = "81806" LocalityIsInvalid = "91824" LocalityIsTooLong = "81807" PostalCodeInvalidCharacters = "81813" PostalCodeIsInvalid = "91826" PostalCodeIsRequired = "81808" PostalCodeIsRequiredForCardBrandAndProcessor = "81828" PostalCodeIsTooLong = "81809" RegionIsInvalid = "91825" RegionIsTooLong = "81810" StateIsInvalidForSellerProtection = "81827" StreetAddressIsInvalid = "91822" StreetAddressIsRequired = "81811" StreetAddressIsTooLong = "81812" TooManyAddressesPerCustomer = "91818" class ApplePay(object): ApplePayCardsAreNotAccepted = "83501" CustomerIdIsRequiredForVaulting = "83502" TokenIsInUse = "93503" PaymentMethodNonceConsumed = "93504" PaymentMethodNonceUnknown = "93505" PaymentMethodNonceLocked = "93506" PaymentMethodNonceCardTypeIsNotAccepted = "83518" CannotUpdateApplePayCardUsingPaymentMethodNonce = "93507" NumberIsRequired = "93508" ExpirationMonthIsRequired = "93509" ExpirationYearIsRequired = "93510" CryptogramIsRequired = "93511" DecryptionFailed = "83512" Disabled = "93513" MerchantNotConfigured = "93514" MerchantKeysAlreadyConfigured = "93515" MerchantKeysNotConfigured = "93516" CertificateInvalid = "93517" CertificateMismatch = "93519" InvalidToken = "83520" PrivateKeyMismatch = "93521" KeyMismatchStoringCertificate = "93522" class AuthorizationFingerprint(object): MissingFingerprint = "93201" InvalidFormat = "93202" SignatureRevoked = "93203" InvalidCreatedAt = "93204" InvalidPublicKey = "93205" InvalidSignature = "93206" OptionsNotAllowedWithoutCustomer = "93207" class ClientToken(object): MakeDefaultRequiresCustomerId = "92801" VerifyCardRequiresCustomerId = "92802" FailOnDuplicatePaymentMethodRequiresCustomerId = "92803" CustomerDoesNotExist = "92804" ProxyMerchantDoesNotExist = "92805" UnsupportedVersion = "92806" MerchantAccountDoesNotExist = "92807" class CreditCard(object): BillingAddressConflict = "91701" BillingAddressFormatIsInvalid = "91744" BillingAddressIdIsInvalid = "91702" CannotUpdateCardUsingPaymentMethodNonce = "91735" CannotUpdateCardUsingPaymentMethodNonce = "91735" CardholderNameIsTooLong = "81723" CreditCardTypeIsNotAccepted = "81703" CreditCardTypeIsNotAcceptedBySubscriptionMerchantAccount = "81718" CustomerIdIsInvalid = "91705" CustomerIdIsRequired = "91704" CvvIsInvalid = "81707" CvvIsRequired = "81706" CvvVerificationFailed = "81736" DuplicateCardExists = "81724" ExpirationDateConflict = "91708" ExpirationDateIsInvalid = "81710" ExpirationDateIsRequired = "81709" ExpirationDateYearIsInvalid = "81711" ExpirationMonthIsInvalid = "81712" ExpirationYearIsInvalid = "81713" InvalidParamsForCreditCardUpdate = "91745" InvalidVenmoSDKPaymentMethodCode = "91727" NumberHasInvalidLength = NumberLengthIsInvalid = "81716" NumberIsInvalid = "81715" NumberIsProhibited = "81750" NumberIsRequired = "81714" NumberMustBeTestNumber = "81717" PaymentMethodConflict = "81725" PaymentMethodIsNotACreditCard = "91738" PaymentMethodNonceCardTypeIsNotAccepted = "91734" PaymentMethodNonceCardTypeIsNotAccepted = "91734" PaymentMethodNonceConsumed = "91731" PaymentMethodNonceConsumed = "91731" PaymentMethodNonceLocked = "91733" PaymentMethodNonceLocked = "91733" PaymentMethodNonceUnknown = "91732" PaymentMethodNonceUnknown = "91732" PostalCodeVerificationFailed = "81737" TokenInvalid = TokenFormatIsInvalid = "91718" TokenIsInUse = "91719" TokenIsNotAllowed = "91721" TokenIsRequired = "91722" TokenIsTooLong = "91720" VenmoSDKPaymentMethodCodeCardTypeIsNotAccepted = "91726" VerificationNotSupportedOnThisMerchantAccount = "91730" VerificationAccountTypeIsInvald = "91757" VerificationAccountTypeNotSupported = "91758" class Options(object): UpdateExistingTokenIsInvalid = "91723" UpdateExistingTokenNotAllowed = "91729" VerificationAmountCannotBeNegative = "91739" VerificationAmountFormatIsInvalid = "91740" VerificationAmountIsTooLarge = "91752" VerificationAmountNotSupportedByProcessor = "91741" VerificationMerchantAccountIdIsInvalid = "91728" VerificationMerchantAccountIsForbidden = "91743" VerificationMerchantAccountIsSuspended = "91742" VerificationMerchantAccountCannotBeSubMerchantAccount = "91755" class Customer(object): CompanyIsTooLong = "81601" CustomFieldIsInvalid = "91602" CustomFieldIsTooLong = "81603" EmailIsInvalid = EmailFormatIsInvalid = "81604" EmailIsRequired = "81606" EmailIsTooLong = "81605" FaxIsTooLong = "81607" FirstNameIsTooLong = "81608" IdIsInUse = "91609" IdIsInvaild = "91610" # Deprecated IdIsInvalid = "91610" IdIsNotAllowed = "91611" IdIsRequired = "91613" IdIsTooLong = "91612" LastNameIsTooLong = "81613" PhoneIsTooLong = "81614" VaultedPaymentInstrumentNonceBelongsToDifferentCustomer = "91617" WebsiteIsInvalid = WebsiteFormatIsInvalid = "81616" WebsiteIsTooLong = "81615" class Descriptor(object): DynamicDescriptorsDisabled = "92203" InternationalNameFormatIsInvalid = "92204" InternationalPhoneFormatIsInvalid = "92205" NameFormatIsInvalid = "92201" PhoneFormatIsInvalid = "92202" UrlFormatIsInvalid = "92206" class Dispute(object): CanOnlyAddEvidenceToOpenDispute = "95701" CanOnlyRemoveEvidenceFromOpenDispute = "95702" CanOnlyAddEvidenceDocumentToDispute = "95703" CanOnlyAcceptOpenDispute = "95704" CanOnlyFinalizeOpenDispute = "95705" CanOnlyCreateEvidenceWithValidCategory = "95706" EvidenceContentDateInvalid = "95707" EvidenceContentTooLong = "95708" EvidenceContentARNTooLong = "95709" EvidenceContentPhoneTooLong = "95710" EvidenceCategoryTextOnly = "95711" EvidenceCategoryDocumentOnly = "95712" EvidenceCategoryNotForReasonCode = "95713" EvidenceCategoryDuplicate = "95714" EvidenceContentEmailInvalid = "95715" DigitalGoodsMissingEvidence = "95720" DigitalGoodsMissingDownloadDate = "95721" NonDisputedPriorTransactionEvidenceMissingARN = "95722" NonDisputedPriorTransactionEvidenceMissingDate = "95723" RecurringTransactionEvidenceMissingDate = "95724" RecurringTransactionEvidenceMissingARN = "95725" ValidEvidenceRequiredToFinalize = "95726" class DocumentUpload(object): KindIsInvalid = "84901" FileIsTooLarge = "84902" FileTypeIsInvalid = "84903" FileIsMalformedOrEncrypted = "84904" FileIsTooLong = "84905" class Merchant(object): CountryCannotBeBlank = "83603" CountryCodeAlpha2IsInvalid = "93607" CountryCodeAlpha2IsNotAccepted = "93606" CountryCodeAlpha3IsInvalid = "93605" CountryCodeAlpha3IsNotAccepted = "93604" CountryCodeNumericIsInvalid = "93609" CountryCodeNumericIsNotAccepted = "93608" CountryNameIsInvalid = "93611" CountryNameIsNotAccepted = "93610" CurrenciesAreInvalid = "93614" EmailFormatIsInvalid = "93602" EmailIsRequired = "83601" InconsistentCountry = "93612" PaymentMethodsAreInvalid = "93613" PaymentMethodsAreNotAllowed = "93615" MerchantAccountExistsForCurrency = "93616" CurrencyIsRequired = "93617" CurrencyIsInvalid = "93618" NoMerchantAccounts = "93619" MerchantAccountExistsForId = "93620" class MerchantAccount(object): IdFormatIsInvalid = "82603" IdIsInUse = "82604" IdIsNotAllowed = "82605" IdIsTooLong = "82602" MasterMerchantAccountIdIsInvalid = "82607" MasterMerchantAccountIdIsRequired = "82606" MasterMerchantAccountMustBeActive = "82608" TosAcceptedIsRequired = "82610" CannotBeUpdated = "82674" IdCannotBeUpdated = "82675" MasterMerchantAccountIdCannotBeUpdated = "82676" Declined = "82626" DeclinedMasterCardMatch = "82622" DeclinedOFAC = "82621" DeclinedFailedKYC = "82623" DeclinedSsnInvalid = "82624" DeclinedSsnMatchesDeceased = "82625" class ApplicantDetails(object): AccountNumberIsRequired = "82614" CompanyNameIsInvalid = "82631" CompanyNameIsRequiredWithTaxId = "82633" DateOfBirthIsRequired = "82612" Declined = "82626" # Keep for backwards compatibility DeclinedMasterCardMatch = "82622" # Keep for backwards compatibility DeclinedOFAC = "82621" # Keep for backwards compatibility DeclinedFailedKYC = "82623" # Keep for backwards compatibility DeclinedSsnInvalid = "82624" # Keep for backwards compatibility DeclinedSsnMatchesDeceased = "82625" # Keep for backwards compatibility EmailAddressIsInvalid = "82616" FirstNameIsInvalid = "82627" FirstNameIsRequired = "82609" LastNameIsInvalid = "82628" LastNameIsRequired = "82611" PhoneIsInvalid = "82636" RoutingNumberIsInvalid = "82635" RoutingNumberIsRequired = "82613" SsnIsInvalid = "82615" TaxIdIsInvalid = "82632" TaxIdIsRequiredWithCompanyName = "82634" DateOfBirthIsInvalid = "82663" EmailAddressIsRequired = "82665" AccountNumberIsInvalid = "82670" TaxIdMustBeBlank = "82673" class Address(object): LocalityIsRequired = "82618" PostalCodeIsInvalid = "82630" PostalCodeIsRequired = "82619" RegionIsRequired = "82620" StreetAddressIsInvalid = "82629" StreetAddressIsRequired = "82617" RegionIsInvalid = "82664" class Individual(object): FirstNameIsRequired = "82637" LastNameIsRequired = "82638" DateOfBirthIsRequired = "82639" SsnIsInvalid = "82642" EmailAddressIsInvalid = "82643" FirstNameIsInvalid = "82644" LastNameIsInvalid = "82645" PhoneIsInvalid = "82656" DateOfBirthIsInvalid = "82666" EmailAddressIsRequired = "82667" class Address(object): StreetAddressIsRequired = "82657" LocalityIsRequired = "82658" PostalCodeIsRequired = "82659" RegionIsRequired = "82660" StreetAddressIsInvalid = "82661" PostalCodeIsInvalid = "82662" RegionIsInvalid = "82668" class Business(object): DbaNameIsInvalid = "82646" LegalNameIsInvalid = "82677" LegalNameIsRequiredWithTaxId = "82669" TaxIdIsInvalid = "82647" TaxIdIsRequiredWithLegalName = "82648" TaxIdMustBeBlank = "82672" class Address(object): StreetAddressIsInvalid = "82685" PostalCodeIsInvalid = "82686" RegionIsInvalid = "82684" class Funding(object): RoutingNumberIsRequired = "82640" AccountNumberIsRequired = "82641" RoutingNumberIsInvalid = "82649" AccountNumberIsInvalid = "82671" DestinationIsInvalid = "82679" DestinationIsRequired = "82678" EmailAddressIsInvalid = "82681" EmailAddressIsRequired = "82680" MobilePhoneIsInvalid = "82683" MobilePhoneIsRequired = "82682" class OAuth(object): InvalidGrant = "93801" InvalidCredentials = "93802" InvalidScope = "93803" InvalidRequest = "93804" UnsupportedGrantType = "93805" class Verification(object): class Options(object): AmountCannotBeNegative = "94201" AmountFormatIsInvalid = "94202" AmountIsTooLarge = "94207" AmountNotSupportedByProcessor = "94203" MerchantAccountIdIsInvalid = "94204" MerchantAccountIsSuspended = "94205" MerchantAccountIsForbidden = "94206" MerchantAccountCannotBeSubMerchantAccount = "94208" AccountTypeIsInvalid = "942184" AccountTypeNotSupported = "942185" class PaymentMethod(object): CannotForwardPaymentMethodType = "93106" PaymentMethodParamsAreRequired = "93101" NonceIsInvalid = "93102" NonceIsRequired = "93103" CustomerIdIsRequired = "93104" CustomerIdIsInvalid = "93105" PaymentMethodNonceConsumed = "93107" PaymentMethodNonceUnknown = "93108" PaymentMethodNonceLocked = "93109" PaymentMethodNoLongerSupported = "93117" AuthExpired = "92911" CannotHaveFundingSourceWithoutAccessToken = "92912" InvalidFundingSourceSelection = "92913" CannotUpdatePayPalAccountUsingPaymentMethodNonce = "92914" class Options(object): UsBankAccountVerificationMethodIsInvalid = "93121" class PayPalAccount(object): CannotHaveBothAccessTokenAndConsentCode = "82903" CannotVaultOneTimeUsePayPalAccount = "82902" ConsentCodeOrAccessTokenIsRequired = "82901" CustomerIdIsRequiredForVaulting = "82905" InvalidParamsForPayPalAccountUpdate = "92915" PayPalAccountsAreNotAccepted = "82904" PayPalCommunicationError = "92910" PaymentMethodNonceConsumed = "92907" PaymentMethodNonceLocked = "92909" PaymentMethodNonceUnknown = "92908" TokenIsInUse = "92906" class SettlementBatchSummary(object): CustomFieldIsInvalid = "82303" SettlementDateIsInvalid = "82302" SettlementDateIsRequired = "82301" class SEPAMandate(object): TypeIsRequired = "93304" IBANInvalidCharacter = "83305" BICInvalidCharacter = "83306" BICLengthIsInvalid = "83307" BICUnsupportedCountry = "83308" IBANUnsupportedCountry = "83309" IBANInvalidFormat = "83310" BillingAddressConflict = "93311" BillingAddressIdIsInvalid = "93312" TypeIsInvalid = "93313" class EuropeBankAccount(object): BICIsRequired = "83302" IBANIsRequired = "83303" AccountHolderNameIsRequired = "83301" class Subscription(object): BillingDayOfMonthCannotBeUpdated = "91918" BillingDayOfMonthIsInvalid = "91914" BillingDayOfMonthMustBeNumeric = "91913" CannotAddDuplicateAddonOrDiscount = "91911" CannotEditCanceledSubscription = "81901" CannotEditExpiredSubscription = "81910" CannotEditPriceChangingFieldsOnPastDueSubscription = "91920" FirstBillingDateCannotBeInThePast = "91916" FirstBillingDateCannotBeUpdated = "91919" FirstBillingDateIsInvalid = "91915" IdIsInUse = "81902" InconsistentNumberOfBillingCycles = "91908" InconsistentStartDate = "91917" InvalidRequestFormat = "91921" MerchantAccountDoesNotSupportInstrumentType = "91930" MerchantAccountIdIsInvalid = "91901" MismatchCurrencyISOCode = "91923" NumberOfBillingCyclesCannotBeBlank = "91912" NumberOfBillingCyclesIsTooSmall = "91909" NumberOfBillingCyclesMustBeGreaterThanZero = "91907" NumberOfBillingCyclesMustBeNumeric = "91906" PaymentMethodNonceCardTypeIsNotAccepted = "91924" PaymentMethodNonceInstrumentTypeDoesNotSupportSubscriptions = "91929" PaymentMethodNonceIsInvalid = "91925" PaymentMethodNonceNotAssociatedWithCustomer = "91926" PaymentMethodNonceUnvaultedCardIsNotAccepted = "91927" PaymentMethodTokenCardTypeIsNotAccepted = "91902" PaymentMethodTokenInstrumentTypeDoesNotSupportSubscriptions = "91928" PaymentMethodTokenIsInvalid = "91903" PaymentMethodTokenNotAssociatedWithCustomer = "91905" PlanBillingFrequencyCannotBeUpdated = "91922" PlanIdIsInvalid = "91904" PriceCannotBeBlank = "81903" PriceFormatIsInvalid = "81904" PriceIsTooLarge = "81923" StatusIsCanceled = "81905" TokenFormatIsInvalid = "81906" TrialDurationFormatIsInvalid = "81907" TrialDurationIsRequired = "81908" TrialDurationUnitIsInvalid = "81909" class Modification(object): AmountCannotBeBlank = "92003" AmountIsInvalid = "92002" AmountIsTooLarge = "92023" CannotEditModificationsOnPastDueSubscription = "92022" CannotUpdateAndRemove = "92015" ExistingIdIsIncorrectKind = "92020" ExistingIdIsInvalid = "92011" ExistingIdIsRequired = "92012" IdToRemoveIsIncorrectKind = "92021" IdToRemoveIsNotPresent = "92016" InconsistentNumberOfBillingCycles = "92018" InheritedFromIdIsInvalid = "92013" InheritedFromIdIsRequired = "92014" Missing = "92024" NumberOfBillingCyclesCannotBeBlank = "92017" NumberOfBillingCyclesIsInvalid = "92005" NumberOfBillingCyclesMustBeGreaterThanZero = "92019" QuantityCannotBeBlank = "92004" QuantityIsInvalid = "92001" QuantityMustBeGreaterThanZero = "92010" IdToRemoveIsInvalid = "92025" class Transaction(object): AmountCannotBeNegative = "81501" AmountDoesNotMatch3DSecureAmount = "91585" AmountDoesNotMatchIdealPaymentAmount = "915144" AmountIsInvalid = AmountFormatIsInvalid = "81503" AmountIsRequired = "81502" AmountIsTooLarge = "81528" AmountMustBeGreaterThanZero = "81531" AmountNotSupportedByProcessor = "815193" BillingAddressConflict = "91530" CannotBeVoided = "91504" CannotCancelRelease = "91562" CannotCloneCredit = "91543" CannotCloneMarketplaceTransaction = "915137" CannotCloneTransactionWithPayPalAccount = "91573" CannotCloneTransactionWithVaultCreditCard = "91540" CannotCloneUnsuccessfulTransaction = "91542" CannotCloneVoiceAuthorizations = "91541" CannotHoldInEscrow = "91560" CannotPartiallyRefundEscrowedTransaction = "91563" CannotRefundCredit = "91505" CannotRefundSettlingTransaction = "91574" CannotRefundUnlessSettled = "91506" CannotRefundWithPendingMerchantAccount = "91559" CannotRefundWithSuspendedMerchantAccount = "91538" CannotReleaseFromEscrow = "91561" CannotSimulateTransactionSettlement = "91575" CannotSubmitForPartialSettlement = "915103" CannotSubmitForSettlement = "91507" CannotUpdateTransactionDetailsNotSubmittedForSettlement = "915129" ChannelIsTooLong = "91550" ChannelIsTooLong = "91550" CreditCardIsRequired = "91508" CustomFieldIsInvalid = "91526" CustomFieldIsTooLong = "81527" CustomerDefaultPaymentMethodCardTypeIsNotAccepted = "81509" CustomerDoesNotHaveCreditCard = "91511" CustomerIdIsInvalid = "91510" FailedAuthAdjustmentAllowRetry = "95603" FailedAuthAdjustmentHardDecline = "95602" FinalAuthSubmitForSettlementForDifferentAmount = "95601" HasAlreadyBeenRefunded = "91512" IdealPaymentNotComplete = "815141" IdealPaymentsCannotBeVaulted = "915150" PaymentInstrumentWithExternalVaultIsInvalid = "915176" DiscountAmountFormatIsInvalid = "915159" DiscountAmountCannotBeNegative = "915160" DiscountAmountIsTooLarge = "915161" ShippingAmountFormatIsInvalid = "915162" ShippingAmountCannotBeNegative = "915163" ShippingAmountIsTooLarge = "915164" ShipsFromPostalCodeIsTooLong = "915165" ShipsFromPostalCodeIsInvalid = "915166" ShipsFromPostalCodeInvalidCharacters = "915167" MerchantAccountDoesNotMatch3DSecureMerchantAccount = "91584" MerchantAccountDoesNotMatchIdealPaymentMerchantAccount = "915143" MerchantAccountDoesNotSupportMOTO = "91558" MerchantAccountDoesNotSupportRefunds = "91547" MerchantAccountIdDoesNotMatchSubscription = "915180" MerchantAccountIdIsInvalid = "91513" MerchantAccountIsSusped = "91514" # Deprecated MerchantAccountIsSuspended = "91514" MerchantAccountNameIsInvalid = "91513" # Deprecated OrderIdDoesNotMatchIdealPaymentOrderId = "91503" OrderIdIsRequiredWithIdealPayment = "91502" OrderIdIsTooLong = "91501" PayPalAuthExpired = "91579" PayPalNotEnabled = "91576" PayPalVaultRecordMissingData = "91583" PaymentInstrumentNotSupportedByMerchantAccount = "91577" PaymentInstrumentTypeIsNotAccepted = "915101" PaymentMethodConflict = "91515" PaymentMethodConflictWithVenmoSDK = "91549" PaymentMethodDoesNotBelongToCustomer = "91516" PaymentMethodDoesNotBelongToSubscription = "91527" PaymentMethodNonceCardTypeIsNotAccepted = "91567" PaymentMethodNonceConsumed = "91564" PaymentMethodNonceHasNoValidPaymentInstrumentType = "91569" PaymentMethodNonceLocked = "91566" PaymentMethodNonceUnknown = "91565" PaymentMethodTokenCardTypeIsNotAccepted = "91517" PaymentMethodTokenIsInvalid = "91518" ProcessorAuthorizationCodeCannotBeSet = "91519" ProcessorAuthorizationCodeIsInvalid = "81520" ProcessorDoesNotSupportAuths = "915104" ProcessorDoesNotSupportCredits = "91546" ProcessorDoesNotSupportPartialSettlement = "915102" ProcessorDoesNotSupportUpdatingOrderId = "915107" ProcessorDoesNotSupportUpdatingDescriptor = "915108" ProcessorDoesNotSupportUpdatingTransactionDetails = "915130" ProcessorDoesNotSupportVoiceAuthorizations = "91545" PurchaseOrderNumberIsInvalid = "91548" PurchaseOrderNumberIsTooLong = "91537" RefundAmountIsTooLarge = "91521" ServiceFeeAmountCannotBeNegative = "91554" ServiceFeeAmountFormatIsInvalid = "91555" ServiceFeeAmountIsTooLarge = "91556" ServiceFeeAmountNotAllowedOnMasterMerchantAccount = "91557" ServiceFeeIsNotAllowedOnCredits = "91552" ServiceFeeNotAcceptedForPayPal = "91578" SettlementAmountIsLessThanServiceFeeAmount = "91551" SettlementAmountIsTooLarge = "91522" ShippingAddressDoesntMatchCustomer = "91581" SubMerchantAccountRequiresServiceFeeAmount = "91553" SubscriptionDoesNotBelongToCustomer = "91529" SubscriptionIdIsInvalid = "91528" SubscriptionStatusMustBePastDue = "91531" TaxAmountCannotBeNegative = "81534" TaxAmountFormatIsInvalid = "81535" TaxAmountIsTooLarge = "81536" ThreeDSecureAuthenticationFailed = "81571" ThreeDSecureTokenIsInvalid = "91568" ThreeDSecureTransactionDataDoesntMatchVerify = "91570" ThreeDSecureEciFlagIsRequired = "915113" ThreeDSecureCavvIsRequired = "915116" ThreeDSecureXidIsRequired = "915115" ThreeDSecureEciFlagIsInvalid = "915114" ThreeDSecureAuthenticationResponseIsInvalid = "915120" ThreeDSecureDirectoryResponseIsInvalid = "915121" ThreeDSecureCavvAlgorithmIsInvalid = "915122" ThreeDSecureMerchantAccountDoesNotSupportCardType = "915131" TooManyLineItems = "915157" LineItemsExpected = "915158" TypeIsInvalid = "91523" TypeIsRequired = "91524" UnsupportedVoiceAuthorization = "91539" UsBankAccountNonceMustBePlaidVerified = "915171" UsBankAccountNotVerified = "915172" TransactionSourceIsInvalid = "915133" class ExternalVault(object): StatusIsInvalid = "915175" StatusWithPreviousNetworkTransactionIdIsInvalid = "915177" CardTypeIsInvalid = "915178" PreviousNetworkTransactionIdIsInvalid = "915179" class Options(object): SubmitForSettlementIsRequiredForCloning = "91544" SubmitForSettlementIsRequiredForPayPalUnilateral = "91582" UseBillingForShippingDisabled = "91572" VaultIsDisabled = "91525" class PayPal(object): CustomFieldTooLong = "91580" class CreditCard(object): AccountTypeIsInvalid = "915184" AccountTypeNotSupported = "915185" AccountTypeDebitDoesNotSupportAuths = "915186" class Industry(object): IndustryTypeIsInvalid = "93401" class Lodging(object): EmptyData = "93402" FolioNumberIsInvalid = "93403" CheckInDateIsInvalid = "93404" CheckOutDateIsInvalid = "93405" CheckOutDateMustFollowCheckInDate = "93406" UnknownDataField = "93407" RoomRateMustBeGreaterThanZero = "93433" RoomRateFormatIsInvalid = "93434" RoomRateIsTooLarge = "93435" RoomTaxMustBeGreaterThanZero = "93436" RoomTaxFormatIsInvalid = "93437" RoomTaxIsTooLarge = "93438" NoShowIndicatorIsInvalid = "93439" AdvancedDepositIndicatorIsInvalid = "93440" FireSafetyIndicatorIsInvalid = "93441" PropertyPhoneIsInvalid = "93442" class TravelCruise(object): EmptyData = "93408" UnknownDataField = "93409" TravelPackageIsInvalid = "93410" DepartureDateIsInvalid = "93411" LodgingCheckInDateIsInvalid = "93412" LodgingCheckOutDateIsInvalid = "93413" class TravelFlight(object): EmptyData = "93414" UnknownDataField = "93415" CustomerCodeIsTooLong = "93416" FareAmountCannotBeNegative = "93417" FareAmountFormatIsInvalid = "93418" FareAmountIsTooLarge = "93419" FeeAmountCannotBeNegative = "93420" FeeAmountFormatIsInvalid = "93421" FeeAmountIsTooLarge = "93422" IssuedDateFormatIsInvalid = "93423" IssuingCarrierCodeIsTooLong = "93424" PassengerMiddleInitialIsTooLong = "93425" RestrictedTicketIsRequired = "93426" TaxAmountCannotBeNegative = "93427" TaxAmountFormatIsInvalid = "93428" TaxAmountIsTooLarge = "93429" TicketNumberIsTooLong = "93430" LegsExpected = "93431" TooManyLegs = "93432" class Leg(object): class TravelFlight(object): ArrivalAirportCodeIsTooLong = "96301" ArrivalTimeFormatIsInvalid = "96302" CarrierCodeIsTooLong = "96303" ConjunctionTicketIsTooLong = "96304" CouponNumberIsTooLong = "96305" DepartureAirportCodeIsTooLong = "96306" DepartureTimeFormatIsInvalid = "96307" ExchangeTicketIsTooLong = "96308" FareAmountCannotBeNegative = "96309" FareAmountFormatIsInvalid = "96310" FareAmountIsTooLarge = "96311" FareBasisCodeIsTooLong = "96312" FeeAmountCannotBeNegative = "96313" FeeAmountFormatIsInvalid = "96314" FeeAmountIsTooLarge = "96315" ServiceClassIsTooLong = "96316" TaxAmountCannotBeNegative = "96317" TaxAmountFormatIsInvalid = "96318" TaxAmountIsTooLarge = "96319" TicketNumberIsTooLong = "96320" class AdditionalCharge(object): KindIsInvalid = "96601" KindMustBeUnique = "96602" AmountMustBeGreaterThanZero = "96603" AmountFormatIsInvalid = "96604" AmountIsTooLarge = "96605" AmountIsRequired = "96606" class LineItem(object): CommodityCodeIsTooLong = "95801" DescriptionIsTooLong = "95803" DiscountAmountFormatIsInvalid = "95804" DiscountAmountIsTooLarge = "95805" DiscountAmountMustBeGreaterThanZero = "95806" # Deprecated as the amount may be zero. DiscountAmountCannotBeNegative = "95806" KindIsInvalid = "95807" KindIsRequired = "95808" NameIsRequired = "95822" NameIsTooLong = "95823" ProductCodeIsTooLong = "95809" QuantityFormatIsInvalid = "95810" QuantityIsRequired = "95811" QuantityIsTooLarge = "95812" TotalAmountFormatIsInvalid = "95813" TotalAmountIsRequired = "95814" TotalAmountIsTooLarge = "95815" TotalAmountMustBeGreaterThanZero = "95816" UnitAmountFormatIsInvalid = "95817" UnitAmountIsRequired = "95818" UnitAmountIsTooLarge = "95819" UnitAmountMustBeGreaterThanZero = "95820" UnitOfMeasureIsTooLarge = "95821" UnitTaxAmountFormatIsInvalid = "95824" UnitTaxAmountIsTooLarge = "95825" UnitTaxAmountMustBeGreaterThanZero = "95826" # Deprecated as the amount may be zero. UnitTaxAmountCannotBeNegative = "95826" TaxAmountFormatIsInvalid = "95827" TaxAmountIsTooLarge = "95828" TaxAmountCannotBeNegative = "95829" class UsBankAccountVerification(object): NotConfirmable = "96101" MustBeMicroTransfersVerification = "96102" AmountsDoNotMatch = "96103" TooManyConfirmationAttempts = "96104" UnableToConfirmDepositAmounts = "96105" InvalidDepositAmounts = "96106" braintree_python-3.57.1/braintree/transaction_details.py0000644000175000017500000000045213545202423021645 0ustar hlehlefrom decimal import Decimal from braintree.attribute_getter import AttributeGetter class TransactionDetails(AttributeGetter): def __init__(self, attributes): AttributeGetter.__init__(self, attributes) if self.amount is not None: self.amount = Decimal(self.amount) braintree_python-3.57.1/braintree/oauth_access_revocation.py0000644000175000017500000000035413545202423022506 0ustar hlehlefrom braintree.resource import Resource class OAuthAccessRevocation(Resource): """ A class representing an OAuth access revocation. """ def __init__(self, attributes): Resource.__init__(self, None, attributes) braintree_python-3.57.1/braintree/partner_merchant.py0000644000175000017500000000177213545202423021155 0ustar hlehlefrom braintree.configuration import Configuration from braintree.resource import Resource class PartnerMerchant(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "partner_merchant_id" in attributes: self.partner_merchant_id = attributes.pop("partner_merchant_id") if "private_key" in attributes: self.private_key = attributes.pop("private_key") if "public_key" in attributes: self.public_key = attributes.pop("public_key") if "merchant_public_id" in attributes: self.merchant_public_id = attributes.pop("merchant_public_id") if "client_side_encryption_key" in attributes: self.client_side_encryption_key = attributes.pop("client_side_encryption_key") def __repr__(self): detail_list = ["partner_merchant_id", "public_key", "merchant_public_id", "client_side_encryption_key"] return super(PartnerMerchant, self).__repr__(detail_list) braintree_python-3.57.1/braintree/connected_merchant_paypal_status_changed.py0000644000175000017500000000042313545202423026056 0ustar hlehlefrom braintree.resource import Resource class ConnectedMerchantPayPalStatusChanged(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) @property def merchant_id(self): return self.merchant_public_id braintree_python-3.57.1/braintree/three_d_secure_info.py0000644000175000017500000000015213545202423021603 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class ThreeDSecureInfo(AttributeGetter): pass braintree_python-3.57.1/braintree/local_payment_completed.py0000644000175000017500000000053413545202423022477 0ustar hlehlefrom braintree.resource import Resource from braintree.transaction import Transaction class LocalPaymentCompleted(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "transaction" in attributes: self.transaction = Transaction(gateway, attributes.pop("transaction")) braintree_python-3.57.1/braintree/transaction_line_item_gateway.py0000644000175000017500000000223513545202423023707 0ustar hlehleimport braintree from braintree.error_result import ErrorResult from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.transaction_line_item import TransactionLineItem from braintree.exceptions.not_found_error import NotFoundError from braintree.exceptions.down_for_maintenance_error import DownForMaintenanceError class TransactionLineItemGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def find_all(self, transaction_id): try: if transaction_id is None or transaction_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/line_items") if "line_items" in response: return [TransactionLineItem(item) for item in ResourceCollection._extract_as_array(response, "line_items")] else: raise DownForMaintenanceError() except NotFoundError: raise NotFoundError("transaction line items with id " + repr(transaction_id) + " not found") braintree_python-3.57.1/braintree/document_upload_gateway.py0000644000175000017500000000260713545202423022522 0ustar hlehleimport braintree import mimetypes from braintree.document_upload import DocumentUpload from braintree.error_result import ErrorResult from braintree.resource import Resource from braintree.successful_result import SuccessfulResult class DocumentUploadGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create(self, params={}): Resource.verify_keys(params, DocumentUpload.create_signature()) if "file" in params and not hasattr(params["file"], "read"): raise ValueError("file must be a file handle") response = self.config.http().post_multipart(self.config.base_merchant_path() + "/document_uploads", *self.__payload(params)) if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: return SuccessfulResult({"document_upload": DocumentUpload(self, response["document_upload"])}) def __file_name(self, file): return file.name.split("/")[-1] def __content_type(self, file): return mimetypes.guess_type(file.name)[0] def __payload(self, params): file = params.pop("file", None) files = { "file": (self.__file_name(file), file, self.__content_type(file)) } params["document_upload[kind]"] = params["kind"] return (files, params) braintree_python-3.57.1/braintree/facilitator_details.py0000644000175000017500000000015413545202423021620 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class FacilitatorDetails(AttributeGetter): pass braintree_python-3.57.1/braintree/modification.py0000644000175000017500000000036013545202423020256 0ustar hlehlefrom decimal import Decimal from braintree.resource import Resource class Modification(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.amount = Decimal(self.amount) braintree_python-3.57.1/braintree/resource_collection.py0000644000175000017500000000365113545202423021661 0ustar hlehleimport braintree from braintree.exceptions.unexpected_error import UnexpectedError class ResourceCollection(object): """ A class representing results from a search. Supports the iterator protocol:: results = braintree.Transaction.search("411111") for transaction in results: print transaction.id """ def __init__(self, query, results, method): if "search_results" not in results: raise UnexpectedError("Unprocessable entity due to an invalid request") self.__ids = results["search_results"]["ids"] self.__method = method self.__page_size = results["search_results"]["page_size"] self.__query = query @property def maximum_size(self): """ Returns the approximate size of the results. The size is approximate due to race conditions when pulling back results. Due to its inexact nature, maximum_size should be avoided. """ return len(self.__ids) @property def first(self): """ Returns the first item in the results. """ return self.__method(self.__query, self.__ids[0:1])[0] @property def items(self): """ Returns a generator allowing iteration over all of the results. """ for batch in self.__batch_ids(): for item in self.__method(self.__query, batch): yield item @property def ids(self): """ Returns the list of ids in the search result. """ return self.__ids def __iter__(self): return self.items def __batch_ids(self): for i in range(0, len(self.__ids), self.__page_size): yield self.__ids[i:i+self.__page_size] @staticmethod def _extract_as_array(results, attribute): if not attribute in results: return [] value = results[attribute] if not isinstance(value, list): value = [value] return value braintree_python-3.57.1/braintree/customer_search.py0000644000175000017500000000414213545202423021001 0ustar hlehlefrom braintree.search import Search class CustomerSearch: address_extended_address = Search.TextNodeBuilder("address_extended_address") address_first_name = Search.TextNodeBuilder("address_first_name") address_last_name = Search.TextNodeBuilder("address_last_name") address_locality = Search.TextNodeBuilder("address_locality") address_postal_code = Search.TextNodeBuilder("address_postal_code") address_region = Search.TextNodeBuilder("address_region") address_street_address = Search.TextNodeBuilder("address_street_address") address_country_name = Search.TextNodeBuilder("address_country_name") cardholder_name = Search.TextNodeBuilder("cardholder_name") company = Search.TextNodeBuilder("company") created_at = Search.RangeNodeBuilder("created_at") credit_card_expiration_date = Search.EqualityNodeBuilder("credit_card_expiration_date") credit_card_number = Search.TextNodeBuilder("credit_card_number") email = Search.TextNodeBuilder("email") fax = Search.TextNodeBuilder("fax") first_name = Search.TextNodeBuilder("first_name") id = Search.TextNodeBuilder("id") ids = Search.MultipleValueNodeBuilder("ids") last_name = Search.TextNodeBuilder("last_name") payment_method_token = Search.TextNodeBuilder("payment_method_token") payment_method_token_with_duplicates = Search.IsNodeBuilder("payment_method_token_with_duplicates") phone = Search.TextNodeBuilder("phone") website = Search.TextNodeBuilder("website") paypal_account_email = Search.TextNodeBuilder("paypal_account_email") braintree_python-3.57.1/braintree/paypal_account_gateway.py0000644000175000017500000000334013545202423022335 0ustar hlehleimport braintree from braintree.paypal_account import PayPalAccount from braintree.error_result import ErrorResult from braintree.exceptions.not_found_error import NotFoundError from braintree.resource import Resource from braintree.successful_result import SuccessfulResult class PayPalAccountGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def find(self, paypal_account_token): try: if paypal_account_token is None or paypal_account_token.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_methods/paypal_account/" + paypal_account_token) if "paypal_account" in response: return PayPalAccount(self.gateway, response["paypal_account"]) except NotFoundError: raise NotFoundError("paypal account with token " + repr(paypal_account_token) + " not found") def delete(self, paypal_account_token): self.config.http().delete(self.config.base_merchant_path() + "/payment_methods/paypal_account/" + paypal_account_token) return SuccessfulResult() def update(self, paypal_account_token, params={}): Resource.verify_keys(params, PayPalAccount.signature()) response = self.config.http().put(self.config.base_merchant_path() + "/payment_methods/paypal_account/" + paypal_account_token, {"paypal_account": params}) if "paypal_account" in response: return SuccessfulResult({"paypal_account": PayPalAccount(self.gateway, response["paypal_account"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) braintree_python-3.57.1/braintree/braintree_gateway.py0000644000175000017500000001040013545202423021301 0ustar hlehlefrom braintree.add_on_gateway import AddOnGateway from braintree.address_gateway import AddressGateway from braintree.client_token_gateway import ClientTokenGateway from braintree.configuration import Configuration from braintree.credit_card_gateway import CreditCardGateway from braintree.credit_card_verification_gateway import CreditCardVerificationGateway from braintree.customer_gateway import CustomerGateway from braintree.document_upload_gateway import DocumentUploadGateway from braintree.discount_gateway import DiscountGateway from braintree.dispute_gateway import DisputeGateway from braintree.merchant_account_gateway import MerchantAccountGateway from braintree.merchant_gateway import MerchantGateway from braintree.oauth_gateway import OAuthGateway from braintree.payment_method_gateway import PaymentMethodGateway from braintree.payment_method_nonce_gateway import PaymentMethodNonceGateway from braintree.paypal_account_gateway import PayPalAccountGateway from braintree.plan_gateway import PlanGateway from braintree.settlement_batch_summary_gateway import SettlementBatchSummaryGateway from braintree.subscription_gateway import SubscriptionGateway from braintree.testing_gateway import TestingGateway from braintree.transaction_gateway import TransactionGateway from braintree.transaction_line_item_gateway import TransactionLineItemGateway from braintree.transparent_redirect_gateway import TransparentRedirectGateway from braintree.us_bank_account_gateway import UsBankAccountGateway from braintree.us_bank_account_verification_gateway import UsBankAccountVerificationGateway from braintree.webhook_notification_gateway import WebhookNotificationGateway from braintree.webhook_testing_gateway import WebhookTestingGateway # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. from braintree.ideal_payment_gateway import IdealPaymentGateway import braintree.configuration class BraintreeGateway(object): def __init__(self, config=None, **kwargs): if isinstance(config, braintree.configuration.Configuration): self.config = config else: self.config = Configuration( client_id=kwargs.get("client_id"), client_secret=kwargs.get("client_secret"), access_token=kwargs.get("access_token"), http_strategy=kwargs.get("http_strategy") ) self.graphql_client = self.config.graphql_client() self.add_on = AddOnGateway(self) self.address = AddressGateway(self) self.client_token = ClientTokenGateway(self) self.credit_card = CreditCardGateway(self) self.customer = CustomerGateway(self) self.document_upload = DocumentUploadGateway(self) self.discount = DiscountGateway(self) self.dispute = DisputeGateway(self) self.merchant_account = MerchantAccountGateway(self) self.merchant = MerchantGateway(self) self.oauth = OAuthGateway(self) self.plan = PlanGateway(self) self.settlement_batch_summary = SettlementBatchSummaryGateway(self) self.subscription = SubscriptionGateway(self) self.transaction = TransactionGateway(self) self.transaction_line_item = TransactionLineItemGateway(self) self.transparent_redirect = TransparentRedirectGateway(self) self.verification = CreditCardVerificationGateway(self) self.webhook_notification = WebhookNotificationGateway(self) self.webhook_testing = WebhookTestingGateway(self) self.payment_method = PaymentMethodGateway(self) self.payment_method_nonce = PaymentMethodNonceGateway(self) self.paypal_account = PayPalAccountGateway(self) self.testing = TestingGateway(self) self.us_bank_account = UsBankAccountGateway(self) self.us_bank_account_verification = UsBankAccountVerificationGateway(self) # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. self.ideal_payment = IdealPaymentGateway(self) braintree_python-3.57.1/braintree/transaction.py0000644000175000017500000007706113545202423020152 0ustar hlehleimport braintree import warnings from decimal import Decimal from braintree.add_on import AddOn from braintree.apple_pay_card import ApplePayCard from braintree.authorization_adjustment import AuthorizationAdjustment from braintree.coinbase_account import CoinbaseAccount from braintree.android_pay_card import AndroidPayCard from braintree.amex_express_checkout_card import AmexExpressCheckoutCard from braintree.venmo_account import VenmoAccount from braintree.disbursement_detail import DisbursementDetail from braintree.dispute import Dispute from braintree.discount import Discount from braintree.successful_result import SuccessfulResult from braintree.status_event import StatusEvent from braintree.error_result import ErrorResult from braintree.resource import Resource from braintree.address import Address from braintree.configuration import Configuration from braintree.credit_card import CreditCard from braintree.customer import Customer from braintree.paypal_account import PayPalAccount from braintree.paypal_here import PayPalHere from braintree.europe_bank_account import EuropeBankAccount from braintree.subscription_details import SubscriptionDetails from braintree.resource_collection import ResourceCollection from braintree.transparent_redirect import TransparentRedirect from braintree.exceptions.not_found_error import NotFoundError from braintree.descriptor import Descriptor from braintree.risk_data import RiskData from braintree.three_d_secure_info import ThreeDSecureInfo from braintree.transaction_line_item import TransactionLineItem from braintree.us_bank_account import UsBankAccount # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. from braintree.ideal_payment import IdealPayment from braintree.local_payment import LocalPayment from braintree.visa_checkout_card import VisaCheckoutCard from braintree.masterpass_card import MasterpassCard from braintree.facilitated_details import FacilitatedDetails from braintree.facilitator_details import FacilitatorDetails from braintree.payment_instrument_type import PaymentInstrumentType from braintree.samsung_pay_card import SamsungPayCard class Transaction(Resource): """ A class representing Braintree Transaction objects. An example of creating a sale transaction with all available fields:: result = Transaction.sale({ "amount": "100.00", "order_id": "123", "channel": "MyShoppingCartProvider", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2011", "cvv": "123" }, "customer": { "first_name": "Dan", "last_name": "Smith", "company": "Braintree", "email": "dan@example.com", "phone": "419-555-1234", "fax": "419-555-1235", "website": "https://www.braintreepayments.com" }, "billing": { "first_name": "Carl", "last_name": "Jones", "company": "Braintree", "street_address": "123 E Main St", "extended_address": "Suite 403", "locality": "Chicago", "region": "IL", "postal_code": "60622", "country_name": "United States of America" }, "shipping": { "first_name": "Andrew", "last_name": "Mason", "company": "Braintree", "street_address": "456 W Main St", "extended_address": "Apt 2F", "locality": "Bartlett", "region": "IL", "postal_code": "60103", "country_name": "United States of America" } }) print(result.transaction.amount) print(result.transaction.order_id) For more information on Transactions, see https://developers.braintreepayments.com/reference/request/transaction/sale/python """ def __repr__(self): detail_list = [ "id", "additional_processor_response", "amount", "authorization_adjustments", "authorization_expires_at", "avs_error_response_code", "avs_postal_code_response_code", "avs_street_address_response_code", "channel", "created_at", "credit_card_details", "currency_iso_code", "customer_id", "cvv_response_code", "discount_amount", "disputes", "escrow_status", "gateway_rejection_reason", "master_merchant_account_id", "merchant_account_id", "network_response_code", "network_response_text", "network_transaction_id", "order_id", "payment_instrument_type", "payment_method_token", "plan_id", "processor_authorization_code", "processor_response_code", "processor_response_text", "processor_settlement_response_code", "processor_settlement_response_text", "purchase_order_number", "recurring", "refund_id", "refunded_transaction_id", "service_fee_amount", "settlement_batch_id", "shipping_amount", "ships_from_postal_code", "status", "status_history", "sub_merchant_account_id", "subscription_id", "tax_amount", "tax_exempt", "type", "updated_at", "voice_referral_number", ] return super(Transaction, self).__repr__(detail_list) class CreatedUsing(object): """ Constants representing how the transaction was created. Available types are: * braintree.Transaction.CreatedUsing.FullInformation * braintree.Transaction.CreatedUsing.Token """ FullInformation = "full_information" Token = "token" Unrecognized = "unrecognized" class GatewayRejectionReason(object): """ Constants representing gateway rejection reasons. Available types are: * braintree.Transaction.GatewayRejectionReason.Avs * braintree.Transaction.GatewayRejectionReason.AvsAndCvv * braintree.Transaction.GatewayRejectionReason.Cvv * braintree.Transaction.GatewayRejectionReason.Duplicate * braintree.Transaction.GatewayRejectionReason.Fraud * braintree.Transaction.GatewayRejectionReason.ThreeDSecure """ ApplicationIncomplete = "application_incomplete" Avs = "avs" AvsAndCvv = "avs_and_cvv" Cvv = "cvv" Duplicate = "duplicate" Fraud = "fraud" ThreeDSecure = "three_d_secure" TokenIssuance = "token_issuance" Unrecognized = "unrecognized" class Source(object): Api = "api" ControlPanel = "control_panel" Recurring = "recurring" Unrecognized = "unrecognized" class EscrowStatus(object): """ Constants representing transaction escrow statuses. Available statuses are: * braintree.Transaction.EscrowStatus.HoldPending * braintree.Transaction.EscrowStatus.Held * braintree.Transaction.EscrowStatus.ReleasePending * braintree.Transaction.EscrowStatus.Released * braintree.Transaction.EscrowStatus.Refunded """ HoldPending = "hold_pending" Held = "held" ReleasePending = "release_pending" Released = "released" Refunded = "refunded" Unrecognized = "unrecognized" class Status(object): """ Constants representing transaction statuses. Available statuses are: * braintree.Transaction.Status.AuthorizationExpired * braintree.Transaction.Status.Authorized * braintree.Transaction.Status.Authorizing * braintree.Transaction.Status.SettlementPending * braintree.Transaction.Status.SettlementDeclined * braintree.Transaction.Status.Failed * braintree.Transaction.Status.GatewayRejected * braintree.Transaction.Status.ProcessorDeclined * braintree.Transaction.Status.Settled * braintree.Transaction.Status.Settling * braintree.Transaction.Status.SubmittedForSettlement * braintree.Transaction.Status.Voided """ AuthorizationExpired = "authorization_expired" Authorized = "authorized" Authorizing = "authorizing" Failed = "failed" GatewayRejected = "gateway_rejected" ProcessorDeclined = "processor_declined" Settled = "settled" SettlementConfirmed = "settlement_confirmed" SettlementDeclined = "settlement_declined" SettlementFailed = "settlement_failed" SettlementPending = "settlement_pending" Settling = "settling" SubmittedForSettlement = "submitted_for_settlement" Voided = "voided" # NEXT_MAJOR_VERSION this is never used and should be removed Unrecognized = "unrecognized" class Type(object): """ Constants representing transaction types. Available types are: * braintree.Transaction.Type.Credit * braintree.Transaction.Type.Sale """ Credit = "credit" Sale = "sale" class IndustryType(object): Lodging = "lodging" TravelAndCruise = "travel_cruise" TravelAndFlight = "travel_flight" class AdditionalCharge(object): Restaurant = "restaurant" GiftShop = "gift_shop" MiniBar = "mini_bar" Telephone = "telephone" Laundry = "laundry" Other = "other" @staticmethod def clone_transaction(transaction_id, params): return Configuration.gateway().transaction.clone_transaction(transaction_id, params) @staticmethod def cancel_release(transaction_id): """ Cancels a pending release from escrow for a transaction. Requires the transaction id:: result = braintree.Transaction.cancel_release("my_transaction_id") """ return Configuration.gateway().transaction.cancel_release(transaction_id) @staticmethod def confirm_transparent_redirect(query_string): """ Confirms a transparent redirect request. It expects the query string from the redirect request. The query string should _not_ include the leading "?" character. :: result = braintree.Transaction.confirm_transparent_redirect_request("foo=bar&id=12345") """ warnings.warn("Please use TransparentRedirect.confirm instead", DeprecationWarning) return Configuration.gateway().transaction.confirm_transparent_redirect(query_string) @staticmethod def credit(params={}): """ Creates a transaction of type Credit. Amount is required. Also, a credit card, customer_id or payment_method_token is required. :: result = braintree.Transaction.credit({ "amount": "100.00", "payment_method_token": "my_token" }) result = braintree.Transaction.credit({ "amount": "100.00", "credit_card": { "number": "4111111111111111", "expiration_date": "12/2012" } }) result = braintree.Transaction.credit({ "amount": "100.00", "customer_id": "my_customer_id" }) """ params["type"] = Transaction.Type.Credit return Transaction.create(params) @staticmethod def find(transaction_id): """ Find a transaction, given a transaction_id. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided credit_card_id is not found. :: transaction = braintree.Transaction.find("my_transaction_id") """ return Configuration.gateway().transaction.find(transaction_id) @staticmethod def line_items(transaction_id): """ Find a transaction's line items, given a transaction_id. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided transaction_id is not found. :: """ return Configuration.gateway().transaction_line_item.find_all(transaction_id) @staticmethod def hold_in_escrow(transaction_id): """ Holds an existing submerchant transaction for escrow. It expects a transaction_id.:: result = braintree.Transaction.hold_in_escrow("my_transaction_id") """ return Configuration.gateway().transaction.hold_in_escrow(transaction_id) @staticmethod def refund(transaction_id, amount_or_options=None): """ Refunds an existing transaction. It expects a transaction_id.:: result = braintree.Transaction.refund("my_transaction_id") """ return Configuration.gateway().transaction.refund(transaction_id, amount_or_options) @staticmethod def sale(params={}): """ Creates a transaction of type Sale. Amount is required. Also, a credit card, customer_id or payment_method_token is required. :: result = braintree.Transaction.sale({ "amount": "100.00", "payment_method_token": "my_token" }) result = braintree.Transaction.sale({ "amount": "100.00", "credit_card": { "number": "4111111111111111", "expiration_date": "12/2012" } }) result = braintree.Transaction.sale({ "amount": "100.00", "customer_id": "my_customer_id" }) """ params["type"] = Transaction.Type.Sale return Transaction.create(params) @staticmethod def search(*query): return Configuration.gateway().transaction.search(*query) @staticmethod def release_from_escrow(transaction_id): """ Submits an escrowed transaction for release. Requires the transaction id:: result = braintree.Transaction.release_from_escrow("my_transaction_id") """ return Configuration.gateway().transaction.release_from_escrow(transaction_id) @staticmethod def submit_for_settlement(transaction_id, amount=None, params={}): """ Submits an authorized transaction for settlement. Requires the transaction id:: result = braintree.Transaction.submit_for_settlement("my_transaction_id") """ return Configuration.gateway().transaction.submit_for_settlement(transaction_id, amount, params) @staticmethod def update_details(transaction_id, params={}): """ Updates exisiting details for transaction submtted_for_settlement. Requires the transaction id:: result = braintree.Transaction.update_details("my_transaction_id", { "amount": "100.00", "order_id": "123", "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "url.com" } ) """ return Configuration.gateway().transaction.update_details(transaction_id, params) @staticmethod def tr_data_for_credit(tr_data, redirect_url): """ Builds tr_data for a Transaction of type Credit """ return Configuration.gateway().transaction.tr_data_for_credit(tr_data, redirect_url) @staticmethod def tr_data_for_sale(tr_data, redirect_url): """ Builds tr_data for a Transaction of type Sale """ return Configuration.gateway().transaction.tr_data_for_sale(tr_data, redirect_url) @staticmethod def transparent_redirect_create_url(): """ Returns the url to be used for creating Transactions through transparent redirect. """ warnings.warn("Please use TransparentRedirect.url instead", DeprecationWarning) return Configuration.gateway().transaction.transparent_redirect_create_url() @staticmethod def void(transaction_id): """ Voids an existing transaction. It expects a transaction_id.:: result = braintree.Transaction.void("my_transaction_id") """ return Configuration.gateway().transaction.void(transaction_id) @staticmethod def create(params): """ Creates a transaction. Amount and type are required. Also, a credit card, customer_id or payment_method_token is required. :: result = braintree.Transaction.sale({ "type": braintree.Transaction.Type.Sale, "amount": "100.00", "payment_method_token": "my_token" }) result = braintree.Transaction.sale({ "type": braintree.Transaction.Type.Sale, "amount": "100.00", "credit_card": { "number": "4111111111111111", "expiration_date": "12/2012" } }) result = braintree.Transaction.sale({ "type": braintree.Transaction.Type.Sale, "amount": "100.00", "customer_id": "my_customer_id" }) """ return Configuration.gateway().transaction.create(params) @staticmethod def clone_signature(): return ["amount", "channel", {"options": ["submit_for_settlement"]}] @staticmethod def create_signature(): return [ "amount", "customer_id", "device_session_id", "fraud_merchant_id", "merchant_account_id", "order_id", "channel", "payment_method_token", "purchase_order_number", "recurring", "transaction_source", "shipping_address_id", "device_data", "billing_address_id", "payment_method_nonce", "tax_amount", "shared_payment_method_token", "shared_customer_id", "shared_billing_address_id", "shared_shipping_address_id", "shared_payment_method_nonce", "discount_amount", "shipping_amount", "ships_from_postal_code", "tax_exempt", "three_d_secure_token", "type", "venmo_sdk_payment_method_code", "service_fee_amount", { "risk_data": [ "customer_browser", "customer_ip" ] }, { "credit_card": [ "token", "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", "number" ] }, { "customer": [ "id", "company", "email", "fax", "first_name", "last_name", "phone", "website" ] }, { "billing": [ "first_name", "last_name", "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "locality", "postal_code", "region", "street_address" ] }, { "shipping": [ "first_name", "last_name", "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "locality", "postal_code", "region", "street_address" ] }, { "three_d_secure_pass_thru": [ "eci_flag", "cavv", "xid", "authentication_response", "directory_response", "cavv_algorithm", "ds_transaction_id", "three_d_secure_version" ] }, { "options": [ "add_billing_address_to_payment_method", "hold_in_escrow", "store_in_vault", "store_in_vault_on_success", "store_shipping_address_in_vault", "submit_for_settlement", "venmo_sdk_session", "payee_id", "payee_email", "skip_advanced_fraud_checking", "skip_avs", "skip_cvv", { "credit_card": [ "account_type" ], "paypal": [ "payee_id", "payee_email", "custom_field", "description", {"supplementary_data": ["__any_key__"]} ], "three_d_secure": [ "required" ], "amex_rewards": [ "request_id", "points", "currency_amount", "currency_iso_code" ], "venmo_merchant_data": [ "venmo_merchant_public_id", "originating_transaction_id", "originating_merchant_id", "originating_merchant_kind" ], "venmo": [ "profile_id" ], }, { "adyen": [ "overwrite_brand", "selected_brand" ] } ] }, {"custom_fields": ["__any_key__"]}, {"external_vault": ["status", "previous_network_transaction_id"]}, {"descriptor": ["name", "phone", "url"]}, {"paypal_account": ["payee_id", "payee_email", "payer_id", "payment_id"]}, {"industry": [ "industry_type", { "data": [ "folio_number", "check_in_date", "check_out_date", "departure_date", "lodging_check_in_date", "lodging_check_out_date", "travel_package", "lodging_name", "room_rate", "passenger_first_name", "passenger_last_name", "passenger_middle_initial", "passenger_title", "issued_date", "travel_agency_name", "travel_agency_code", "ticket_number", "issuing_carrier_code", "customer_code", "fare_amount", "fee_amount", "room_tax", "tax_amount", "restricted_ticket", "no_show", "advanced_deposit", "fire_safe", "property_phone", { "legs": [ "conjunction_ticket", "exchange_ticket", "coupon_number", "service_class", "carrier_code", "fare_basis_code", "flight_number", "departure_date", "departure_airport_code", "departure_time", "arrival_airport_code", "arrival_time", "stopover_permitted", "fare_amount", "fee_amount", "tax_amount", "endorsement_or_restrictions" ] }, { "additional_charges": [ "kind", "amount" ], } ] } ] }, {"line_items": [ "quantity", "name", "description", "kind", "unit_amount", "unit_tax_amount", "total_amount", "discount_amount", "tax_amount", "unit_of_measure", "product_code", "commodity_code", "url", ] }, ] @staticmethod def submit_for_settlement_signature(): return ["order_id", {"descriptor": ["name", "phone", "url"]}] @staticmethod def update_details_signature(): return ["amount", "order_id", {"descriptor": ["name", "phone", "url"]}] @staticmethod def refund_signature(): return ["amount", "order_id"] @staticmethod def submit_for_partial_settlement(transaction_id, amount, params={}): """ Creates a partial settlement transaction for an authorized transaction Requires the transaction id of the authorized transaction and an amount:: result = braintree.Transaction.submit_for_partial_settlement("my_transaction_id", "20.00") """ return Configuration.gateway().transaction.submit_for_partial_settlement(transaction_id, amount, params) def __init__(self, gateway, attributes): if "refund_id" in attributes: self._refund_id = attributes["refund_id"] del(attributes["refund_id"]) else: self._refund_id = None Resource.__init__(self, gateway, attributes) self.amount = Decimal(self.amount) if "tax_amount" in attributes and self.tax_amount: self.tax_amount = Decimal(self.tax_amount) if "discount_amount" in attributes and self.discount_amount: self.discount_amount = Decimal(self.discount_amount) if "shipping_amount" in attributes and self.shipping_amount: self.shipping_amount = Decimal(self.shipping_amount) if "billing" in attributes: self.billing_details = Address(gateway, attributes.pop("billing")) if "credit_card" in attributes: self.credit_card_details = CreditCard(gateway, attributes.pop("credit_card")) if "paypal" in attributes: self.paypal_details = PayPalAccount(gateway, attributes.pop("paypal")) if "paypal_here" in attributes: self.paypal_here_details = PayPalHere(gateway, attributes.pop("paypal_here")) if "local_payment" in attributes: self.local_payment_details = LocalPayment(gateway, attributes.pop("local_payment")) if "europe_bank_account" in attributes: self.europe_bank_account_details = EuropeBankAccount(gateway, attributes.pop("europe_bank_account")) if "us_bank_account" in attributes: self.us_bank_account = UsBankAccount(gateway, attributes.pop("us_bank_account")) # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. if "ideal_payment" in attributes: self.ideal_payment_details = IdealPayment(gateway, attributes.pop("ideal_payment")) if "apple_pay" in attributes: self.apple_pay_details = ApplePayCard(gateway, attributes.pop("apple_pay")) if "coinbase_account" in attributes: self.coinbase_details = CoinbaseAccount(gateway, attributes.pop("coinbase_account")) if "android_pay_card" in attributes: self.android_pay_card_details = AndroidPayCard(gateway, attributes.pop("android_pay_card")) if "amex_express_checkout_card" in attributes: self.amex_express_checkout_card_details = AmexExpressCheckoutCard(gateway, attributes.pop("amex_express_checkout_card")) if "venmo_account" in attributes: self.venmo_account_details = VenmoAccount(gateway, attributes.pop("venmo_account")) if "visa_checkout_card" in attributes: self.visa_checkout_card_details = VisaCheckoutCard(gateway, attributes.pop("visa_checkout_card")) if "masterpass_card" in attributes: self.masterpass_card_details = MasterpassCard(gateway, attributes.pop("masterpass_card")) if "samsung_pay_card" in attributes: self.samsung_pay_card_details = SamsungPayCard(gateway, attributes.pop("samsung_pay_card")) if "customer" in attributes: self.customer_details = Customer(gateway, attributes.pop("customer")) if "shipping" in attributes: self.shipping_details = Address(gateway, attributes.pop("shipping")) if "add_ons" in attributes: self.add_ons = [AddOn(gateway, add_on) for add_on in self.add_ons] if "discounts" in attributes: self.discounts = [Discount(gateway, discount) for discount in self.discounts] if "status_history" in attributes: self.status_history = [StatusEvent(gateway, status_event) for status_event in self.status_history] if "subscription" in attributes: self.subscription_details = SubscriptionDetails(attributes.pop("subscription")) if "descriptor" in attributes: self.descriptor = Descriptor(gateway, attributes.pop("descriptor")) if "disbursement_details" in attributes: self.disbursement_details = DisbursementDetail(attributes.pop("disbursement_details")) if "disputes" in attributes: self.disputes = [Dispute(dispute) for dispute in self.disputes] if "authorization_adjustments" in attributes: self.authorization_adjustments = [AuthorizationAdjustment(authorization_adjustment) for authorization_adjustment in self.authorization_adjustments] if "payment_instrument_type" in attributes: self.payment_instrument_type = attributes["payment_instrument_type"] if "risk_data" in attributes: self.risk_data = RiskData(attributes["risk_data"]) else: self.risk_data = None if "three_d_secure_info" in attributes and not attributes["three_d_secure_info"] is None: self.three_d_secure_info = ThreeDSecureInfo(attributes["three_d_secure_info"]) else: self.three_d_secure_info = None if "facilitated_details" in attributes: self.facilitated_details = FacilitatedDetails(attributes.pop("facilitated_details")) if "facilitator_details" in attributes: self.facilitator_details = FacilitatorDetails(attributes.pop("facilitator_details")) if "network_transaction_id" in attributes: self.network_transaction_id = attributes["network_transaction_id"] @property def refund_id(self): warnings.warn("Please use Transaction.refund_ids instead", DeprecationWarning) return self._refund_id @property def vault_billing_address(self): """ The vault billing address associated with this transaction """ return self.gateway.address.find(self.customer_details.id, self.billing_details.id) @property def vault_credit_card(self): """ The vault credit card associated with this transaction """ if self.credit_card_details.token is None: return None return self.gateway.credit_card.find(self.credit_card_details.token) @property def vault_customer(self): """ The vault customer associated with this transaction """ if self.customer_details.id is None: return None return self.gateway.customer.find(self.customer_details.id) @property def is_disbursed(self): return self.disbursement_details.is_valid @property def line_items(self): """ The line items associated with this transaction """ return self.gateway.transaction_line_item.find_all(self.id) braintree_python-3.57.1/braintree/connected_merchant_status_transitioned.py0000644000175000017500000000042213545202423025621 0ustar hlehlefrom braintree.resource import Resource class ConnectedMerchantStatusTransitioned(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) @property def merchant_id(self): return self.merchant_public_id braintree_python-3.57.1/braintree/merchant.py0000644000175000017500000000057513545202423017422 0ustar hlehlefrom braintree.resource import Resource from braintree.merchant_account import MerchantAccount class Merchant(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "merchant_accounts" in attributes: self.merchant_accounts = [MerchantAccount(gateway, ma) for ma in attributes.get("merchant_accounts")] braintree_python-3.57.1/braintree/account_updater_daily_report.py0000644000175000017500000000111113545202423023541 0ustar hlehlefrom braintree.configuration import Configuration from braintree.resource import Resource class AccountUpdaterDailyReport(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "report_url" in attributes: self.report_url = attributes.pop("report_url") if "report_date" in attributes: self.report_date = attributes.pop("report_date") def __repr__(self): detail_list = ["report_url", "report_date"] return super(AccountUpdaterDailyReport, self).__repr__(detail_list) braintree_python-3.57.1/braintree/oauth_gateway.py0000644000175000017500000000530413545202423020455 0ustar hlehleimport braintree from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult from braintree.exceptions.not_found_error import NotFoundError from braintree.oauth_credentials import OAuthCredentials import sys if sys.version_info[0] == 2: from urllib import quote_plus else: from urllib.parse import quote_plus from functools import reduce class OAuthGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create_token_from_code(self, params): params["grant_type"] = "authorization_code" return self._create_token(params) def create_token_from_refresh_token(self, params): params["grant_type"] = "refresh_token" return self._create_token(params) def revoke_access_token(self, access_token): self.config.assert_has_client_credentials() response = self.config.http().post("/oauth/revoke_access_token", { "token": access_token }) if "result" in response and response["result"]["success"]: return SuccessfulResult else: return ErrorResult(self.gateway, "could not revoke access token") def _create_token(self, params): self.config.assert_has_client_credentials() response = self.config.http().post("/oauth/access_tokens", { "credentials": params }) if "credentials" in response: return SuccessfulResult({"credentials": OAuthCredentials(self.gateway, response["credentials"])}) else: return ErrorResult(self.gateway, response["api_error_response"]) def connect_url(self, raw_params): params = {"client_id": self.config.client_id} params.update(raw_params) user_params = self._sub_query(params, "user") business_params = self._sub_query(params, "business") def clean_values(accumulator, kv_pair): key, value = kv_pair if isinstance(value, list): accumulator += [(key + "[]", v) for v in value] else: accumulator += [(key, value)] return accumulator params = reduce(clean_values, params.items(), []) query = params + user_params + business_params query_string = "&".join(quote_plus(key) + "=" + quote_plus(value) for key, value in query) return self.config.environment.base_url + "/oauth/connect?" + query_string def _sub_query(self, params, root): if root in params: sub_query = params.pop(root) else: sub_query = {} query = [(root + "[" + key + "]", str(value)) for key, value in sub_query.items()] return query braintree_python-3.57.1/braintree/webhook_testing_gateway.py0000644000175000017500000007124113545202423022533 0ustar hlehlefrom braintree.util.crypto import Crypto from braintree.webhook_notification import WebhookNotification import sys if sys.version_info[0] == 2: from base64 import encodestring as encodebytes else: from base64 import encodebytes from datetime import datetime class WebhookTestingGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def sample_notification(self, kind, id, source_merchant_id=None): payload = encodebytes(self.__sample_xml(kind, id, source_merchant_id)) hmac_payload = Crypto.sha1_hmac_hash(self.gateway.config.private_key, payload) signature = "%s|%s" % (self.gateway.config.public_key, hmac_payload) return {'bt_signature': signature, 'bt_payload': payload} def __sample_xml(self, kind, id, source_merchant_id): timestamp = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") source_merchant_id_xml = '' if source_merchant_id is not None: source_merchant_id_xml = '%s' % source_merchant_id sample_xml = """ %s %s %s %s """ % (timestamp, kind, source_merchant_id_xml, self.__subject_sample_xml(kind, id)) return sample_xml.encode('utf-8') def __subject_sample_xml(self, kind, id): if kind == WebhookNotification.Kind.Check: return self.__check_sample_xml() if kind == WebhookNotification.Kind.ConnectedMerchantStatusTransitioned: return self.__connected_merchant_status_transitioned_xml(id) if kind == WebhookNotification.Kind.ConnectedMerchantPayPalStatusChanged: return self.__connected_merchant_paypal_status_changed_xml(id) if kind == WebhookNotification.Kind.SubMerchantAccountApproved: return self.__merchant_account_approved_sample_xml(id) elif kind == WebhookNotification.Kind.SubMerchantAccountDeclined: return self.__merchant_account_declined_sample_xml(id) elif kind == WebhookNotification.Kind.TransactionDisbursed: return self.__transaction_disbursed_sample_xml(id) elif kind == WebhookNotification.Kind.TransactionSettled: return self.__transaction_settled_sample_xml(id) elif kind == WebhookNotification.Kind.TransactionSettlementDeclined: return self.__transaction_settlement_declined_sample_xml(id) elif kind == WebhookNotification.Kind.PartnerMerchantConnected: return self.__partner_merchant_connected_sample_xml() elif kind == WebhookNotification.Kind.PartnerMerchantDisconnected: return self.__partner_merchant_disconnected_sample_xml() elif kind == WebhookNotification.Kind.PartnerMerchantDeclined: return self.__partner_merchant_declined_sample_xml() elif kind == WebhookNotification.Kind.OAuthAccessRevoked: return self.__oauth_access_revocation_sample_xml(id) elif kind == WebhookNotification.Kind.DisbursementException: return self.__disbursement_exception_sample_xml(id) elif kind == WebhookNotification.Kind.Disbursement: return self.__disbursement_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeOpened: return self.__dispute_opened_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeLost: return self.__dispute_lost_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeWon: return self.__dispute_won_sample_xml(id) elif kind == WebhookNotification.Kind.SubscriptionChargedSuccessfully: return self.__subscription_charged_successfully_sample_xml(id) elif kind == WebhookNotification.Kind.SubscriptionChargedUnsuccessfully: return self.__subscription_charged_unsuccessfully_sample_xml(id) elif kind == WebhookNotification.Kind.AccountUpdaterDailyReport: return self.__account_updater_daily_report_sample_xml() # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. elif kind == WebhookNotification.Kind.IdealPaymentComplete: return self.__ideal_payment_complete_sample_xml(id) # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. elif kind == WebhookNotification.Kind.IdealPaymentFailed: return self.__ideal_payment_failed_sample_xml(id) # NEXT_MAJOR_VERSION remove GrantedPaymentInstrumentUpdate elif kind == WebhookNotification.Kind.GrantedPaymentInstrumentUpdate: return self.__granted_payment_instrument_update() elif kind == WebhookNotification.Kind.GrantorUpdatedGrantedPaymentMethod: return self.__granted_payment_instrument_update() elif kind == WebhookNotification.Kind.RecipientUpdatedGrantedPaymentMethod: return self.__granted_payment_instrument_update() elif kind == WebhookNotification.Kind.PaymentMethodRevokedByCustomer: return self.__payment_method_revoked_by_customer(id) elif kind == WebhookNotification.Kind.LocalPaymentCompleted: return self.__local_payment_completed() else: return self.__subscription_sample_xml(id) def __check_sample_xml(self): return """ true """ def __transaction_disbursed_sample_xml(self, id): return """ %s 100 10 100 10 2013-07-09T18:23:29Z """ % id def __transaction_settled_sample_xml(self, id): return """ %s settled sale USD 100.00 ogaotkivejpfayqfeaimuktty us_bank_account 123456789 1234 checking Dan Schulman 0 """ % id def __transaction_settlement_declined_sample_xml(self, id): return """ %s settlement_declined sale USD 100.00 ogaotkivejpfayqfeaimuktty us_bank_account 123456789 1234 checking Dan Schulman 0 """ % id def __disbursement_exception_sample_xml(self, id): return """ %s afv56j kj8hjk false false merchant_account_token USD false active 100.00 2014-02-09 bank_rejected update_funding_information """ % id def __disbursement_sample_xml(self, id): return """ %s afv56j kj8hjk true false merchant_account_token USD false active 100.00 2014-02-09 """ % id def __dispute_opened_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_opened_sample_xml(id) else: return self.__new_dispute_opened_sample_xml(id) def __dispute_lost_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_lost_sample_xml(id) else: return self.__new_dispute_lost_sample_xml(id) def __dispute_won_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_won_sample_xml(id) else: return self.__new_dispute_won_sample_xml(id) def __old_dispute_opened_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback open fraud %s %s 250.00 2014-03-28 """ % (id, id) def __old_dispute_lost_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback lost fraud %s %s 250.00 2014-03-28 """ % (id, id) def __old_dispute_won_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback won fraud %s %s 250.00 2014-03-28 2014-09-01 """ % (id, id) def __new_dispute_opened_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 open 2017-06-16T20:44:41Z 9qde5qgp open 2017-06-16T20:44:41Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 """ % (id, id) def __new_dispute_lost_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 lost 2017-06-21T20:44:41Z 9qde5qgp open 2017-06-16T20:44:41Z lost 2017-06-25T20:50:55Z rxtngk9j5j93tsrq 2017-06-21T20:44:42Z s3.amazonaws.com/foo.jpg 88cfb8dd text evidence 2017-06-21T20:44:42Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 """ % (id, id) def __new_dispute_won_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 won 2017-06-21T20:44:41Z 9qde5qgp open 2017-06-16T20:44:41Z won 2017-06-25T20:50:55Z rxtngk9j5j93tsrq 2017-06-21T20:44:42Z s3.amazonaws.com/foo.jpg 88cfb8dd text evidence 2017-06-21T20:44:42Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 2014-09-01 """ % (id, id) def __subscription_sample_xml(self, id): return """ %s """ % id def __subscription_charged_successfully_sample_xml(self, id): return """ %s %s submitted_for_settlement 49.99 """ % (id, id) def __subscription_charged_unsuccessfully_sample_xml(self, id): return """ %s %s failed 49.99 """ % (id, id) def __merchant_account_approved_sample_xml(self, id): return """ %s active master_ma_for_%s active """ % (id, id) def __merchant_account_declined_sample_xml(self, id): return """ Credit score is too low 82621 Credit score is too low base %s suspended master_ma_for_%s suspended """ % (id, id) def __partner_merchant_connected_sample_xml(self): return """ abc123 public_key private_key public_id cse_key """ def __partner_merchant_disconnected_sample_xml(self): return """ abc123 """ def __connected_merchant_status_transitioned_xml(self, id): return """ new_status %s oauth_application_client_id """ % id def __connected_merchant_paypal_status_changed_xml(self, id): return """ link %s oauth_application_client_id """ % id def __partner_merchant_declined_sample_xml(self): return """ abc123 """ def __oauth_access_revocation_sample_xml(self, id): return """ %s oauth_application_client_id """ % id def __account_updater_daily_report_sample_xml(self): return """ 2016-01-14 link-to-csv-report """ # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. def __ideal_payment_complete_sample_xml(self, id): return """ %s COMPLETE ABCISSUER ORDERABC EUR 10.00 2016-11-29T23:27:34.547Z https://example.com 1234567890 """ % id # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. def __ideal_payment_failed_sample_xml(self, id): return """ %s FAILED ABCISSUER ORDERABC EUR 10.00 2016-11-29T23:27:34.547Z https://example.com 1234567890 """ % id def __granted_payment_instrument_update(self): return """ vczo7jqrpwrsi2px cf0i8wgarszuy6hc ee257d98-de40-47e8-96b3-a6954ea7a9a4 false false abc123z expiration-month expiration-year """ def __payment_method_revoked_by_customer(self, id): return """ a-billing-agreement-id 2019-01-01T12:00:00Z a-customer-id true name@email.com cGF5bWVudG1ldGhvZF9jaDZieXNz https://assets.braintreegateway.com/payment_method_logo/paypal.png?environment=test %s 2019-01-02T12:00:00Z a-payer-id 2019-01-02T12:00:00Z """ % id def __local_payment_completed(self): return """ a-payment-id a-payer-id ee257d98-de40-47e8-96b3-a6954ea7a9a4 1 authorizing 10.00 order1234 """ braintree_python-3.57.1/braintree/status_event.py0000644000175000017500000000036013545202423020335 0ustar hlehlefrom decimal import Decimal from braintree.resource import Resource class StatusEvent(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.amount = Decimal(self.amount) braintree_python-3.57.1/braintree/paginated_result.py0000644000175000017500000000044513545202423021147 0ustar hlehleclass PaginatedResult(object): """ An instance of this class is returned from paginated operations """ def __init__(self, total_items, page_size, current_page): self.total_items = total_items self.page_size = page_size self.current_page = current_page braintree_python-3.57.1/braintree/payment_instrument_type.py0000644000175000017500000000111013545202423022611 0ustar hlehle class PaymentInstrumentType(): PayPalAccount = "paypal_account" PayPalHere = "paypal_here" EuropeBankAccount = "europe_bank_account" CreditCard = "credit_card" CoinbaseAccount = "coinbase_account" ApplePayCard = "apple_pay_card" AndroidPayCard = "android_pay_card" AmexExpressCheckoutCard = "amex_express_checkout_card" VenmoAccount = "venmo_account" UsBankAccount = "us_bank_account" VisaCheckoutCard = "visa_checkout_card" MasterpassCard = "masterpass_card" SamsungPayCard = "samsung_pay_card" LocalPayment = "local_payment" braintree_python-3.57.1/braintree/payment_method_parser.py0000644000175000017500000000441513545202423022207 0ustar hlehleimport braintree from braintree.apple_pay_card import ApplePayCard from braintree.credit_card import CreditCard from braintree.payment_method import PaymentMethod from braintree.paypal_account import PayPalAccount from braintree.europe_bank_account import EuropeBankAccount from braintree.coinbase_account import CoinbaseAccount from braintree.android_pay_card import AndroidPayCard from braintree.amex_express_checkout_card import AmexExpressCheckoutCard from braintree.venmo_account import VenmoAccount from braintree.us_bank_account import UsBankAccount from braintree.visa_checkout_card import VisaCheckoutCard from braintree.masterpass_card import MasterpassCard from braintree.samsung_pay_card import SamsungPayCard from braintree.unknown_payment_method import UnknownPaymentMethod def parse_payment_method(gateway, attributes): if "paypal_account" in attributes: return PayPalAccount(gateway, attributes["paypal_account"]) elif "credit_card" in attributes: return CreditCard(gateway, attributes["credit_card"]) elif "europe_bank_account" in attributes: return EuropeBankAccount(gateway, attributes["europe_bank_account"]) elif "apple_pay_card" in attributes: return ApplePayCard(gateway, attributes["apple_pay_card"]) elif "android_pay_card" in attributes: return AndroidPayCard(gateway, attributes["android_pay_card"]) elif "amex_express_checkout_card" in attributes: return AmexExpressCheckoutCard(gateway, attributes["amex_express_checkout_card"]) elif "coinbase_account" in attributes: return CoinbaseAccount(gateway, attributes["coinbase_account"]) elif "venmo_account" in attributes: return VenmoAccount(gateway, attributes["venmo_account"]) elif "us_bank_account" in attributes: return UsBankAccount(gateway, attributes["us_bank_account"]) elif "visa_checkout_card" in attributes: return VisaCheckoutCard(gateway, attributes["visa_checkout_card"]) elif "masterpass_card" in attributes: return MasterpassCard(gateway, attributes["masterpass_card"]) elif "samsung_pay_card" in attributes: return SamsungPayCard(gateway, attributes["samsung_pay_card"]) else: name = list(attributes)[0] return UnknownPaymentMethod(gateway, attributes[name]) braintree_python-3.57.1/braintree/transaction_line_item.py0000644000175000017500000000216613545202423022171 0ustar hlehleimport braintree import warnings from braintree.attribute_getter import AttributeGetter from braintree.resource import Resource from braintree.configuration import Configuration class TransactionLineItem(AttributeGetter): pass class Kind(object): """ Constants representing transaction line item kinds. Available kinds are: * braintree.TransactionLineItem.Kind.Credit * braintree.TransactionLineItem.Kind.Debit """ Credit = "credit" Debit = "debit" def __init__(self, attributes): AttributeGetter.__init__(self, attributes) @staticmethod def find_all(transaction_id): """ Find all line items on a transaction, given a transaction_id. This returns an array of TransactionLineItems. This will raise a :class:`NotFoundError ` if the provided transaction_id is not found. :: transaction_line_items = braintree.TransactionLineItem.find_all("my_transaction_id") """ return Configuration.gateway().transaction_line_item.find_all(transaction_id) braintree_python-3.57.1/braintree/version.py0000644000175000017500000000002313545202423017272 0ustar hlehleVersion = "3.57.1" braintree_python-3.57.1/braintree/payment_method_nonce_gateway.py0000644000175000017500000000337313545202423023540 0ustar hlehleimport braintree from braintree.payment_method_nonce import PaymentMethodNonce from braintree.error_result import ErrorResult from braintree.exceptions.not_found_error import NotFoundError from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult class PaymentMethodNonceGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create(self, payment_method_token): try: response = self.config.http().post(self.config.base_merchant_path() + "/payment_methods/" + payment_method_token + "/nonces") if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: payment_method_nonce = self._parse_payment_method_nonce(response) return SuccessfulResult({"payment_method_nonce": payment_method_nonce}) except NotFoundError: raise NotFoundError("payment method with token " + repr(payment_method_token) + " not found") def find(self, payment_method_nonce): try: if payment_method_nonce is None or payment_method_nonce.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_method_nonces/" + payment_method_nonce) return self._parse_payment_method_nonce(response) except NotFoundError: raise NotFoundError("payment method nonce with id " + repr(payment_method_nonce) + " not found") def _parse_payment_method_nonce(self, response): return PaymentMethodNonce(self.gateway, response["payment_method_nonce"]) braintree_python-3.57.1/braintree/disbursement_detail.py0000644000175000017500000000111013545202423021631 0ustar hlehlefrom decimal import Decimal from braintree.attribute_getter import AttributeGetter class DisbursementDetail(AttributeGetter): def __init__(self, attributes): AttributeGetter.__init__(self, attributes) if self.settlement_amount is not None: self.settlement_amount = Decimal(self.settlement_amount) if self.settlement_currency_exchange_rate is not None: self.settlement_currency_exchange_rate = Decimal(self.settlement_currency_exchange_rate) @property def is_valid(self): return self.disbursement_date is not None braintree_python-3.57.1/braintree/subscription_status_event.py0000644000175000017500000000044713545202423023147 0ustar hlehlefrom decimal import Decimal from braintree.resource import Resource class SubscriptionStatusEvent(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.balance = Decimal(self.balance) self.price = Decimal(self.price) braintree_python-3.57.1/braintree/visa_checkout_card.py0000644000175000017500000000232113545202423021430 0ustar hlehleimport braintree from braintree.address import Address from braintree.resource import Resource from braintree.credit_card_verification import CreditCardVerification class VisaCheckoutCard(Resource): """ A class representing Visa Checkout card """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "billing_address" in attributes: self.billing_address = Address(gateway, self.billing_address) else: self.billing_address = None if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] if "verifications" in attributes: sorted_verifications = sorted(attributes["verifications"], key=lambda verification: verification["created_at"], reverse=True) if len(sorted_verifications) > 0: self.verification = CreditCardVerification(gateway, sorted_verifications[0]) @property def expiration_date(self): return self.expiration_month + "/" + self.expiration_year @property def masked_number(self): return self.bin + "******" + self.last_4 braintree_python-3.57.1/braintree/authorization_adjustment.py0000644000175000017500000000051213545202423022746 0ustar hlehlefrom decimal import Decimal from braintree.attribute_getter import AttributeGetter class AuthorizationAdjustment(AttributeGetter): def __init__(self, attributes): AttributeGetter.__init__(self, attributes) if hasattr(self, 'amount') and self.amount is not None: self.amount = Decimal(self.amount) braintree_python-3.57.1/braintree/search.py0000644000175000017500000001004413545202423017056 0ustar hlehleclass Search: """ Collection of classes used to build search queries. Each Builder class defines one or more methods that returns a Node object with the name of the field, the comparator, and the value. """ class IsNodeBuilder(object): """Builds a query for value equality.""" def __init__(self, name): self.name = name def __eq__(self, value): return self.is_equal(value) def is_equal(self, value): return Search.Node(self.name, {"is": value}) class EqualityNodeBuilder(IsNodeBuilder): """Builds a query for value inequality.""" def __ne__(self, value): return self.is_not_equal(value) def is_not_equal(self, value): return Search.Node(self.name, {"is_not": value}) class KeyValueNodeBuilder(object): """Builds a query based on a key-value map.""" def __init__(self, name): self.name = name def __eq__(self, value): return self.is_equal(value) def is_equal(self, value): return Search.Node(self.name, value) def __ne__(self, value): return self.is_not_equal(value) def is_not_equal(self, value): return Search.Node(self.name, not value) class PartialMatchNodeBuilder(EqualityNodeBuilder): """Builds a query for matching parts of a sequence.""" def starts_with(self, value): return Search.Node(self.name, {"starts_with": value}) def ends_with(self, value): return Search.Node(self.name, {"ends_with": value}) class EndsWithNodeBuilder(object): def __init__(self, name): self.name = name def ends_with(self, value): return Search.Node(self.name, {"ends_with": value}) class TextNodeBuilder(PartialMatchNodeBuilder): """Builds a query for matching any part of a sequence.""" def contains(self, value): return Search.Node(self.name, {"contains": value}) class Node(object): """Container for part of a search query.""" def __init__(self, name, dict): self.name = name self.dict = dict def to_param(self): return self.dict class MultipleValueNodeBuilder(object): """Builds a query to check membership in a sequence.""" def __init__(self, name, whitelist = []): self.name = name self.whitelist = whitelist def in_list(self, *values): if isinstance(values[0], list): values = values[0] invalid_args = set(values) - set(self.whitelist) if len(self.whitelist) > 0 and len(invalid_args) > 0: error_string = "Invalid argument(s) for %s: %s" % (self.name, ", ".join(invalid_args)) raise AttributeError(error_string) return Search.Node(self.name, list(values)) def __eq__(self, value): return self.in_list([value]) class MultipleValueOrTextNodeBuilder(TextNodeBuilder, MultipleValueNodeBuilder): """Builder node supporting contains and in_list.""" def __init__(self, name, whitelist = []): Search.MultipleValueNodeBuilder.__init__(self, name, whitelist) class RangeNodeBuilder(object): """Builds a query supporting <=, >=, or == value.""" def __init__(self, name): self.name = name def __eq__(self, value): return self.is_equal(value) def is_equal(self, value): return Search.EqualityNodeBuilder(self.name) == value def __ge__(self, min): return self.greater_than_or_equal_to(min) def greater_than_or_equal_to(self, min): return Search.Node(self.name, {"min": min}) def __le__(self, max): return self.less_than_or_equal_to(max) def less_than_or_equal_to(self, max): return Search.Node(self.name, {"max": max}) def between(self, min, max): return Search.Node(self.name, {"min": min, "max": max}) braintree_python-3.57.1/braintree/errors.py0000644000175000017500000000071213545202423017126 0ustar hlehlefrom braintree.validation_error_collection import ValidationErrorCollection class Errors(object): def __init__(self, data): data["errors"] = [] self.errors = ValidationErrorCollection(data) self.size = self.errors.deep_size @property def deep_errors(self): return self.errors.deep_errors def for_object(self, key): return self.errors.for_object(key) def __len__(self): return self.size braintree_python-3.57.1/braintree/ssl/0000755000175000017500000000000013545202423016041 5ustar hlehlebraintree_python-3.57.1/braintree/ssl/api_braintreegateway_com.ca.crt0000644000175000017500000003447113545202423024172 0ustar hlehle-----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO 0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj 7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS 8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ 3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH /PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu 9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo 2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI 4uJEvlz36hz1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB /wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG 9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU 1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV 5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF 9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN /BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz 4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 7M2CYfE45k+XmCpajQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI 2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx 1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV 5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY 1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- braintree_python-3.57.1/braintree/address_gateway.py0000644000175000017500000000467713545202423020776 0ustar hlehleimport re import braintree from braintree.address import Address from braintree.error_result import ErrorResult from braintree.exceptions.not_found_error import NotFoundError from braintree.resource import Resource from braintree.successful_result import SuccessfulResult class AddressGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create(self, params={}): Resource.verify_keys(params, Address.create_signature()) if not "customer_id" in params: raise KeyError("customer_id must be provided") if not re.search("\A[0-9A-Za-z_-]+\Z", params["customer_id"]): raise KeyError("customer_id contains invalid characters") response = self.config.http().post(self.config.base_merchant_path() + "/customers/" + params.pop("customer_id") + "/addresses", {"address": params}) if "address" in response: return SuccessfulResult({"address": Address(self.gateway, response["address"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def delete(self, customer_id, address_id): self.config.http().delete(self.config.base_merchant_path() + "/customers/" + customer_id + "/addresses/" + address_id) return SuccessfulResult() def find(self, customer_id, address_id): try: if customer_id is None or customer_id.strip() == "" or address_id is None or address_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/customers/" + customer_id + "/addresses/" + address_id) return Address(self.gateway, response["address"]) except NotFoundError: raise NotFoundError("address for customer " + repr(customer_id) + " with id " + repr(address_id) + " not found") def update(self, customer_id, address_id, params={}): Resource.verify_keys(params, Address.update_signature()) response = self.config.http().put( self.config.base_merchant_path() + "/customers/" + customer_id + "/addresses/" + address_id, {"address": params} ) if "address" in response: return SuccessfulResult({"address": Address(self.gateway, response["address"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) braintree_python-3.57.1/braintree/merchant_account/0000755000175000017500000000000013545202423020555 5ustar hlehlebraintree_python-3.57.1/braintree/merchant_account/funding_details.py0000644000175000017500000000065313545202423024272 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class FundingDetails(AttributeGetter): detail_list = [ "account_number_last_4", "routing_number", "destination", "email", "mobile_phone", ] def __init__(self, attributes): AttributeGetter.__init__(self, attributes) def __repr__(self): return super(FundingDetails, self).__repr__(self.detail_list) braintree_python-3.57.1/braintree/merchant_account/business_details.py0000644000175000017500000000103413545202423024465 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter from braintree.merchant_account.address_details import AddressDetails class BusinessDetails(AttributeGetter): detail_list = [ "dba_name", "legal_name", "tax_id", "address_details", ] def __init__(self, attributes): AttributeGetter.__init__(self, attributes) self.address_details = AddressDetails(attributes.get("address", {})) def __repr__(self): return super(BusinessDetails, self).__repr__(self.detail_list) braintree_python-3.57.1/braintree/merchant_account/address_details.py0000644000175000017500000000060713545202423024264 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter class AddressDetails(AttributeGetter): detail_list = [ "street_address", "locality", "region", "postal_code", ] def __init__(self, attributes): AttributeGetter.__init__(self, attributes) def __repr__(self): return super(AddressDetails, self).__repr__(self.detail_list) braintree_python-3.57.1/braintree/merchant_account/individual_details.py0000644000175000017500000000114013545202423024760 0ustar hlehlefrom braintree.attribute_getter import AttributeGetter from braintree.merchant_account.address_details import AddressDetails class IndividualDetails(AttributeGetter): detail_list = [ "first_name", "last_name", "email", "phone", "date_of_birth", "ssn_last_4", "address_details", ] def __init__(self, attributes): AttributeGetter.__init__(self, attributes) self.address_details = AddressDetails(attributes.get("address", {})) def __repr__(self): return super(IndividualDetails, self).__repr__(self.detail_list) braintree_python-3.57.1/braintree/merchant_account/merchant_account.py0000644000175000017500000000325113545202423024445 0ustar hlehlefrom braintree.configuration import Configuration from braintree.resource import Resource from braintree.merchant_account import BusinessDetails, FundingDetails, IndividualDetails class MerchantAccount(Resource): class Status(object): Active = "active" Pending = "pending" Suspended = "suspended" class FundingDestination(object): Bank = "bank" Email = "email" MobilePhone = "mobile_phone" FundingDestinations = FundingDestination def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.individual_details = IndividualDetails(attributes.get("individual", {})) self.business_details = BusinessDetails(attributes.get("business", {})) self.funding_details = FundingDetails(attributes.get("funding", {})) if "master_merchant_account" in attributes: self.master_merchant_account = MerchantAccount(gateway, attributes.pop("master_merchant_account")) def __repr__(self): detail_list = [ "id", "business_details", "currency_iso_code", "default", "funding_details", "individual_details", "master_merchant_account", "status", ] return super(MerchantAccount, self).__repr__(detail_list) @staticmethod def create(params={}): return Configuration.gateway().merchant_account.create(params) @staticmethod def update(id, attributes): return Configuration.gateway().merchant_account.update(id, attributes) @staticmethod def find(id): return Configuration.gateway().merchant_account.find(id) braintree_python-3.57.1/braintree/merchant_account/__init__.py0000644000175000017500000000044213545202423022666 0ustar hlehlefrom braintree.merchant_account.business_details import BusinessDetails from braintree.merchant_account.funding_details import FundingDetails from braintree.merchant_account.individual_details import IndividualDetails from braintree.merchant_account.merchant_account import MerchantAccount braintree_python-3.57.1/braintree/coinbase_account.py0000644000175000017500000000055413545202423021115 0ustar hlehleimport braintree from braintree.resource import Resource class CoinbaseAccount(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] braintree_python-3.57.1/braintree/payment_method.py0000644000175000017500000000700313545202423020627 0ustar hlehleimport braintree from braintree.address import Address from braintree.resource import Resource from braintree.configuration import Configuration class PaymentMethod(Resource): @staticmethod def create(params={}): return Configuration.gateway().payment_method.create(params) @staticmethod def find(payment_method_token): return Configuration.gateway().payment_method.find(payment_method_token) @staticmethod def update(payment_method_token, params): return Configuration.gateway().payment_method.update(payment_method_token, params) @staticmethod def delete(payment_method_token, options={}): return Configuration.gateway().payment_method.delete(payment_method_token, options) @staticmethod def create_signature(): return PaymentMethod.signature("create") @staticmethod def signature(type): options = [ "fail_on_duplicate_payment_method", "make_default", "us_bank_account_verification_method", "verification_merchant_account_id", "verify_card", "verification_amount", "verification_account_type", { "adyen": [ "overwrite_brand", "selected_brand" ] }, { "paypal": [ "payee_email", "order_id", "custom_field", "description", "amount", { "shipping": Address.create_signature() } ], }, ] signature = [ "billing_address_id", "cardholder_name", "customer_id", "cvv", "device_data", "device_session_id", "expiration_date", "expiration_month", "expiration_year", "number", "payment_method_nonce", "paypal_refresh_token", "paypal_vault_without_upgrade", "token", { "billing_address": Address.create_signature() }, { "options": options } ] return signature @staticmethod def update_signature(): signature = [ "billing_address_id", "cardholder_name", "cvv", "device_session_id", "expiration_date", "expiration_month", "expiration_year", "number", "token", "venmo_sdk_payment_method_code", "device_data", "fraud_merchant_id", "payment_method_nonce", { "options": [ "make_default", "us_bank_account_verification_method", "verify_card", "verification_amount", "verification_merchant_account_id", "verification_account_type", "venmo_sdk_session", { "adyen": [ "overwrite_brand", "selected_brand" ] } ] }, { "billing_address": Address.update_signature() + [{"options": ["update_existing"]}] } ] return signature @staticmethod def delete_signature(): return ["revoke_all_grants"] braintree_python-3.57.1/braintree/subscription.py0000644000175000017500000002200613545202423020336 0ustar hlehlefrom decimal import Decimal from braintree.util.http import Http import braintree import warnings from braintree.add_on import AddOn from braintree.descriptor import Descriptor from braintree.discount import Discount from braintree.exceptions.not_found_error import NotFoundError from braintree.resource_collection import ResourceCollection from braintree.subscription_status_event import SubscriptionStatusEvent from braintree.successful_result import SuccessfulResult from braintree.error_result import ErrorResult from braintree.transaction import Transaction from braintree.resource import Resource from braintree.configuration import Configuration class Subscription(Resource): """ A class representing a Subscription. An example of creating a subscription with all available fields:: result = braintree.Subscription.create({ "id": "my_subscription_id", "merchant_account_id": "merchant_account_one", "payment_method_token": "my_payment_token", "plan_id": "some_plan_id", "price": "29.95", "trial_duration": 1, "trial_duration_unit": braintree.Subscription.TrialDurationUnit.Month, "trial_period": True }) For more information on Subscriptions, see https://developers.braintreepayments.com/reference/request/subscription/create/python """ class TrialDurationUnit(object): """ Constants representing trial duration units. Available types are: * braintree.Subscription.TrialDurationUnit.Day * braintree.Subscription.TrialDurationUnit.Month """ Day = "day" Month = "month" class Source(object): Api = "api" ControlPanel = "control_panel" Recurring = "recurring" Unrecognized = "unrecognized" class Status(object): """ Constants representing subscription statusues. Available statuses are: * braintree.Subscription.Status.Active * braintree.Subscription.Status.Canceled * braintree.Subscription.Status.Expired * braintree.Subscription.Status.PastDue * braintree.Subscription.Status.Pending """ Active = "Active" Canceled = "Canceled" Expired = "Expired" PastDue = "Past Due" Pending = "Pending" @staticmethod def create(params={}): """ Create a Subscription Token and Plan are required::: result = braintree.Subscription.create({ "payment_method_token": "my_payment_token", "plan_id": "some_plan_id", }) """ return Configuration.gateway().subscription.create(params) @staticmethod def create_signature(): return [ "billing_day_of_month", "first_billing_date", "id", "merchant_account_id", "never_expires", "number_of_billing_cycles", "payment_method_nonce", "payment_method_token", "plan_id", "price", "trial_duration", "trial_duration_unit", "trial_period", { "descriptor": [ "name", "phone", "url" ] }, { "options": [ "do_not_inherit_add_ons_or_discounts", "start_immediately", { "paypal": [ "description" ] } ] } ] + Subscription._add_ons_discounts_signature() @staticmethod def find(subscription_id): """ Find a subscription given a subscription_id. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided subscription_id is not found. :: subscription = braintree.Subscription.find("my_subscription_id") """ return Configuration.gateway().subscription.find(subscription_id) @staticmethod def retryCharge(subscription_id, amount=None): warnings.warn("Please use Subscription.retry_charge instead", DeprecationWarning) return Subscription.retry_charge(subscription_id, amount) @staticmethod def retry_charge(subscription_id, amount=None, submit_for_settlement=False): return Configuration.gateway().subscription.retry_charge(subscription_id, amount, submit_for_settlement) @staticmethod def update(subscription_id, params={}): """ Update an existing subscription By subscription_id. The params are similar to create:: result = braintree.Subscription.update("my_subscription_id", { "price": "9.99", }) """ return Configuration.gateway().subscription.update(subscription_id, params) @staticmethod def cancel(subscription_id): """ Cancel a subscription By subscription_id:: result = braintree.Subscription.cancel("my_subscription_id") """ return Configuration.gateway().subscription.cancel(subscription_id) @staticmethod def search(*query): """ Allows searching on subscriptions. There are two types of fields that are searchable: text and multiple value fields. Searchable text fields are: - plan_id - days_past_due Searchable multiple value fields are: - status For text fields, you can search using the following operators: ==, !=, starts_with, ends_with and contains. For mutiple value fields, you can search using the in_list operator. An example:: braintree.Subscription.search([ braintree.SubscriptionSearch.plan_id.starts_with("abc"), braintree.SubscriptionSearch.days_past_due == "30", braintree.SubscriptionSearch.status.in_list([braintree.Subscription.Status.PastDue]) ]) """ return Configuration.gateway().subscription.search(*query) @staticmethod def update_signature(): return [ "id", "merchant_account_id", "never_expires", "number_of_billing_cycles", "payment_method_nonce", "payment_method_token", "plan_id", "price", { "descriptor": [ "name", "phone", "url" ] }, { "options": [ "prorate_charges", "replace_all_add_ons_and_discounts", "revert_subscription_on_proration_failure", { "paypal": [ "description" ] } ] } ] + Subscription._add_ons_discounts_signature() @staticmethod def _add_ons_discounts_signature(): return [ { "add_ons": [{ "add": ["amount", "inherited_from_id", "never_expires", "number_of_billing_cycles", "quantity"], "remove": ["__any_key__"], "update": ["amount", "existing_id", "never_expires", "number_of_billing_cycles", "quantity"] }], "discounts": [{ "add": ["amount", "inherited_from_id", "never_expires", "number_of_billing_cycles", "quantity"], "remove": ["__any_key__"], "update": ["amount", "existing_id", "never_expires", "number_of_billing_cycles", "quantity"] }] } ] def __init__(self, gateway, attributes): if "next_bill_amount" in attributes: self._next_bill_amount = Decimal(attributes["next_bill_amount"]) del(attributes["next_bill_amount"]) Resource.__init__(self, gateway, attributes) if "price" in attributes: self.price = Decimal(self.price) if "balance" in attributes: self.balance = Decimal(self.balance) if "next_billing_period_amount" in attributes: self.next_billing_period_amount = Decimal(self.next_billing_period_amount) if "add_ons" in attributes: self.add_ons = [AddOn(gateway, add_on) for add_on in self.add_ons] if "descriptor" in attributes: self.descriptor = Descriptor(gateway, attributes.pop("descriptor")) if "description" in attributes: self.description = attributes["description"] if "discounts" in attributes: self.discounts = [Discount(gateway, discount) for discount in self.discounts] if "status_history" in attributes: self.status_history = [SubscriptionStatusEvent(gateway, status_event) for status_event in self.status_history] if "transactions" in attributes: self.transactions = [Transaction(gateway, transaction) for transaction in self.transactions] @property def next_bill_amount(self): warnings.warn("Please use Subscription.next_billing_period_amount instead", DeprecationWarning) return self._next_bill_amount braintree_python-3.57.1/braintree/error_result.py0000644000175000017500000000466213545202423020351 0ustar hlehleimport braintree from braintree.errors import Errors from braintree.credit_card_verification import CreditCardVerification class ErrorResult(object): """ An instance of this class is returned from most operations when there is a validation error. Call :func:`errors` to get the collection of errors:: error_result = Transaction.sale({}) assert(error_result.is_success == False) assert(error_result.errors.for_object("transaction").on("amount")[0].code == ErrorCodes.Transaction.AmountIsRequired) Errors can be nested at different levels. For example, creating a transaction with a credit card can have errors at the transaction level as well as the credit card level. :func:`for_object` returns the :class:`ValidationErrorCollection ` for the errors at that level. For example:: error_result = Transaction.sale({"credit_card": {"number": "invalid"}}) assert(error_result.errors.for_object("transaction").for_object("credit_card").on("number")[0].code == ErrorCodes.CreditCard.NumberHasInvalidLength) """ def __init__(self, gateway, attributes): if "params" in attributes: self.params = attributes["params"] else: self.params = None self.errors = Errors(attributes["errors"]) self.message = attributes["message"] if "verification" in attributes: self.credit_card_verification = CreditCardVerification(gateway, attributes["verification"]) else: self.credit_card_verification = None if "transaction" in attributes: self.transaction = braintree.transaction.Transaction(gateway, attributes["transaction"]) else: self.transaction = None if "subscription" in attributes: self.subscription = braintree.subscription.Subscription(gateway, attributes["subscription"]) else: self.subscription = None if "merchant_account" in attributes: self.merchant_account = braintree.merchant_account.MerchantAccount(gateway, attributes["merchant_account"]) else: self.merchant_account = None def __repr__(self): return "<%s '%s' at %x>" % (self.__class__.__name__, self.message, id(self)) @property def is_success(self): """ Returns whether the result from the gateway is a successful response. """ return False braintree_python-3.57.1/tests/0000755000175000017500000000000013545202423014427 5ustar hlehlebraintree_python-3.57.1/tests/fixtures/0000755000175000017500000000000013545202423016300 5ustar hlehlebraintree_python-3.57.1/tests/fixtures/bt_logo.png0000644000175000017500000000461313545202423020437 0ustar hlehle‰PNG  IHDRu ,G7øsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î< IDAThí›{°WUÇ?KyÉ› (ò  s CËÔñA0db¦å£$¨f´TC™b„|›SC# DÖÊR0)ˆ‚¢‚¼®€p/÷Ûký¼‡Ã9¿‹è½€ý¾3gÎïì½ÖÚk¿÷^kýŒc ’ç›Ìlò‘Öçh„Ij—‘Wl4³òÚU©8$ÝüXefÝj@~ 5Pnf>mùµIÛ• I«%Ý")«ãk’î Ý^­!ùýBþë5!¿6Pxhtö+#¯1Ðè LÚ7Õ¾Ša°%žò éòkSé %ý:òÊ%µ8R:Ö>+35f¶[Ò|†ÖN¶H M? ”áû]_À€%À]föFHR#à`p:¾:¬f3ÍLi=¢¬ RÉïšÙø,½%ΉÏ]ÀÀ`0ÐX< Ì(”'i"Ð89øZIšžý¶™Ý™(§05©0ø>p9¾7o5³ÇR:ÖF—ð3Ì«A;7§^LJÜ+ñÔ€ÕÀ¤Û.o¦FÞ¥‘·CÒ ‰ô_¤öß©’veìËïH:9x:IÚPd §22hs÷TI%èÊ$­Ê)ï7 žbzðrºcÒ:Iš—Ã;.Áw¢¤eEÊù­¼“e5•´ ÏÓ’êguêVIã™ –Ç32UHoIתªÁ*%m”tµ¤¶’ºFÞ>I£‚§Ž¤Y’^‘4DRIŸ—46ø%éìŒNê%é;ñÜtÅ:õ«’nKT¸"êÓKR;IÓ"}¿¤Ó‚gxÔçW‘·9¾“Ï%©rŽ‹ô‚N…:üNRŸ¨ÛÏ"mEЛ¤ç"m½¤‹äÛ\Óµ;ònK•5+Ò7IºBRcIBïm‘7%«Só0«PùŒükÐìÔ6•×FRãTZ=Iu3ä, 9cò:+è¾tEO¿’º$ô›Ê;^Ò–ÈœÊûØ{ª¤þ‰²&¥òLR— ÚrI3dŠü²BÛIê–VÏÐÈÛ'©uzOÝÜ¿ONâëþy’™Ù¿rêö¸™½™Lȹçµ®–Ôß¿Êð=îs‘ß(GþáBÀƒ)½öKZ´êgr*€ ©²ü;‘Ô?ÞeÀ]ÒAGˆÂ€oŒŸ žIðì~œÁc@eðHwêf63•6IÒ}Àð«M²±2'ý#HÌÄL9>ˆZ}ªãýøÀ̶f¤WÖ@Yo›Ù¶jhšÅ»pY5´mR< …§èé7Åx§v/B³ïäLÅ;ôAàV3Û ©%0‹üS›(tv½Ãà=”6XïÕÀAç‡v§xÞÃû ¢Ïžj­DÑà?ŒÏþ»ÉÍo…=÷þB‡šg®ìOïÆûTI“’Α4âÊ ïü/#Íl[ò¶ã³±©™í žùÀN|;¼)Í|C€SÌìC“4·&uÇGÆâ„-ðÆ®à‹Íìé¨à|üîÚ ßW%d»™´LȯL¿ã³v?p0_†ÞÖšÙÁ3 ¿›Ð_®?^H¤¯0³±Á37úŸe,f›ÙTIჴ/>˜–ïG§{I‹ƒ÷-`°è|·“ÃÌæÊo#¢zg´ßd3›ŸÑ〻ãóoÀ`+ÐïÐøêif»‚ç»ÀCÁ³xŸ¹§ߌvÜô¨Îö[ÀRI\þ%í-Bÿ^º"Ás®ªNI¬“´$ñ]žà¹ûô“¤çkçšÙÛ šø*—‡×Ìì¼LIMqKY7 ÞÞ/KÍlOCàë@Oü|²ø'°ØÌŠíµ%”PB %”PB %”P±èÝ+i¥¤¡Õsfʪ/igBÞI”Ô¼OW¹nBMMâ¨&«ôŠ÷#¸Å¦F(|t¢*Zâ^Üqµ‡¸ç䈄ĪAÿ¨„¤ssŒ]póà Ài¸]´r%p&:² ÑùnyÁÌI2à:Ü•µ1dÎ1³1’šß ymQx§ÿ7_.¦Ê¸ñZJßá¸×å 3;fã jòH—t°Ñ½Q,};$ýRÒ‹±lNVUôÀšXF+%½%©µ< â¹qsÐÝ¡ªй’¦È×Jº0~ï–´\UQ7Jš¿[&ôê*omºäìþ¿G4vI×§Ò{§l¢ïKz@ÒyñýHÐuŽïgâûy¹m÷+ÑQË$Õ•ôû„¬rùþò•±òë ¡ß­’ÆIºFò2VÒOå‘*×Kú¹¤Á ÏQ ´Çäž*©'î…ù20 •Ý5Þ÷›£¥™]‹Ç-¼ïÂwa‰œ/£•ÀUñï„‚¼öfV×ÌÎ0³9x4ß`­|¹.¸×àûðK/P×Ì’ŽùáÀ2àvà Ü 4 ÷–ÍĽDÍl"n¾%t|·û~ ²œ)·i÷5³mÇÜž 8ßtT7ñ÷B'¤Ãn–àûìyYïH/4þL` ¾?^gfkbfu¶šÙú”¼Åxc¯ÄÖñ•:x„BºS·É=] óqçÅÒÐwî+= x wÁ¼/7ú7ÀÝ›eÀÅA¿8?À­‹6Á2[î(†¤Ö@+3[ß}€uf¶%¾/Æ}¥S“•È\Š{C–ã3}š™½%™Z€Ÿ–/43Éû·ëÍlzJVCàf܃ôü„½˜‹О2³$è ø~ˆz6ÊÿÓàx<Òð­føLTü~?´ šu¸ï¶ ÷Ô´›ÙìÃjÔÏ"$µ˜6ÉO¨G’îTøm«¡k$D/! IÍ%/÷tê!Ò5—Ô,™ö?ÒQÿâc¶°pIEND®B`‚braintree_python-3.57.1/tests/fixtures/too_long.pdf0000644000175000017500000023224013545202423020616 0ustar hlehle%PDF-1.4 %Çì¢ 5 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 6 0 obj 30 endobj 10 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 11 0 obj 30 endobj 14 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 15 0 obj 30 endobj 18 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 19 0 obj 30 endobj 22 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 23 0 obj 30 endobj 26 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 27 0 obj 30 endobj 30 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 31 0 obj 30 endobj 34 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 35 0 obj 30 endobj 38 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 39 0 obj 30 endobj 42 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 43 0 obj 30 endobj 46 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 47 0 obj 30 endobj 50 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 51 0 obj 30 endobj 54 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 55 0 obj 30 endobj 58 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 59 0 obj 30 endobj 62 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 63 0 obj 30 endobj 66 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 67 0 obj 30 endobj 70 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 71 0 obj 30 endobj 74 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 75 0 obj 30 endobj 78 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 79 0 obj 30 endobj 82 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 83 0 obj 30 endobj 86 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 87 0 obj 30 endobj 90 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 91 0 obj 30 endobj 94 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 95 0 obj 30 endobj 98 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 99 0 obj 30 endobj 102 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 103 0 obj 30 endobj 106 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 107 0 obj 30 endobj 110 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 111 0 obj 30 endobj 114 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 115 0 obj 30 endobj 118 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 119 0 obj 30 endobj 122 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 123 0 obj 30 endobj 126 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 127 0 obj 30 endobj 130 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 131 0 obj 30 endobj 134 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 135 0 obj 30 endobj 138 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 139 0 obj 30 endobj 142 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 143 0 obj 30 endobj 146 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 147 0 obj 30 endobj 150 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 151 0 obj 30 endobj 154 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 155 0 obj 30 endobj 158 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 159 0 obj 30 endobj 162 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 163 0 obj 30 endobj 166 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 167 0 obj 30 endobj 170 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 171 0 obj 30 endobj 174 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 175 0 obj 30 endobj 178 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 179 0 obj 30 endobj 182 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 183 0 obj 30 endobj 186 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 187 0 obj 30 endobj 190 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 191 0 obj 30 endobj 194 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 195 0 obj 30 endobj 198 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 199 0 obj 30 endobj 202 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 203 0 obj 30 endobj 206 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 207 0 obj 30 endobj 210 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 211 0 obj 30 endobj 214 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 215 0 obj 30 endobj 218 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 219 0 obj 30 endobj 222 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 223 0 obj 30 endobj 226 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 227 0 obj 30 endobj 230 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 231 0 obj 30 endobj 234 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 235 0 obj 30 endobj 238 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 239 0 obj 30 endobj 242 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 243 0 obj 30 endobj 246 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 247 0 obj 30 endobj 250 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 251 0 obj 30 endobj 254 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 255 0 obj 30 endobj 258 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 259 0 obj 30 endobj 262 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 263 0 obj 30 endobj 266 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 267 0 obj 30 endobj 270 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 271 0 obj 30 endobj 274 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 275 0 obj 30 endobj 278 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 279 0 obj 30 endobj 282 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 283 0 obj 30 endobj 286 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 287 0 obj 30 endobj 290 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 291 0 obj 30 endobj 294 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 295 0 obj 30 endobj 298 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 299 0 obj 30 endobj 302 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 303 0 obj 30 endobj 306 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 307 0 obj 30 endobj 310 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 311 0 obj 30 endobj 314 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 315 0 obj 30 endobj 318 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 319 0 obj 30 endobj 322 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 323 0 obj 30 endobj 326 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 327 0 obj 30 endobj 330 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 331 0 obj 30 endobj 334 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 335 0 obj 30 endobj 338 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 339 0 obj 30 endobj 342 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 343 0 obj 30 endobj 346 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 347 0 obj 30 endobj 350 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 351 0 obj 30 endobj 354 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 355 0 obj 30 endobj 358 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 359 0 obj 30 endobj 362 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 363 0 obj 30 endobj 366 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 367 0 obj 30 endobj 370 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 371 0 obj 30 endobj 374 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 375 0 obj 30 endobj 378 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 379 0 obj 30 endobj 382 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 383 0 obj 30 endobj 386 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 387 0 obj 30 endobj 390 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 391 0 obj 30 endobj 394 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 395 0 obj 30 endobj 398 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 399 0 obj 30 endobj 402 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 403 0 obj 30 endobj 406 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 407 0 obj 30 endobj 410 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 411 0 obj 30 endobj 414 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 415 0 obj 30 endobj 418 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 419 0 obj 30 endobj 422 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 423 0 obj 30 endobj 426 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 427 0 obj 30 endobj 430 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 431 0 obj 30 endobj 434 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 435 0 obj 30 endobj 438 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 439 0 obj 30 endobj 442 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 443 0 obj 30 endobj 446 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 447 0 obj 30 endobj 450 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 451 0 obj 30 endobj 454 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 455 0 obj 30 endobj 458 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 459 0 obj 30 endobj 462 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 463 0 obj 30 endobj 466 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 467 0 obj 30 endobj 470 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 471 0 obj 30 endobj 474 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 475 0 obj 30 endobj 478 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 479 0 obj 30 endobj 482 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 483 0 obj 30 endobj 486 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 487 0 obj 30 endobj 490 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 491 0 obj 30 endobj 494 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 495 0 obj 30 endobj 498 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 499 0 obj 30 endobj 502 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 503 0 obj 30 endobj 506 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 507 0 obj 30 endobj 510 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 511 0 obj 30 endobj 514 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 515 0 obj 30 endobj 518 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 519 0 obj 30 endobj 522 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 523 0 obj 30 endobj 526 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 527 0 obj 30 endobj 530 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 531 0 obj 30 endobj 534 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 535 0 obj 30 endobj 538 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 539 0 obj 30 endobj 542 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 543 0 obj 30 endobj 546 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 547 0 obj 30 endobj 550 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 551 0 obj 30 endobj 554 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 555 0 obj 30 endobj 558 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 559 0 obj 30 endobj 562 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 563 0 obj 30 endobj 566 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 567 0 obj 30 endobj 570 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 571 0 obj 30 endobj 574 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 575 0 obj 30 endobj 578 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 579 0 obj 30 endobj 582 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 583 0 obj 30 endobj 586 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 587 0 obj 30 endobj 590 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 591 0 obj 30 endobj 594 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 595 0 obj 30 endobj 598 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 599 0 obj 30 endobj 602 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 603 0 obj 30 endobj 606 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 607 0 obj 30 endobj 610 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 611 0 obj 30 endobj 614 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 615 0 obj 30 endobj 618 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 619 0 obj 30 endobj 622 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 623 0 obj 30 endobj 626 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 627 0 obj 30 endobj 630 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 631 0 obj 30 endobj 634 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 635 0 obj 30 endobj 638 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 639 0 obj 30 endobj 642 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 643 0 obj 30 endobj 646 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 647 0 obj 30 endobj 650 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 651 0 obj 30 endobj 654 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 655 0 obj 30 endobj 658 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 659 0 obj 30 endobj 662 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 663 0 obj 30 endobj 666 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 667 0 obj 30 endobj 670 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 671 0 obj 30 endobj 674 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 675 0 obj 30 endobj 678 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 679 0 obj 30 endobj 682 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 683 0 obj 30 endobj 686 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 687 0 obj 30 endobj 690 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 691 0 obj 30 endobj 694 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 695 0 obj 30 endobj 698 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 699 0 obj 30 endobj 702 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 703 0 obj 30 endobj 706 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 707 0 obj 30 endobj 710 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 711 0 obj 30 endobj 714 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 715 0 obj 30 endobj 718 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 719 0 obj 30 endobj 722 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 723 0 obj 30 endobj 726 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 727 0 obj 30 endobj 730 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 731 0 obj 30 endobj 734 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 735 0 obj 30 endobj 738 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 739 0 obj 30 endobj 742 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 743 0 obj 30 endobj 746 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 747 0 obj 30 endobj 750 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 751 0 obj 30 endobj 754 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 755 0 obj 30 endobj 758 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 759 0 obj 30 endobj 762 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 763 0 obj 30 endobj 766 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 767 0 obj 30 endobj 770 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 771 0 obj 30 endobj 774 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 775 0 obj 30 endobj 778 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 779 0 obj 30 endobj 782 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 783 0 obj 30 endobj 786 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 787 0 obj 30 endobj 790 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 791 0 obj 30 endobj 794 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 795 0 obj 30 endobj 798 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 799 0 obj 30 endobj 802 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 803 0 obj 30 endobj 4 0 obj <> /Contents 5 0 R >> endobj 9 0 obj <> /Contents 10 0 R >> endobj 13 0 obj <> /Contents 14 0 R >> endobj 17 0 obj <> /Contents 18 0 R >> endobj 21 0 obj <> /Contents 22 0 R >> endobj 25 0 obj <> /Contents 26 0 R >> endobj 29 0 obj <> /Contents 30 0 R >> endobj 33 0 obj <> /Contents 34 0 R >> endobj 37 0 obj <> /Contents 38 0 R >> endobj 41 0 obj <> /Contents 42 0 R >> endobj 45 0 obj <> /Contents 46 0 R >> endobj 49 0 obj <> /Contents 50 0 R >> endobj 53 0 obj <> /Contents 54 0 R >> endobj 57 0 obj <> /Contents 58 0 R >> endobj 61 0 obj <> /Contents 62 0 R >> endobj 65 0 obj <> /Contents 66 0 R >> endobj 69 0 obj <> /Contents 70 0 R >> endobj 73 0 obj <> /Contents 74 0 R >> endobj 77 0 obj <> /Contents 78 0 R >> endobj 81 0 obj <> /Contents 82 0 R >> endobj 85 0 obj <> /Contents 86 0 R >> endobj 89 0 obj <> /Contents 90 0 R >> endobj 93 0 obj <> /Contents 94 0 R >> endobj 97 0 obj <> /Contents 98 0 R >> endobj 101 0 obj <> /Contents 102 0 R >> endobj 105 0 obj <> /Contents 106 0 R >> endobj 109 0 obj <> /Contents 110 0 R >> endobj 113 0 obj <> /Contents 114 0 R >> endobj 117 0 obj <> /Contents 118 0 R >> endobj 121 0 obj <> /Contents 122 0 R >> endobj 125 0 obj <> /Contents 126 0 R >> endobj 129 0 obj <> /Contents 130 0 R >> endobj 133 0 obj <> /Contents 134 0 R >> endobj 137 0 obj <> /Contents 138 0 R >> endobj 141 0 obj <> /Contents 142 0 R >> endobj 145 0 obj <> /Contents 146 0 R >> endobj 149 0 obj <> /Contents 150 0 R >> endobj 153 0 obj <> /Contents 154 0 R >> endobj 157 0 obj <> /Contents 158 0 R >> endobj 161 0 obj <> /Contents 162 0 R >> endobj 165 0 obj <> /Contents 166 0 R >> endobj 169 0 obj <> /Contents 170 0 R >> endobj 173 0 obj <> /Contents 174 0 R >> endobj 177 0 obj <> /Contents 178 0 R >> endobj 181 0 obj <> /Contents 182 0 R >> endobj 185 0 obj <> /Contents 186 0 R >> endobj 189 0 obj <> /Contents 190 0 R >> endobj 193 0 obj <> /Contents 194 0 R >> endobj 197 0 obj <> /Contents 198 0 R >> endobj 201 0 obj <> /Contents 202 0 R >> endobj 205 0 obj <> /Contents 206 0 R >> endobj 209 0 obj <> /Contents 210 0 R >> endobj 213 0 obj <> /Contents 214 0 R >> endobj 217 0 obj <> /Contents 218 0 R >> endobj 221 0 obj <> /Contents 222 0 R >> endobj 225 0 obj <> /Contents 226 0 R >> endobj 229 0 obj <> /Contents 230 0 R >> endobj 233 0 obj <> /Contents 234 0 R >> endobj 237 0 obj <> /Contents 238 0 R >> endobj 241 0 obj <> /Contents 242 0 R >> endobj 245 0 obj <> /Contents 246 0 R >> endobj 249 0 obj <> /Contents 250 0 R >> endobj 253 0 obj <> /Contents 254 0 R >> endobj 257 0 obj <> /Contents 258 0 R >> endobj 261 0 obj <> /Contents 262 0 R >> endobj 265 0 obj <> /Contents 266 0 R >> endobj 269 0 obj <> /Contents 270 0 R >> endobj 273 0 obj <> /Contents 274 0 R >> endobj 277 0 obj <> /Contents 278 0 R >> endobj 281 0 obj <> /Contents 282 0 R >> endobj 285 0 obj <> /Contents 286 0 R >> endobj 289 0 obj <> /Contents 290 0 R >> endobj 293 0 obj <> /Contents 294 0 R >> endobj 297 0 obj <> /Contents 298 0 R >> endobj 301 0 obj <> /Contents 302 0 R >> endobj 305 0 obj <> /Contents 306 0 R >> endobj 309 0 obj <> /Contents 310 0 R >> endobj 313 0 obj <> /Contents 314 0 R >> endobj 317 0 obj <> /Contents 318 0 R >> endobj 321 0 obj <> /Contents 322 0 R >> endobj 325 0 obj <> /Contents 326 0 R >> endobj 329 0 obj <> /Contents 330 0 R >> endobj 333 0 obj <> /Contents 334 0 R >> endobj 337 0 obj <> /Contents 338 0 R >> endobj 341 0 obj <> /Contents 342 0 R >> endobj 345 0 obj <> /Contents 346 0 R >> endobj 349 0 obj <> /Contents 350 0 R >> endobj 353 0 obj <> /Contents 354 0 R >> endobj 357 0 obj <> /Contents 358 0 R >> endobj 361 0 obj <> /Contents 362 0 R >> endobj 365 0 obj <> /Contents 366 0 R >> endobj 369 0 obj <> /Contents 370 0 R >> endobj 373 0 obj <> /Contents 374 0 R >> endobj 377 0 obj <> /Contents 378 0 R >> endobj 381 0 obj <> /Contents 382 0 R >> endobj 385 0 obj <> /Contents 386 0 R >> endobj 389 0 obj <> /Contents 390 0 R >> endobj 393 0 obj <> /Contents 394 0 R >> endobj 397 0 obj <> /Contents 398 0 R >> endobj 401 0 obj <> /Contents 402 0 R >> endobj 405 0 obj <> /Contents 406 0 R >> endobj 409 0 obj <> /Contents 410 0 R >> endobj 413 0 obj <> /Contents 414 0 R >> endobj 417 0 obj <> /Contents 418 0 R >> endobj 421 0 obj <> /Contents 422 0 R >> endobj 425 0 obj <> /Contents 426 0 R >> endobj 429 0 obj <> /Contents 430 0 R >> endobj 433 0 obj <> /Contents 434 0 R >> endobj 437 0 obj <> /Contents 438 0 R >> endobj 441 0 obj <> /Contents 442 0 R >> endobj 445 0 obj <> /Contents 446 0 R >> endobj 449 0 obj <> /Contents 450 0 R >> endobj 453 0 obj <> /Contents 454 0 R >> endobj 457 0 obj <> /Contents 458 0 R >> endobj 461 0 obj <> /Contents 462 0 R >> endobj 465 0 obj <> /Contents 466 0 R >> endobj 469 0 obj <> /Contents 470 0 R >> endobj 473 0 obj <> /Contents 474 0 R >> endobj 477 0 obj <> /Contents 478 0 R >> endobj 481 0 obj <> /Contents 482 0 R >> endobj 485 0 obj <> /Contents 486 0 R >> endobj 489 0 obj <> /Contents 490 0 R >> endobj 493 0 obj <> /Contents 494 0 R >> endobj 497 0 obj <> /Contents 498 0 R >> endobj 501 0 obj <> /Contents 502 0 R >> endobj 505 0 obj <> /Contents 506 0 R >> endobj 509 0 obj <> /Contents 510 0 R >> endobj 513 0 obj <> /Contents 514 0 R >> endobj 517 0 obj <> /Contents 518 0 R >> endobj 521 0 obj <> /Contents 522 0 R >> endobj 525 0 obj <> /Contents 526 0 R >> endobj 529 0 obj <> /Contents 530 0 R >> endobj 533 0 obj <> /Contents 534 0 R >> endobj 537 0 obj <> /Contents 538 0 R >> endobj 541 0 obj <> /Contents 542 0 R >> endobj 545 0 obj <> /Contents 546 0 R >> endobj 549 0 obj <> /Contents 550 0 R >> endobj 553 0 obj <> /Contents 554 0 R >> endobj 557 0 obj <> /Contents 558 0 R >> endobj 561 0 obj <> /Contents 562 0 R >> endobj 565 0 obj <> /Contents 566 0 R >> endobj 569 0 obj <> /Contents 570 0 R >> endobj 573 0 obj <> /Contents 574 0 R >> endobj 577 0 obj <> /Contents 578 0 R >> endobj 581 0 obj <> /Contents 582 0 R >> endobj 585 0 obj <> /Contents 586 0 R >> endobj 589 0 obj <> /Contents 590 0 R >> endobj 593 0 obj <> /Contents 594 0 R >> endobj 597 0 obj <> /Contents 598 0 R >> endobj 601 0 obj <> /Contents 602 0 R >> endobj 605 0 obj <> /Contents 606 0 R >> endobj 609 0 obj <> /Contents 610 0 R >> endobj 613 0 obj <> /Contents 614 0 R >> endobj 617 0 obj <> /Contents 618 0 R >> endobj 621 0 obj <> /Contents 622 0 R >> endobj 625 0 obj <> /Contents 626 0 R >> endobj 629 0 obj <> /Contents 630 0 R >> endobj 633 0 obj <> /Contents 634 0 R >> endobj 637 0 obj <> /Contents 638 0 R >> endobj 641 0 obj <> /Contents 642 0 R >> endobj 645 0 obj <> /Contents 646 0 R >> endobj 649 0 obj <> /Contents 650 0 R >> endobj 653 0 obj <> /Contents 654 0 R >> endobj 657 0 obj <> /Contents 658 0 R >> endobj 661 0 obj <> /Contents 662 0 R >> endobj 665 0 obj <> /Contents 666 0 R >> endobj 669 0 obj <> /Contents 670 0 R >> endobj 673 0 obj <> /Contents 674 0 R >> endobj 677 0 obj <> /Contents 678 0 R >> endobj 681 0 obj <> /Contents 682 0 R >> endobj 685 0 obj <> /Contents 686 0 R >> endobj 689 0 obj <> /Contents 690 0 R >> endobj 693 0 obj <> /Contents 694 0 R >> endobj 697 0 obj <> /Contents 698 0 R >> endobj 701 0 obj <> /Contents 702 0 R >> endobj 705 0 obj <> /Contents 706 0 R >> endobj 709 0 obj <> /Contents 710 0 R >> endobj 713 0 obj <> /Contents 714 0 R >> endobj 717 0 obj <> /Contents 718 0 R >> endobj 721 0 obj <> /Contents 722 0 R >> endobj 725 0 obj <> /Contents 726 0 R >> endobj 729 0 obj <> /Contents 730 0 R >> endobj 733 0 obj <> /Contents 734 0 R >> endobj 737 0 obj <> /Contents 738 0 R >> endobj 741 0 obj <> /Contents 742 0 R >> endobj 745 0 obj <> /Contents 746 0 R >> endobj 749 0 obj <> /Contents 750 0 R >> endobj 753 0 obj <> /Contents 754 0 R >> endobj 757 0 obj <> /Contents 758 0 R >> endobj 761 0 obj <> /Contents 762 0 R >> endobj 765 0 obj <> /Contents 766 0 R >> endobj 769 0 obj <> /Contents 770 0 R >> endobj 773 0 obj <> /Contents 774 0 R >> endobj 777 0 obj <> /Contents 778 0 R >> endobj 781 0 obj <> /Contents 782 0 R >> endobj 785 0 obj <> /Contents 786 0 R >> endobj 789 0 obj <> /Contents 790 0 R >> endobj 793 0 obj <> /Contents 794 0 R >> endobj 797 0 obj <> /Contents 798 0 R >> endobj 801 0 obj <> /Contents 802 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 9 0 R 13 0 R 17 0 R 21 0 R 25 0 R 29 0 R 33 0 R 37 0 R 41 0 R 45 0 R 49 0 R 53 0 R 57 0 R 61 0 R 65 0 R 69 0 R 73 0 R 77 0 R 81 0 R 85 0 R 89 0 R 93 0 R 97 0 R 101 0 R 105 0 R 109 0 R 113 0 R 117 0 R 121 0 R 125 0 R 129 0 R 133 0 R 137 0 R 141 0 R 145 0 R 149 0 R 153 0 R 157 0 R 161 0 R 165 0 R 169 0 R 173 0 R 177 0 R 181 0 R 185 0 R 189 0 R 193 0 R 197 0 R 201 0 R 205 0 R 209 0 R 213 0 R 217 0 R 221 0 R 225 0 R 229 0 R 233 0 R 237 0 R 241 0 R 245 0 R 249 0 R 253 0 R 257 0 R 261 0 R 265 0 R 269 0 R 273 0 R 277 0 R 281 0 R 285 0 R 289 0 R 293 0 R 297 0 R 301 0 R 305 0 R 309 0 R 313 0 R 317 0 R 321 0 R 325 0 R 329 0 R 333 0 R 337 0 R 341 0 R 345 0 R 349 0 R 353 0 R 357 0 R 361 0 R 365 0 R 369 0 R 373 0 R 377 0 R 381 0 R 385 0 R 389 0 R 393 0 R 397 0 R 401 0 R 405 0 R 409 0 R 413 0 R 417 0 R 421 0 R 425 0 R 429 0 R 433 0 R 437 0 R 441 0 R 445 0 R 449 0 R 453 0 R 457 0 R 461 0 R 465 0 R 469 0 R 473 0 R 477 0 R 481 0 R 485 0 R 489 0 R 493 0 R 497 0 R 501 0 R 505 0 R 509 0 R 513 0 R 517 0 R 521 0 R 525 0 R 529 0 R 533 0 R 537 0 R 541 0 R 545 0 R 549 0 R 553 0 R 557 0 R 561 0 R 565 0 R 569 0 R 573 0 R 577 0 R 581 0 R 585 0 R 589 0 R 593 0 R 597 0 R 601 0 R 605 0 R 609 0 R 613 0 R 617 0 R 621 0 R 625 0 R 629 0 R 633 0 R 637 0 R 641 0 R 645 0 R 649 0 R 653 0 R 657 0 R 661 0 R 665 0 R 669 0 R 673 0 R 677 0 R 681 0 R 685 0 R 689 0 R 693 0 R 697 0 R 701 0 R 705 0 R 709 0 R 713 0 R 717 0 R 721 0 R 725 0 R 729 0 R 733 0 R 737 0 R 741 0 R 745 0 R 749 0 R 753 0 R 757 0 R 761 0 R 765 0 R 769 0 R 773 0 R 777 0 R 781 0 R 785 0 R 789 0 R 793 0 R 797 0 R 801 0 R ] /Count 200 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 8 0 obj <> endobj 12 0 obj <> endobj 16 0 obj <> endobj 20 0 obj <> endobj 24 0 obj <> endobj 28 0 obj <> endobj 32 0 obj <> endobj 36 0 obj <> endobj 40 0 obj <> endobj 44 0 obj <> endobj 48 0 obj <> endobj 52 0 obj <> endobj 56 0 obj <> endobj 60 0 obj <> endobj 64 0 obj <> endobj 68 0 obj <> endobj 72 0 obj <> endobj 76 0 obj <> endobj 80 0 obj <> endobj 84 0 obj <> endobj 88 0 obj <> endobj 92 0 obj <> endobj 96 0 obj <> endobj 100 0 obj <> endobj 104 0 obj <> endobj 108 0 obj <> endobj 112 0 obj <> endobj 116 0 obj <> endobj 120 0 obj <> endobj 124 0 obj <> endobj 128 0 obj <> endobj 132 0 obj <> endobj 136 0 obj <> endobj 140 0 obj <> endobj 144 0 obj <> endobj 148 0 obj <> endobj 152 0 obj <> endobj 156 0 obj <> endobj 160 0 obj <> endobj 164 0 obj <> endobj 168 0 obj <> endobj 172 0 obj <> endobj 176 0 obj <> endobj 180 0 obj <> endobj 184 0 obj <> endobj 188 0 obj <> endobj 192 0 obj <> endobj 196 0 obj <> endobj 200 0 obj <> endobj 204 0 obj <> endobj 208 0 obj <> endobj 212 0 obj <> endobj 216 0 obj <> endobj 220 0 obj <> endobj 224 0 obj <> endobj 228 0 obj <> endobj 232 0 obj <> endobj 236 0 obj <> endobj 240 0 obj <> endobj 244 0 obj <> endobj 248 0 obj <> endobj 252 0 obj <> endobj 256 0 obj <> endobj 260 0 obj <> endobj 264 0 obj <> endobj 268 0 obj <> endobj 272 0 obj <> endobj 276 0 obj <> endobj 280 0 obj <> endobj 284 0 obj <> endobj 288 0 obj <> endobj 292 0 obj <> endobj 296 0 obj <> endobj 300 0 obj <> endobj 304 0 obj <> endobj 308 0 obj <> endobj 312 0 obj <> endobj 316 0 obj <> endobj 320 0 obj <> endobj 324 0 obj <> endobj 328 0 obj <> endobj 332 0 obj <> endobj 336 0 obj <> endobj 340 0 obj <> endobj 344 0 obj <> endobj 348 0 obj <> endobj 352 0 obj <> endobj 356 0 obj <> endobj 360 0 obj <> endobj 364 0 obj <> endobj 368 0 obj <> endobj 372 0 obj <> endobj 376 0 obj <> endobj 380 0 obj <> endobj 384 0 obj <> endobj 388 0 obj <> endobj 392 0 obj <> endobj 396 0 obj <> endobj 400 0 obj <> endobj 404 0 obj <> endobj 408 0 obj <> endobj 412 0 obj <> endobj 416 0 obj <> endobj 420 0 obj <> endobj 424 0 obj <> endobj 428 0 obj <> endobj 432 0 obj <> endobj 436 0 obj <> endobj 440 0 obj <> endobj 444 0 obj <> endobj 448 0 obj <> endobj 452 0 obj <> endobj 456 0 obj <> endobj 460 0 obj <> endobj 464 0 obj <> endobj 468 0 obj <> endobj 472 0 obj <> endobj 476 0 obj <> endobj 480 0 obj <> endobj 484 0 obj <> endobj 488 0 obj <> endobj 492 0 obj <> endobj 496 0 obj <> endobj 500 0 obj <> endobj 504 0 obj <> endobj 508 0 obj <> endobj 512 0 obj <> endobj 516 0 obj <> endobj 520 0 obj <> endobj 524 0 obj <> endobj 528 0 obj <> endobj 532 0 obj <> endobj 536 0 obj <> endobj 540 0 obj <> endobj 544 0 obj <> endobj 548 0 obj <> endobj 552 0 obj <> endobj 556 0 obj <> endobj 560 0 obj <> endobj 564 0 obj <> endobj 568 0 obj <> endobj 572 0 obj <> endobj 576 0 obj <> endobj 580 0 obj <> endobj 584 0 obj <> endobj 588 0 obj <> endobj 592 0 obj <> endobj 596 0 obj <> endobj 600 0 obj <> endobj 604 0 obj <> endobj 608 0 obj <> endobj 612 0 obj <> endobj 616 0 obj <> endobj 620 0 obj <> endobj 624 0 obj <> endobj 628 0 obj <> endobj 632 0 obj <> endobj 636 0 obj <> endobj 640 0 obj <> endobj 644 0 obj <> endobj 648 0 obj <> endobj 652 0 obj <> endobj 656 0 obj <> endobj 660 0 obj <> endobj 664 0 obj <> endobj 668 0 obj <> endobj 672 0 obj <> endobj 676 0 obj <> endobj 680 0 obj <> endobj 684 0 obj <> endobj 688 0 obj <> endobj 692 0 obj <> endobj 696 0 obj <> endobj 700 0 obj <> endobj 704 0 obj <> endobj 708 0 obj <> endobj 712 0 obj <> endobj 716 0 obj <> endobj 720 0 obj <> endobj 724 0 obj <> endobj 728 0 obj <> endobj 732 0 obj <> endobj 736 0 obj <> endobj 740 0 obj <> endobj 744 0 obj <> endobj 748 0 obj <> endobj 752 0 obj <> endobj 756 0 obj <> endobj 760 0 obj <> endobj 764 0 obj <> endobj 768 0 obj <> endobj 772 0 obj <> endobj 776 0 obj <> endobj 780 0 obj <> endobj 784 0 obj <> endobj 788 0 obj <> endobj 792 0 obj <> endobj 796 0 obj <> endobj 800 0 obj <> endobj 804 0 obj <> endobj 805 0 obj <>stream 2018-04-17T21:15:35Z 2018-04-17T21:15:35Z UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 806 0000000000 65535 f 0000054894 00000 n 0000062609 00000 n 0000053265 00000 n 0000024740 00000 n 0000000015 00000 n 0000000115 00000 n 0000054960 00000 n 0000055021 00000 n 0000024877 00000 n 0000000133 00000 n 0000000235 00000 n 0000055050 00000 n 0000025016 00000 n 0000000254 00000 n 0000000356 00000 n 0000055080 00000 n 0000025156 00000 n 0000000375 00000 n 0000000477 00000 n 0000055110 00000 n 0000025296 00000 n 0000000496 00000 n 0000000598 00000 n 0000055140 00000 n 0000025436 00000 n 0000000617 00000 n 0000000719 00000 n 0000055170 00000 n 0000025576 00000 n 0000000738 00000 n 0000000840 00000 n 0000055200 00000 n 0000025716 00000 n 0000000859 00000 n 0000000961 00000 n 0000055230 00000 n 0000025856 00000 n 0000000980 00000 n 0000001082 00000 n 0000055260 00000 n 0000025996 00000 n 0000001101 00000 n 0000001203 00000 n 0000055290 00000 n 0000026136 00000 n 0000001222 00000 n 0000001324 00000 n 0000055320 00000 n 0000026276 00000 n 0000001343 00000 n 0000001445 00000 n 0000055350 00000 n 0000026416 00000 n 0000001464 00000 n 0000001566 00000 n 0000055380 00000 n 0000026556 00000 n 0000001585 00000 n 0000001687 00000 n 0000055410 00000 n 0000026696 00000 n 0000001706 00000 n 0000001808 00000 n 0000055440 00000 n 0000026836 00000 n 0000001827 00000 n 0000001929 00000 n 0000055470 00000 n 0000026976 00000 n 0000001948 00000 n 0000002050 00000 n 0000055500 00000 n 0000027116 00000 n 0000002069 00000 n 0000002171 00000 n 0000055530 00000 n 0000027256 00000 n 0000002190 00000 n 0000002292 00000 n 0000055560 00000 n 0000027396 00000 n 0000002311 00000 n 0000002413 00000 n 0000055590 00000 n 0000027536 00000 n 0000002432 00000 n 0000002534 00000 n 0000055620 00000 n 0000027676 00000 n 0000002553 00000 n 0000002655 00000 n 0000055650 00000 n 0000027816 00000 n 0000002674 00000 n 0000002776 00000 n 0000055680 00000 n 0000027956 00000 n 0000002795 00000 n 0000002897 00000 n 0000055710 00000 n 0000028097 00000 n 0000002916 00000 n 0000003020 00000 n 0000055741 00000 n 0000028240 00000 n 0000003040 00000 n 0000003144 00000 n 0000055772 00000 n 0000028383 00000 n 0000003164 00000 n 0000003268 00000 n 0000055803 00000 n 0000028526 00000 n 0000003288 00000 n 0000003392 00000 n 0000055834 00000 n 0000028669 00000 n 0000003412 00000 n 0000003516 00000 n 0000055865 00000 n 0000028812 00000 n 0000003536 00000 n 0000003640 00000 n 0000055896 00000 n 0000028955 00000 n 0000003660 00000 n 0000003764 00000 n 0000055927 00000 n 0000029098 00000 n 0000003784 00000 n 0000003888 00000 n 0000055958 00000 n 0000029241 00000 n 0000003908 00000 n 0000004012 00000 n 0000055989 00000 n 0000029384 00000 n 0000004032 00000 n 0000004136 00000 n 0000056020 00000 n 0000029527 00000 n 0000004156 00000 n 0000004260 00000 n 0000056051 00000 n 0000029670 00000 n 0000004280 00000 n 0000004384 00000 n 0000056082 00000 n 0000029813 00000 n 0000004404 00000 n 0000004508 00000 n 0000056113 00000 n 0000029956 00000 n 0000004528 00000 n 0000004632 00000 n 0000056144 00000 n 0000030099 00000 n 0000004652 00000 n 0000004756 00000 n 0000056175 00000 n 0000030242 00000 n 0000004776 00000 n 0000004880 00000 n 0000056206 00000 n 0000030385 00000 n 0000004900 00000 n 0000005004 00000 n 0000056237 00000 n 0000030528 00000 n 0000005024 00000 n 0000005128 00000 n 0000056268 00000 n 0000030671 00000 n 0000005148 00000 n 0000005252 00000 n 0000056299 00000 n 0000030814 00000 n 0000005272 00000 n 0000005376 00000 n 0000056330 00000 n 0000030957 00000 n 0000005396 00000 n 0000005500 00000 n 0000056361 00000 n 0000031100 00000 n 0000005520 00000 n 0000005624 00000 n 0000056392 00000 n 0000031243 00000 n 0000005644 00000 n 0000005748 00000 n 0000056423 00000 n 0000031386 00000 n 0000005768 00000 n 0000005872 00000 n 0000056454 00000 n 0000031529 00000 n 0000005892 00000 n 0000005996 00000 n 0000056485 00000 n 0000031672 00000 n 0000006016 00000 n 0000006120 00000 n 0000056516 00000 n 0000031815 00000 n 0000006140 00000 n 0000006244 00000 n 0000056547 00000 n 0000031958 00000 n 0000006264 00000 n 0000006368 00000 n 0000056578 00000 n 0000032101 00000 n 0000006388 00000 n 0000006492 00000 n 0000056609 00000 n 0000032244 00000 n 0000006512 00000 n 0000006616 00000 n 0000056640 00000 n 0000032387 00000 n 0000006636 00000 n 0000006740 00000 n 0000056671 00000 n 0000032530 00000 n 0000006760 00000 n 0000006864 00000 n 0000056702 00000 n 0000032673 00000 n 0000006884 00000 n 0000006988 00000 n 0000056733 00000 n 0000032816 00000 n 0000007008 00000 n 0000007112 00000 n 0000056764 00000 n 0000032959 00000 n 0000007132 00000 n 0000007236 00000 n 0000056795 00000 n 0000033102 00000 n 0000007256 00000 n 0000007360 00000 n 0000056826 00000 n 0000033245 00000 n 0000007380 00000 n 0000007484 00000 n 0000056857 00000 n 0000033388 00000 n 0000007504 00000 n 0000007608 00000 n 0000056888 00000 n 0000033531 00000 n 0000007628 00000 n 0000007732 00000 n 0000056919 00000 n 0000033674 00000 n 0000007752 00000 n 0000007856 00000 n 0000056950 00000 n 0000033817 00000 n 0000007876 00000 n 0000007980 00000 n 0000056981 00000 n 0000033960 00000 n 0000008000 00000 n 0000008104 00000 n 0000057012 00000 n 0000034103 00000 n 0000008124 00000 n 0000008228 00000 n 0000057043 00000 n 0000034246 00000 n 0000008248 00000 n 0000008352 00000 n 0000057074 00000 n 0000034389 00000 n 0000008372 00000 n 0000008476 00000 n 0000057105 00000 n 0000034532 00000 n 0000008496 00000 n 0000008600 00000 n 0000057136 00000 n 0000034675 00000 n 0000008620 00000 n 0000008724 00000 n 0000057167 00000 n 0000034818 00000 n 0000008744 00000 n 0000008848 00000 n 0000057198 00000 n 0000034961 00000 n 0000008868 00000 n 0000008972 00000 n 0000057229 00000 n 0000035104 00000 n 0000008992 00000 n 0000009096 00000 n 0000057260 00000 n 0000035247 00000 n 0000009116 00000 n 0000009220 00000 n 0000057291 00000 n 0000035390 00000 n 0000009240 00000 n 0000009344 00000 n 0000057322 00000 n 0000035533 00000 n 0000009364 00000 n 0000009468 00000 n 0000057353 00000 n 0000035676 00000 n 0000009488 00000 n 0000009592 00000 n 0000057384 00000 n 0000035819 00000 n 0000009612 00000 n 0000009716 00000 n 0000057415 00000 n 0000035962 00000 n 0000009736 00000 n 0000009840 00000 n 0000057446 00000 n 0000036105 00000 n 0000009860 00000 n 0000009964 00000 n 0000057477 00000 n 0000036248 00000 n 0000009984 00000 n 0000010088 00000 n 0000057508 00000 n 0000036391 00000 n 0000010108 00000 n 0000010212 00000 n 0000057539 00000 n 0000036534 00000 n 0000010232 00000 n 0000010336 00000 n 0000057570 00000 n 0000036677 00000 n 0000010356 00000 n 0000010460 00000 n 0000057601 00000 n 0000036820 00000 n 0000010480 00000 n 0000010584 00000 n 0000057632 00000 n 0000036963 00000 n 0000010604 00000 n 0000010708 00000 n 0000057663 00000 n 0000037106 00000 n 0000010728 00000 n 0000010832 00000 n 0000057694 00000 n 0000037249 00000 n 0000010852 00000 n 0000010956 00000 n 0000057725 00000 n 0000037392 00000 n 0000010976 00000 n 0000011080 00000 n 0000057756 00000 n 0000037535 00000 n 0000011100 00000 n 0000011204 00000 n 0000057787 00000 n 0000037678 00000 n 0000011224 00000 n 0000011328 00000 n 0000057818 00000 n 0000037821 00000 n 0000011348 00000 n 0000011452 00000 n 0000057849 00000 n 0000037964 00000 n 0000011472 00000 n 0000011576 00000 n 0000057880 00000 n 0000038107 00000 n 0000011596 00000 n 0000011700 00000 n 0000057911 00000 n 0000038250 00000 n 0000011720 00000 n 0000011824 00000 n 0000057942 00000 n 0000038393 00000 n 0000011844 00000 n 0000011948 00000 n 0000057973 00000 n 0000038536 00000 n 0000011968 00000 n 0000012072 00000 n 0000058004 00000 n 0000038679 00000 n 0000012092 00000 n 0000012196 00000 n 0000058035 00000 n 0000038822 00000 n 0000012216 00000 n 0000012320 00000 n 0000058066 00000 n 0000038965 00000 n 0000012340 00000 n 0000012444 00000 n 0000058097 00000 n 0000039108 00000 n 0000012464 00000 n 0000012568 00000 n 0000058128 00000 n 0000039251 00000 n 0000012588 00000 n 0000012692 00000 n 0000058159 00000 n 0000039394 00000 n 0000012712 00000 n 0000012816 00000 n 0000058190 00000 n 0000039537 00000 n 0000012836 00000 n 0000012940 00000 n 0000058221 00000 n 0000039680 00000 n 0000012960 00000 n 0000013064 00000 n 0000058252 00000 n 0000039823 00000 n 0000013084 00000 n 0000013188 00000 n 0000058283 00000 n 0000039966 00000 n 0000013208 00000 n 0000013312 00000 n 0000058314 00000 n 0000040109 00000 n 0000013332 00000 n 0000013436 00000 n 0000058345 00000 n 0000040252 00000 n 0000013456 00000 n 0000013560 00000 n 0000058376 00000 n 0000040395 00000 n 0000013580 00000 n 0000013684 00000 n 0000058407 00000 n 0000040538 00000 n 0000013704 00000 n 0000013808 00000 n 0000058438 00000 n 0000040681 00000 n 0000013828 00000 n 0000013932 00000 n 0000058469 00000 n 0000040824 00000 n 0000013952 00000 n 0000014056 00000 n 0000058500 00000 n 0000040967 00000 n 0000014076 00000 n 0000014180 00000 n 0000058531 00000 n 0000041110 00000 n 0000014200 00000 n 0000014304 00000 n 0000058562 00000 n 0000041253 00000 n 0000014324 00000 n 0000014428 00000 n 0000058593 00000 n 0000041396 00000 n 0000014448 00000 n 0000014552 00000 n 0000058624 00000 n 0000041539 00000 n 0000014572 00000 n 0000014676 00000 n 0000058655 00000 n 0000041682 00000 n 0000014696 00000 n 0000014800 00000 n 0000058686 00000 n 0000041825 00000 n 0000014820 00000 n 0000014924 00000 n 0000058717 00000 n 0000041968 00000 n 0000014944 00000 n 0000015048 00000 n 0000058748 00000 n 0000042111 00000 n 0000015068 00000 n 0000015172 00000 n 0000058779 00000 n 0000042254 00000 n 0000015192 00000 n 0000015296 00000 n 0000058810 00000 n 0000042397 00000 n 0000015316 00000 n 0000015420 00000 n 0000058841 00000 n 0000042540 00000 n 0000015440 00000 n 0000015544 00000 n 0000058872 00000 n 0000042683 00000 n 0000015564 00000 n 0000015668 00000 n 0000058903 00000 n 0000042826 00000 n 0000015688 00000 n 0000015792 00000 n 0000058934 00000 n 0000042969 00000 n 0000015812 00000 n 0000015916 00000 n 0000058965 00000 n 0000043112 00000 n 0000015936 00000 n 0000016040 00000 n 0000058996 00000 n 0000043255 00000 n 0000016060 00000 n 0000016164 00000 n 0000059027 00000 n 0000043398 00000 n 0000016184 00000 n 0000016288 00000 n 0000059058 00000 n 0000043541 00000 n 0000016308 00000 n 0000016412 00000 n 0000059089 00000 n 0000043684 00000 n 0000016432 00000 n 0000016536 00000 n 0000059120 00000 n 0000043827 00000 n 0000016556 00000 n 0000016660 00000 n 0000059151 00000 n 0000043970 00000 n 0000016680 00000 n 0000016784 00000 n 0000059182 00000 n 0000044113 00000 n 0000016804 00000 n 0000016908 00000 n 0000059213 00000 n 0000044256 00000 n 0000016928 00000 n 0000017032 00000 n 0000059244 00000 n 0000044399 00000 n 0000017052 00000 n 0000017156 00000 n 0000059275 00000 n 0000044542 00000 n 0000017176 00000 n 0000017280 00000 n 0000059306 00000 n 0000044685 00000 n 0000017300 00000 n 0000017404 00000 n 0000059337 00000 n 0000044828 00000 n 0000017424 00000 n 0000017528 00000 n 0000059368 00000 n 0000044971 00000 n 0000017548 00000 n 0000017652 00000 n 0000059399 00000 n 0000045114 00000 n 0000017672 00000 n 0000017776 00000 n 0000059430 00000 n 0000045257 00000 n 0000017796 00000 n 0000017900 00000 n 0000059461 00000 n 0000045400 00000 n 0000017920 00000 n 0000018024 00000 n 0000059492 00000 n 0000045543 00000 n 0000018044 00000 n 0000018148 00000 n 0000059523 00000 n 0000045686 00000 n 0000018168 00000 n 0000018272 00000 n 0000059554 00000 n 0000045829 00000 n 0000018292 00000 n 0000018396 00000 n 0000059585 00000 n 0000045972 00000 n 0000018416 00000 n 0000018520 00000 n 0000059616 00000 n 0000046115 00000 n 0000018540 00000 n 0000018644 00000 n 0000059647 00000 n 0000046258 00000 n 0000018664 00000 n 0000018768 00000 n 0000059678 00000 n 0000046401 00000 n 0000018788 00000 n 0000018892 00000 n 0000059709 00000 n 0000046544 00000 n 0000018912 00000 n 0000019016 00000 n 0000059740 00000 n 0000046687 00000 n 0000019036 00000 n 0000019140 00000 n 0000059771 00000 n 0000046830 00000 n 0000019160 00000 n 0000019264 00000 n 0000059802 00000 n 0000046973 00000 n 0000019284 00000 n 0000019388 00000 n 0000059833 00000 n 0000047116 00000 n 0000019408 00000 n 0000019512 00000 n 0000059864 00000 n 0000047259 00000 n 0000019532 00000 n 0000019636 00000 n 0000059895 00000 n 0000047402 00000 n 0000019656 00000 n 0000019760 00000 n 0000059926 00000 n 0000047545 00000 n 0000019780 00000 n 0000019884 00000 n 0000059957 00000 n 0000047688 00000 n 0000019904 00000 n 0000020008 00000 n 0000059988 00000 n 0000047831 00000 n 0000020028 00000 n 0000020132 00000 n 0000060019 00000 n 0000047974 00000 n 0000020152 00000 n 0000020256 00000 n 0000060050 00000 n 0000048117 00000 n 0000020276 00000 n 0000020380 00000 n 0000060081 00000 n 0000048260 00000 n 0000020400 00000 n 0000020504 00000 n 0000060112 00000 n 0000048403 00000 n 0000020524 00000 n 0000020628 00000 n 0000060143 00000 n 0000048546 00000 n 0000020648 00000 n 0000020752 00000 n 0000060174 00000 n 0000048689 00000 n 0000020772 00000 n 0000020876 00000 n 0000060205 00000 n 0000048832 00000 n 0000020896 00000 n 0000021000 00000 n 0000060236 00000 n 0000048975 00000 n 0000021020 00000 n 0000021124 00000 n 0000060267 00000 n 0000049118 00000 n 0000021144 00000 n 0000021248 00000 n 0000060298 00000 n 0000049261 00000 n 0000021268 00000 n 0000021372 00000 n 0000060329 00000 n 0000049404 00000 n 0000021392 00000 n 0000021496 00000 n 0000060360 00000 n 0000049547 00000 n 0000021516 00000 n 0000021620 00000 n 0000060391 00000 n 0000049690 00000 n 0000021640 00000 n 0000021744 00000 n 0000060422 00000 n 0000049833 00000 n 0000021764 00000 n 0000021868 00000 n 0000060453 00000 n 0000049976 00000 n 0000021888 00000 n 0000021992 00000 n 0000060484 00000 n 0000050119 00000 n 0000022012 00000 n 0000022116 00000 n 0000060515 00000 n 0000050262 00000 n 0000022136 00000 n 0000022240 00000 n 0000060546 00000 n 0000050405 00000 n 0000022260 00000 n 0000022364 00000 n 0000060577 00000 n 0000050548 00000 n 0000022384 00000 n 0000022488 00000 n 0000060608 00000 n 0000050691 00000 n 0000022508 00000 n 0000022612 00000 n 0000060639 00000 n 0000050834 00000 n 0000022632 00000 n 0000022736 00000 n 0000060670 00000 n 0000050977 00000 n 0000022756 00000 n 0000022860 00000 n 0000060701 00000 n 0000051120 00000 n 0000022880 00000 n 0000022984 00000 n 0000060732 00000 n 0000051263 00000 n 0000023004 00000 n 0000023108 00000 n 0000060763 00000 n 0000051406 00000 n 0000023128 00000 n 0000023232 00000 n 0000060794 00000 n 0000051549 00000 n 0000023252 00000 n 0000023356 00000 n 0000060825 00000 n 0000051692 00000 n 0000023376 00000 n 0000023480 00000 n 0000060856 00000 n 0000051835 00000 n 0000023500 00000 n 0000023604 00000 n 0000060887 00000 n 0000051978 00000 n 0000023624 00000 n 0000023728 00000 n 0000060918 00000 n 0000052121 00000 n 0000023748 00000 n 0000023852 00000 n 0000060949 00000 n 0000052264 00000 n 0000023872 00000 n 0000023976 00000 n 0000060980 00000 n 0000052407 00000 n 0000023996 00000 n 0000024100 00000 n 0000061011 00000 n 0000052550 00000 n 0000024120 00000 n 0000024224 00000 n 0000061042 00000 n 0000052693 00000 n 0000024244 00000 n 0000024348 00000 n 0000061073 00000 n 0000052836 00000 n 0000024368 00000 n 0000024472 00000 n 0000061104 00000 n 0000052979 00000 n 0000024492 00000 n 0000024596 00000 n 0000061135 00000 n 0000053122 00000 n 0000024616 00000 n 0000024720 00000 n 0000061166 00000 n 0000061197 00000 n trailer << /Size 806 /Root 1 0 R /Info 2 0 R /ID [<9E6D85AA6B3DFDFB7051887B05827804><9E6D85AA6B3DFDFB7051887B05827804>] >> startxref 62732 %%EOF braintree_python-3.57.1/tests/fixtures/gif_extension_bt_logo.gif0000644000175000017500000000461313545202423023341 0ustar hlehle‰PNG  IHDRu ,G7øsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î< IDAThí›{°WUÇ?KyÉ› (ò  s CËÔñA0db¦å£$¨f´TC™b„|›SC# DÖÊR0)ˆ‚¢‚¼®€p/÷Ûký¼‡Ã9¿‹è½€ý¾3gÎïì½ÖÚk¿÷^kýŒc ’ç›Ìlò‘Öçh„Ij—‘Wl4³òÚU©8$ÝüXefÝj@~ 5Pnf>mùµIÛ• I«%Ý")«ãk’î Ý^­!ùýBþë5!¿6Pxhtö+#¯1Ðè LÚ7Õ¾Ša°%žò éòkSé %ý:òÊ%µ8R:Ö>+35f¶[Ò|†ÖN¶H M? ”áû]_À€%À]föFHR#à`p:¾:¬f3ÍLi=¢¬ RÉïšÙø,½%ΉÏ]ÀÀ`0ÐX< Ì(”'i"Ð89øZIšžý¶™Ý™(§05©0ø>p9¾7o5³ÇR:ÖF—ð3Ì«A;7§^LJÜ+ñÔ€ÕÀ¤Û.o¦FÞ¥‘·CÒ ‰ô_¤öß©’veìËïH:9x:IÚPd §22hs÷TI%èÊ$­Ê)ï7 žbzðrºcÒ:Iš—Ã;.Áw¢¤eEÊù­¼“e5•´ ÏÓ’êguêVIã™ –Ç32UHoIתªÁ*%m”tµ¤¶’ºFÞ>I£‚§Ž¤Y’^‘4DRIŸ—46ø%éìŒNê%é;ñÜtÅ:õ«’nKT¸"êÓKR;IÓ"}¿¤Ó‚gxÔçW‘·9¾“Ï%©rŽ‹ô‚N…:üNRŸ¨ÛÏ"mEЛ¤ç"m½¤‹äÛ\Óµ;ònK•5+Ò7IºBRcIBïm‘7%«Só0«PùŒükÐìÔ6•×FRãTZ=Iu3ä, 9cò:+è¾tEO¿’º$ô›Ê;^Ò–ÈœÊûØ{ª¤þ‰²&¥òLR— ÚrI3dŠü²BÛIê–VÏÐÈÛ'©uzOÝÜ¿ONâëþy’™Ù¿rêö¸™½™Lȹçµ®–Ôß¿Êð=îs‘ß(GþáBÀƒ)½öKZ´êgr*€ ©²ü;‘Ô?ÞeÀ]ÒAGˆÂ€oŒŸ žIðì~œÁc@eðHwêf63•6IÒ}Àð«M²±2'ý#HÌÄL9>ˆZ}ªãýøÀ̶f¤WÖ@Yo›Ù¶jhšÅ»pY5´mR< …§èé7Åx§v/B³ïäLÅ;ôAàV3Û ©%0‹üS›(tv½Ãà=”6XïÕÀAç‡v§xÞÃû ¢Ïžj­DÑà?ŒÏþ»ÉÍo…=÷þB‡šg®ìOïÆûTI“’Α4âÊ ïü/#Íl[ò¶ã³±©™í žùÀN|;¼)Í|C€SÌìC“4·&uÇGÆâ„-ðÆ®à‹Íìé¨à|üîÚ ßW%d»™´LȯL¿ã³v?p0_†ÞÖšÙÁ3 ¿›Ð_®?^H¤¯0³±Á37úŸe,f›ÙTIჴ/>˜–ïG§{I‹ƒ÷-`°è|·“ÃÌæÊo#¢zg´ßd3›ŸÑ〻ãóoÀ`+ÐïÐøêif»‚ç»ÀCÁ³xŸ¹§ߌvÜô¨Îö[ÀRI\þ%í-Bÿ^º"Ás®ªNI¬“´$ñ]žà¹ûô“¤çkçšÙÛ šø*—‡×Ìì¼LIMqKY7 ÞÞ/KÍlOCàë@Oü|²ø'°ØÌŠíµ%”PB %”PB %”P±èÝ+i¥¤¡Õsfʪ/igBÞI”Ô¼OW¹nBMMâ¨&«ôŠ÷#¸Å¦F(|t¢*Zâ^Üqµ‡¸ç䈄ĪAÿ¨„¤ssŒ]póà Ài¸]´r%p&:² ÑùnyÁÌI2à:Ü•µ1dÎ1³1’šß ymQx§ÿ7_.¦Ê¸ñZJßá¸×å 3;fã jòH—t°Ñ½Q,};$ýRÒ‹±lNVUôÀšXF+%½%©µ< â¹qsÐÝ¡ªй’¦È×Jº0~ï–´\UQ7Jš¿[&ôê*omºäìþ¿G4vI×§Ò{§l¢ïKz@ÒyñýHÐuŽïgâûy¹m÷+ÑQË$Õ•ôû„¬rùþò•±òë ¡ß­’ÆIºFò2VÒOå‘*×Kú¹¤Á ÏQ ´Çäž*©'î…ù20 •Ý5Þ÷›£¥™]‹Ç-¼ïÂwa‰œ/£•ÀUñï„‚¼öfV×ÌÎ0³9x4ß`­|¹.¸×àûðK/P×Ì’ŽùáÀ2àvà Ü 4 ÷–ÍĽDÍl"n¾%t|·û~ ²œ)·i÷5³mÇÜž 8ßtT7ñ÷B'¤Ãn–àûìyYïH/4þL` ¾?^gfkbfu¶šÙú”¼Åxc¯ÄÖñ•:x„BºS·É=] óqçÅÒÐwî+= x wÁ¼/7ú7ÀÝ›eÀÅA¿8?À­‹6Á2[î(†¤Ö@+3[ß}€uf¶%¾/Æ}¥S“•È\Š{C–ã3}š™½%™Z€Ÿ–/43Éû·ëÍlzJVCàf܃ôü„½˜‹О2³$è ø~ˆz6ÊÿÓàx<Òð­føLTü~?´ šu¸ï¶ ÷Ô´›ÙìÃjÔÏ"$µ˜6ÉO¨G’îTøm«¡k$D/! IÍ%/÷tê!Ò5—Ô,™ö?ÒQÿâc¶°pIEND®B`‚braintree_python-3.57.1/tests/fixtures/malformed_pdf.pdf0000644000175000017500000000022613545202423021572 0ustar hlehleXXXXXXXXXXX¾?^gfkbfu¶šÙú”¼Åxc¯ÄÂÖÂñ•:x„BºS·É=] ÂóqçÅÒÃwî+= x wü/7ú7ÀÛeÀÅA¿8?À­‹6Ã2[î(†¤Ö@+3[ß} braintree_python-3.57.1/tests/integration/0000755000175000017500000000000013545202423016752 5ustar hlehlebraintree_python-3.57.1/tests/integration/test_credit_card_verification.py0000644000175000017500000001633413545202423025377 0ustar hlehlefrom tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestCreditCardVerfication(unittest.TestCase): def test_create_success(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2012" }}) self.assertTrue(result.is_success) verification = result.verification self.assertEqual("1000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, verification.processor_response_type) def test_create_failure(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.FailsSandboxVerification.MasterCard, "expiration_date": "05/2012" }}) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual("2000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.SoftDeclined, verification.processor_response_type) def test_create_returns_validation_errors(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.FailsSandboxVerification.MasterCard, "expiration_date": "05/2012" }, "options": {"amount": "-10.00"} }) self.assertFalse(result.is_success) amount_errors = result.errors.for_object("verification").for_object("options").on("amount") self.assertEqual(1, len(amount_errors)) self.assertEqual(ErrorCodes.Verification.Options.AmountCannotBeNegative, amount_errors[0].code) def test_create_with_account_type_debit(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "account_type": "debit", }, }) self.assertTrue(result.is_success) self.assertEqual("debit", result.verification.credit_card["account_type"]) def test_create_with_account_type_credit(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "account_type": "credit", }, }) self.assertTrue(result.is_success) self.assertEqual("credit", result.verification.credit_card["account_type"]) def test_create_with_unsupported_account_type(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2012" }, "options": { "account_type": "debit", }, }) self.assertFalse(result.is_success) account_type_errors = result.errors.for_object("verification").for_object("options").on("account_type") self.assertEqual(1, len(account_type_errors)) self.assertEqual(ErrorCodes.Verification.Options.AccountTypeNotSupported , account_type_errors[0].code) def test_create_with_invalid_account_type(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "account_type": "invalid", }, }) self.assertFalse(result.is_success) account_type_errors = result.errors.for_object("verification").for_object("options").on("account_type") self.assertEqual(1, len(account_type_errors)) self.assertEqual(ErrorCodes.Verification.Options.AccountTypeIsInvalid, account_type_errors[0].code) def test_find_with_verification_id(self): customer = Customer.create({ "credit_card": { "number": CreditCardNumbers.FailsSandboxVerification.MasterCard, "expiration_date": "05/2012", "cardholder_name": "Tom Smith", "options": {"verify_card": True} }}) created_verification = customer.credit_card_verification found_verification = CreditCardVerification.find(created_verification.id) self.assertEqual(created_verification, found_verification) def test_verification_not_found(self): self.assertRaises(NotFoundError, CreditCardVerification.find, "invalid-id") def test_card_type_indicators(self): cardholder_name = "Tom %s" % random.randint(1, 10000) Customer.create({"credit_card": { "cardholder_name": cardholder_name, "expiration_date": "10/2012", "number": CreditCardNumbers.CardTypeIndicators.Unknown, "options": {"verify_card": True} }}) found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.credit_card_cardholder_name == cardholder_name ) self.assertEqual(CreditCard.Prepaid.Unknown, found_verifications.first.credit_card['prepaid']) self.assertEqual(CreditCard.Debit.Unknown, found_verifications.first.credit_card['debit']) self.assertEqual(CreditCard.Commercial.Unknown, found_verifications.first.credit_card['commercial']) self.assertEqual(CreditCard.Healthcare.Unknown, found_verifications.first.credit_card['healthcare']) self.assertEqual(CreditCard.Payroll.Unknown, found_verifications.first.credit_card['payroll']) self.assertEqual(CreditCard.DurbinRegulated.Unknown, found_verifications.first.credit_card['durbin_regulated']) self.assertEqual(CreditCard.IssuingBank.Unknown, found_verifications.first.credit_card['issuing_bank']) self.assertEqual(CreditCard.CountryOfIssuance.Unknown, found_verifications.first.credit_card['country_of_issuance']) self.assertEqual(CreditCard.ProductId.Unknown, found_verifications.first.credit_card['product_id']) def test_create_success_network_response_code_text(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2012" }, }) self.assertTrue(result.is_success) verification = result.verification self.assertEqual("1000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, verification.processor_response_type) self.assertEqual("XX", verification.network_response_code) self.assertEqual("sample network response text", verification.network_response_text) braintree_python-3.57.1/tests/integration/test_transaction_line_item_gateway.py0000644000175000017500000000046213545202423026460 0ustar hlehlefrom tests.test_helper import * class TestTransactionLineItemGateway(unittest.TestCase): @raises(NotFoundError) def test_transaction_line_item_gateway_find_all_raises_when_transaction_not_found(self): transaction_id = "willnotbefound" TransactionLineItem.find_all(transaction_id) braintree_python-3.57.1/tests/integration/test_transaction_search.py0000644000175000017500000016673413545202423024256 0ustar hlehlefrom tests.test_helper import * class TestTransactionSearch(unittest.TestCase): def test_advanced_search_no_results(self): collection = Transaction.search([ TransactionSearch.billing_first_name == "no_such_person" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_searches_all_text_fields_at_once(self): first_name = "Tim%s" % random.randint(1, 100000) token = "creditcard%s" % random.randint(1, 100000) customer_id = "customer%s" % random.randint(1, 100000) transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Tom Smith", "token": token, }, "billing": { "company": "Braintree", "country_name": "United States of America", "extended_address": "Suite 123", "first_name": first_name, "last_name": "Smith", "locality": "Chicago", "postal_code": "12345", "region": "IL", "street_address": "123 Main St" }, "customer": { "company": "Braintree", "email": "smith@example.com", "fax": "5551231234", "first_name": "Tom", "id": customer_id, "last_name": "Smith", "phone": "5551231234", "website": "http://example.com", }, "options": { "store_in_vault": True, "submit_for_settlement": True }, "order_id": "myorder", "shipping": { "company": "Braintree P.S.", "country_name": "Mexico", "extended_address": "Apt 456", "first_name": "Thomas", "last_name": "Smithy", "locality": "Braintree", "postal_code": "54321", "region": "MA", "street_address": "456 Road" } }).transaction TestHelper.settle_transaction(transaction.id) transaction = Transaction.find(transaction.id) collection = Transaction.search([ TransactionSearch.billing_company == "Braintree", TransactionSearch.billing_country_name == "United States of America", TransactionSearch.billing_extended_address == "Suite 123", TransactionSearch.billing_first_name == first_name, TransactionSearch.billing_last_name == "Smith", TransactionSearch.billing_locality == "Chicago", TransactionSearch.billing_postal_code == "12345", TransactionSearch.billing_region == "IL", TransactionSearch.billing_street_address == "123 Main St", TransactionSearch.credit_card_cardholder_name == "Tom Smith", TransactionSearch.credit_card_expiration_date == "05/2012", TransactionSearch.credit_card_number == "4111111111111111", TransactionSearch.customer_company == "Braintree", TransactionSearch.customer_email == "smith@example.com", TransactionSearch.customer_fax == "5551231234", TransactionSearch.customer_first_name == "Tom", TransactionSearch.customer_id == customer_id, TransactionSearch.customer_last_name == "Smith", TransactionSearch.customer_phone == "5551231234", TransactionSearch.customer_website == "http://example.com", TransactionSearch.order_id == "myorder", TransactionSearch.payment_method_token == token, TransactionSearch.processor_authorization_code == transaction.processor_authorization_code, TransactionSearch.settlement_batch_id == transaction.settlement_batch_id, TransactionSearch.shipping_company == "Braintree P.S.", TransactionSearch.shipping_country_name == "Mexico", TransactionSearch.shipping_extended_address == "Apt 456", TransactionSearch.shipping_first_name == "Thomas", TransactionSearch.shipping_last_name == "Smithy", TransactionSearch.shipping_locality == "Braintree", TransactionSearch.shipping_postal_code == "54321", TransactionSearch.shipping_region == "MA", TransactionSearch.shipping_street_address == "456 Road", TransactionSearch.id == transaction.id ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_search_each_text_field(self): first_name = "Tim%s" % random.randint(1, 100000) token = "creditcard%s" % random.randint(1, 100000) customer_id = "customer%s" % random.randint(1, 100000) transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Tom Smith", "token": token, }, "billing": { "company": "Braintree", "country_name": "United States of America", "extended_address": "Suite 123", "first_name": first_name, "last_name": "Smith", "locality": "Chicago", "postal_code": "12345", "region": "IL", "street_address": "123 Main St" }, "customer": { "company": "Braintree", "email": "smith@example.com", "fax": "5551231234", "first_name": "Tom", "id": customer_id, "last_name": "Smith", "phone": "5551231234", "website": "http://example.com", }, "options": { "store_in_vault": True }, "order_id": "myorder", "shipping": { "company": "Braintree P.S.", "country_name": "Mexico", "extended_address": "Apt 456", "first_name": "Thomas", "last_name": "Smithy", "locality": "Braintree", "postal_code": "54321", "region": "MA", "street_address": "456 Road" } }).transaction search_criteria = { "billing_company": "Braintree", "billing_country_name": "United States of America", "billing_extended_address": "Suite 123", "billing_first_name": first_name, "billing_last_name": "Smith", "billing_locality": "Chicago", "billing_postal_code": "12345", "billing_region": "IL", "billing_street_address": "123 Main St", "credit_card_cardholder_name": "Tom Smith", "credit_card_expiration_date": "05/2012", "credit_card_number": "4111111111111111", "customer_company": "Braintree", "customer_email": "smith@example.com", "customer_fax": "5551231234", "customer_first_name": "Tom", "customer_id": customer_id, "customer_last_name": "Smith", "customer_phone": "5551231234", "customer_website": "http://example.com", "order_id": "myorder", "payment_method_token": token, "processor_authorization_code": transaction.processor_authorization_code, "shipping_company": "Braintree P.S.", "shipping_country_name": "Mexico", "shipping_extended_address": "Apt 456", "shipping_first_name": "Thomas", "shipping_last_name": "Smithy", "shipping_locality": "Braintree", "shipping_postal_code": "54321", "shipping_region": "MA", "shipping_street_address": "456 Road", "user": "integration_user_public_id", "credit_card_unique_identifier": transaction.credit_card["unique_number_identifier"] } for criterion, value in search_criteria.items(): text_node = getattr(TransactionSearch, criterion) collection = Transaction.search([ TransactionSearch.id == transaction.id, text_node == value ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, text_node == "invalid" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_with_argument_list_rather_than_literal_list(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Tom Smith", }, }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name == "Tom Smith" ) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_payment_instrument_type_is_credit_card(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Tom Smith", }, }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == "CreditCardDetail" ) self.assertEqual(transaction.payment_instrument_type, PaymentInstrumentType.CreditCard) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_payment_instrument_type_is_paypal(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == "PayPalDetail" ) self.assertEqual(transaction.payment_instrument_type, PaymentInstrumentType.PayPalAccount) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_payment_instrument_type_is_local_payment(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "payment_method_nonce": Nonces.LocalPayment }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == "LocalPaymentDetail" ) self.assertEqual(transaction.payment_instrument_type, PaymentInstrumentType.LocalPayment) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_payment_instrument_type_is_apple_pay(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.ApplePayVisa }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == "ApplePayDetail" ) self.assertEqual(transaction.payment_instrument_type, PaymentInstrumentType.ApplePayCard) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_text_node_contains(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Jane Shea" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.contains("ane She") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.contains("invalid") ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_text_node_starts_with(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Jane Shea" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.starts_with("Jane S") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.starts_with("invalid") ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_text_node_ends_with(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Jane Shea" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.ends_with("e Shea") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.ends_with("invalid") ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_text_node_is_not(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Jane Shea" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name != "invalid" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name != "Jane Shea" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_multiple_value_node_created_using(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_using == Transaction.CreatedUsing.FullInformation ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_using.in_list([Transaction.CreatedUsing.FullInformation, Transaction.CreatedUsing.Token]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_using == Transaction.CreatedUsing.Token ]) self.assertEqual(0, collection.maximum_size) @raises_with_regexp(AttributeError, "Invalid argument\(s\) for created_using: noSuchCreatedUsing") def test_advanced_search_multiple_value_node_allowed_values_created_using(self): Transaction.search([TransactionSearch.created_using == "noSuchCreatedUsing"]) def test_advanced_search_multiple_value_node_credit_card_customer_location(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_customer_location == CreditCard.CustomerLocation.US ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_customer_location.in_list([CreditCard.CustomerLocation.US, CreditCard.CustomerLocation.International]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_customer_location == CreditCard.CustomerLocation.International ]) self.assertEqual(0, collection.maximum_size) @raises_with_regexp(AttributeError, "Invalid argument\(s\) for credit_card_customer_location: noSuchCreditCardCustomerLocation") def test_advanced_search_multiple_value_node_allowed_values_credit_card_customer_location(self): Transaction.search([ TransactionSearch.credit_card_customer_location == "noSuchCreditCardCustomerLocation" ]) def test_advanced_search_multiple_value_node_merchant_account_id(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.merchant_account_id == transaction.merchant_account_id ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.merchant_account_id.in_list([transaction.merchant_account_id, "bogus_merchant_account_id"]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.merchant_account_id == "bogus_merchant_account_id" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_multiple_value_node_credit_card_card_type(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == transaction.credit_card_details.card_type ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type.in_list([transaction.credit_card_details.card_type, CreditCard.CardType.AmEx]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == CreditCard.CardType.AmEx ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_elo(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.adyen_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Elo, "expiration_date": "10/2020", "cvv": "737", } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == transaction.credit_card_details.card_type ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) self.assertEqual(transaction.credit_card_details.card_type, collection.first.credit_card_details.card_type) def test_advanced_search_hiper(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == transaction.credit_card_details.card_type ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) self.assertEqual(transaction.credit_card_details.card_type, collection.first.credit_card_details.card_type) def test_advanced_search_hipercard(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hipercard, "expiration_date": "10/2020", "cvv": "737", } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == transaction.credit_card_details.card_type ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) self.assertEqual(transaction.credit_card_details.card_type, collection.first.credit_card_details.card_type) @raises_with_regexp(AttributeError, "Invalid argument\(s\) for credit_card_card_type: noSuchCreditCardCardType") def test_advanced_search_multiple_value_node_allowed_values_credit_card_card_type(self): Transaction.search([ TransactionSearch.credit_card_card_type == "noSuchCreditCardCardType" ]) def test_advanced_search_multiple_value_node_status(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.status == Transaction.Status.Authorized ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.status.in_list([Transaction.Status.Authorized, Transaction.Status.Settled]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.status == Transaction.Status.Settled ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_authorization_expired_status(self): collection = Transaction.search( TransactionSearch.status == Transaction.Status.AuthorizationExpired ) self.assertTrue(collection.maximum_size > 0) self.assertEqual(Transaction.Status.AuthorizationExpired, collection.first.status) def test_advanced_search_allows_new_settlement_statuses(self): collection = Transaction.search([ TransactionSearch.status.in_list(["settlement_confirmed", "settlement_declined"]) ]) print(collection) @raises_with_regexp(AttributeError, "Invalid argument\(s\) for status: noSuchStatus") def test_advanced_search_multiple_value_node_allowed_values_status(self): Transaction.search([TransactionSearch.status == "noSuchStatus"]) def test_advanced_search_multiple_value_node_source(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.source == Transaction.Source.Api ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.source.in_list([Transaction.Source.Api, Transaction.Source.ControlPanel]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.source == Transaction.Source.ControlPanel ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_multiple_value_node_type(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.type == Transaction.Type.Sale ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.type.in_list([Transaction.Type.Sale, Transaction.Type.Credit]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.type == Transaction.Type.Credit ]) self.assertEqual(0, collection.maximum_size) @raises_with_regexp(AttributeError, "Invalid argument\(s\) for type: noSuchType") def test_advanced_search_multiple_value_node_allowed_values_type(self): Transaction.search([ TransactionSearch.type == "noSuchType" ]) def test_advanced_search_multiple_value_node_type_with_refund(self): name = "Anabel Atkins%s" % random.randint(1, 100000) sale = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name }, 'options': { 'submit_for_settlement': True } }).transaction TestHelper.settle_transaction(sale.id) refund = Transaction.refund(sale.id).transaction credit = Transaction.credit({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009", "cardholder_name": name } }).transaction collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.type == Transaction.Type.Credit ]) self.assertEqual(2, collection.maximum_size) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.type == Transaction.Type.Credit, TransactionSearch.refund == True ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(refund.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.type == Transaction.Type.Credit, TransactionSearch.refund == False ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(credit.id, collection.first.id) def test_advanced_search_range_node_amount(self): name = "Henrietta Livingston%s" % random.randint(1, 100000) t_1000 = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction t_1500 = Transaction.sale({ "amount": "1500.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction t_1800 = Transaction.sale({ "amount": "1800.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount >= "1700" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1800.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount <= "1250" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1000.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.between("1100", "1600") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1500.id, collection.first.id) def test_advanced_search_range_node_created_at_less_than_or_equal_to(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = transaction.created_at - timedelta(minutes=10) now = transaction.created_at future = transaction.created_at + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at <= past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at <= now ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at <= future ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_range_node_created_at_greater_than_or_equal_to(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = transaction.created_at - timedelta(minutes=10) now = transaction.created_at future = transaction.created_at + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at >= past ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at >= now ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at >= future ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_created_at_between(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = transaction.created_at - timedelta(minutes=10) now = transaction.created_at future = transaction.created_at + timedelta(minutes=10) future2 = transaction.created_at + timedelta(minutes=20) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(past, now) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(now, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_created_at_is(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = transaction.created_at - timedelta(minutes=10) now = transaction.created_at future = transaction.created_at + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at == past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at == now ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at == future ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_created_with_dates(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_range_node_disbursement_date_less_than_or_equal_to(self): transaction_id = "deposittransaction" disbursement_time = datetime(2013, 4, 10, 0, 0, 0) past = disbursement_time - timedelta(minutes=10) future = disbursement_time + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date <= past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date <= disbursement_time ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date <= future ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) def test_advanced_search_range_node_disbursement_date_greater_than_or_equal_to(self): transaction_id = "deposittransaction" disbursement_time = datetime(2013, 4, 10, 0, 0, 0) past = disbursement_time - timedelta(minutes=10) future = disbursement_time + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date >= past ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date >= disbursement_time ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date >= future ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_disbursement_date_between(self): transaction_id = "deposittransaction" disbursement_time = datetime(2013, 4, 10, 0, 0, 0) past = disbursement_time - timedelta(days=1) future = disbursement_time + timedelta(days=1) future2 = disbursement_time + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(past, disbursement_time) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(disbursement_time, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_disbursement_date_is(self): transaction_id = "deposittransaction" disbursement_time = datetime(2013, 4, 10, 0, 0, 0) past = disbursement_time - timedelta(days=10) now = disbursement_time future = disbursement_time + timedelta(days=10) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date == past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date == now ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date == future ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_disbursement_date_with_dates(self): transaction_id = "deposittransaction" disbursement_date = date(2013, 4, 10) past = disbursement_date - timedelta(days=1) future = disbursement_date + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) def test_advanced_search_range_node_disputed_date_less_than_or_equal_to(self): disputed_transaction_id = TestHelper.create_disputed_transaction().id disputed_time = datetime.now() past = disputed_time - timedelta(days=1) future = disputed_time + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date <= past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date <= disputed_time ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date <= future ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) def test_advanced_search_range_node_disputed_date_greater_than_or_equal_to(self): disputed_transaction_id = TestHelper.create_disputed_transaction().id disputed_time = datetime.now() past = disputed_time - timedelta(minutes=10) future = disputed_time + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date >= past ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date >= disputed_time ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date >= future ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_disputed_date_between(self): disputed_transaction_id = TestHelper.create_disputed_transaction().id disputed_time = datetime.now() past = disputed_time - timedelta(days=1) future = disputed_time + timedelta(days=1) future2 = disputed_time + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date.between(past, disputed_time) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date.between(disputed_time, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_disputed_date_is(self): disputed_transaction_id = TestHelper.create_disputed_transaction().id disputed_date = datetime.today() past = disputed_date - timedelta(days=10) future = disputed_date + timedelta(days=10) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date == past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date == future ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date == disputed_date ]) self.assertEqual(1, collection.maximum_size) def test_advanced_search_range_node_disputed_date_with_dates(self): disputed_transaction_id = TestHelper.create_disputed_transaction().id disputed_date = datetime.today() past = disputed_date - timedelta(days=1) future = disputed_date + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) def test_advanced_search_range_node_authorization_expired_at(self): two_days_ago = datetime.today() - timedelta(days=2) yesterday = datetime.today() - timedelta(days=1) tomorrow = datetime.today() + timedelta(days=1) collection = Transaction.search( TransactionSearch.authorization_expired_at.between(two_days_ago, yesterday) ) self.assertEqual(0, collection.maximum_size) collection = Transaction.search( TransactionSearch.authorization_expired_at.between(yesterday, tomorrow) ) self.assertTrue(collection.maximum_size > 0) self.assertEqual(Transaction.Status.AuthorizationExpired, collection.first.status) def test_advanced_search_range_node_authorized_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_failed_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Fail, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.failed_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.failed_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_gateway_rejected_at(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cvv": "200" } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.gateway_rejected_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.gateway_rejected_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_advanced_search_range_node_processor_declined_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Decline, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.processor_declined_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.processor_declined_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_settled_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" }, "options": { "submit_for_settlement": True } }).transaction TestHelper.settle_transaction(transaction.id) transaction = Transaction.find(transaction.id) past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.settled_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.settled_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_submitted_for_settlement_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" }, "options": { "submit_for_settlement": True } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.submitted_for_settlement_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.submitted_for_settlement_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_voided_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction transaction = Transaction.void(transaction.id).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.voided_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.voided_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_can_search_on_multiple_statuses(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" }, "options": { "submit_for_settlement": True } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(past, future), TransactionSearch.submitted_for_settlement_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(future, future2), TransactionSearch.submitted_for_settlement_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(past, future), TransactionSearch.voided_at.between(past, future) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_returns_iteratable_results(self): collection = Transaction.search([ TransactionSearch.credit_card_number.starts_with("411") ]) self.assertTrue(collection.maximum_size > 100) transaction_ids = [transaction.id for transaction in collection.items] self.assertEqual(collection.maximum_size, len(TestHelper.unique(transaction_ids))) def test_advanced_search_can_search_on_paypal_fields(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "access_token": "PAYPAL-ACCESS-TOKEN", "options": {"validate": False} }) self.assertEqual(202, status_code) transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": nonce }).transaction collection = Transaction.search([ TransactionSearch.paypal_payer_email == transaction.paypal_details.payer_email, TransactionSearch.paypal_authorization_id == transaction.paypal_details.authorization_id, TransactionSearch.paypal_payment_id == transaction.paypal_details.payment_id, ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) @raises(DownForMaintenanceError) def test_search_handles_a_search_timeout(self): Transaction.search([ TransactionSearch.amount.between("-1100", "1600") ]) braintree_python-3.57.1/tests/integration/test_oauth.py0000644000175000017500000001563713545202423021517 0ustar hlehlefrom tests.test_helper import * from braintree.test.nonces import Nonces import sys if sys.version_info[0] == 2: import urlparse else: import urllib.parse as urlparse class TestOAuthGateway(unittest.TestCase): def setUp(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) def test_create_token_from_code(self): code = TestHelper.create_grant(self.gateway, { "merchant_public_id": "integration_merchant_id", "scope": "read_write" }) result = self.gateway.oauth.create_token_from_code({ "code": code }) self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.refresh_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) def test_create_token_from_code_with_bad_parameters(self): result = self.gateway.oauth.create_token_from_code({ "code": "bad_code", "scope": "read_write" }) self.assertFalse(result.is_success) self.assertIn(result.message, "Invalid grant: code not found") credentials_code_errors = result.errors.for_object("credentials").on("code") self.assertEqual(1, len(credentials_code_errors)) self.assertEqual(ErrorCodes.OAuth.InvalidGrant, credentials_code_errors[0].code) def test_create_token_from_code_returns_helpful_error_with_bad_credentials(self): gateway = BraintreeGateway( access_token="access_token$development$integration_merchant_id$fb27c79dd", ) with self.assertRaises(ConfigurationError) as error: gateway.oauth.create_token_from_code({ "code": "some_code", "scope": "read_write" }) config_error = error.exception self.assertIn("client_id and client_secret are required", str(config_error)) def test_create_token_from_refresh_token(self): code = TestHelper.create_grant(self.gateway, { "merchant_public_id": "integration_merchant_id", "scope": "read_write" }) refresh_token = self.gateway.oauth.create_token_from_code({ "code": code, "scope": "read_write" }).credentials.refresh_token result = self.gateway.oauth.create_token_from_refresh_token({ "refresh_token": refresh_token }) self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.refresh_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) def test_revoke_access_token(self): code = TestHelper.create_grant(self.gateway, { "merchant_public_id": "integration_merchant_id", "scope": "read_write" }) access_token = self.gateway.oauth.create_token_from_code({ "code": code, "scope": "read_write" }).credentials.access_token result = self.gateway.oauth.revoke_access_token(access_token) self.assertTrue(result.is_success) with self.assertRaises(AuthenticationError): gateway = BraintreeGateway(access_token=access_token) gateway.customer.create() def test_connect_url(self): connect_url = self.gateway.oauth.connect_url({ "merchant_id": "integration_merchant_id", "redirect_uri": "http://bar.example.com", "scope": "read_write", "state": "baz_state", "landing_page": "login", "login_only": "true", "user": { "country": "USA", "email": "foo@example.com", "first_name": "Bob", "last_name": "Jones", "phone": "555-555-5555", "dob_year": "1970", "dob_month": "01", "dob_day": "01", "street_address": "222 W Merchandise Mart", "locality": "Chicago", "region": "IL", "postal_code": "60606" }, "business": { "name": "14 Ladders", "registered_as": "14.0 Ladders", "industry": "Ladders", "description": "We sell the best ladders", "street_address": "111 N Canal", "locality": "Chicago", "region": "IL", "postal_code": "60606", "country": "USA", "annual_volume_amount": "1000000", "average_transaction_amount": "100", "maximum_transaction_amount": "10000", "ship_physical_goods": "true", "fulfillment_completed_in": 7, "currency": "USD", "website": "http://example.com" }, "payment_methods": ["credit_card", "paypal"] }) query_string = urlparse.urlparse(connect_url)[4] params = urlparse.parse_qs(query_string) self.assertEqual(params["merchant_id"], ["integration_merchant_id"]) self.assertEqual(params["client_id"], ["client_id$development$integration_client_id"]) self.assertEqual(params["redirect_uri"], ["http://bar.example.com"]) self.assertEqual(params["scope"], ["read_write"]) self.assertEqual(params["state"], ["baz_state"]) self.assertEqual(params["landing_page"], ["login"]) self.assertEqual(params["login_only"], ["true"]) self.assertEqual(params["user[country]"], ["USA"]) self.assertEqual(params["business[name]"], ["14 Ladders"]) self.assertEqual(params["payment_methods[]"], ["credit_card", "paypal"]) def test_connect_url_limits_payment_methods(self): connect_url = self.gateway.oauth.connect_url({ "merchant_id": "integration_merchant_id", "redirect_uri": "http://bar.example.com", "scope": "read_write", "state": "baz_state", "payment_methods": ["credit_card"] }) query_string = urlparse.urlparse(connect_url)[4] params = urlparse.parse_qs(query_string) self.assertEqual(params["merchant_id"], ["integration_merchant_id"]) self.assertEqual(params["client_id"], ["client_id$development$integration_client_id"]) self.assertEqual(params["redirect_uri"], ["http://bar.example.com"]) self.assertEqual(params["payment_methods[]"], ["credit_card"]) def test_connect_url_doesnt_modify_options(self): options = {"payment_methods": ["credit_card"]} connect_url = self.gateway.oauth.connect_url(options) self.assertEqual(options, {"payment_methods": ["credit_card"]}) braintree_python-3.57.1/tests/integration/test_masterpass.py0000644000175000017500000001057113545202423022551 0ustar hlehlefrom tests.test_helper import * class TestMasterpass(unittest.TestCase): def test_create_from_nonce(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.MasterpassVisa }) self.assertTrue(result.is_success) masterpass_card = result.payment_method self.assertIsNotNone(masterpass_card.billing_address) self.assertIsNotNone(masterpass_card.bin) self.assertIsNotNone(masterpass_card.card_type) self.assertIsNotNone(masterpass_card.cardholder_name) self.assertIsNotNone(masterpass_card.commercial) self.assertIsNotNone(masterpass_card.country_of_issuance) self.assertIsNotNone(masterpass_card.created_at) self.assertIsNotNone(masterpass_card.customer_id) self.assertIsNotNone(masterpass_card.customer_location) self.assertIsNotNone(masterpass_card.debit) self.assertIsNotNone(masterpass_card.default) self.assertIsNotNone(masterpass_card.durbin_regulated) self.assertIsNotNone(masterpass_card.expiration_date) self.assertIsNotNone(masterpass_card.expiration_month) self.assertIsNotNone(masterpass_card.expiration_year) self.assertIsNotNone(masterpass_card.expired) self.assertIsNotNone(masterpass_card.healthcare) self.assertIsNotNone(masterpass_card.image_url) self.assertIsNotNone(masterpass_card.issuing_bank) self.assertIsNotNone(masterpass_card.last_4) self.assertIsNotNone(masterpass_card.masked_number) self.assertIsNotNone(masterpass_card.payroll) self.assertIsNotNone(masterpass_card.prepaid) self.assertIsNotNone(masterpass_card.product_id) self.assertIsNotNone(masterpass_card.subscriptions) self.assertIsNotNone(masterpass_card.token) self.assertIsNotNone(masterpass_card.unique_number_identifier) self.assertIsNotNone(masterpass_card.updated_at) customer = Customer.find(customer.id) self.assertEqual(len(customer.masterpass_cards), 1) self.assertEqual(result.payment_method.token, customer.masterpass_cards[0].token) def test_search_for_transaction(self): result = Transaction.sale({ "payment_method_nonce": Nonces.MasterpassVisa, "amount": "1.23" }) self.assertTrue(result.is_success) transaction = result.transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == PaymentInstrumentType.MasterpassCard ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_create_transaction_from_nonce_and_vault(self): customer = Customer.create().customer result = Transaction.sale({ "payment_method_nonce": Nonces.MasterpassVisa, "customer_id": customer.id, "amount": "1.23", "options": { "store_in_vault": "true" } }) self.assertTrue(result.is_success) masterpass_card_details = result.transaction.masterpass_card_details self.assertIsNotNone(masterpass_card_details.bin) self.assertIsNotNone(masterpass_card_details.card_type) self.assertIsNotNone(masterpass_card_details.cardholder_name) self.assertIsNotNone(masterpass_card_details.commercial) self.assertIsNotNone(masterpass_card_details.country_of_issuance) self.assertIsNotNone(masterpass_card_details.debit) self.assertIsNotNone(masterpass_card_details.durbin_regulated) self.assertIsNotNone(masterpass_card_details.expiration_date) self.assertIsNotNone(masterpass_card_details.expiration_year) self.assertIsNotNone(masterpass_card_details.expiration_month) self.assertIsNotNone(masterpass_card_details.healthcare) self.assertIsNotNone(masterpass_card_details.image_url) self.assertIsNotNone(masterpass_card_details.issuing_bank) self.assertIsNotNone(masterpass_card_details.last_4) self.assertIsNotNone(masterpass_card_details.payroll) self.assertIsNotNone(masterpass_card_details.prepaid) self.assertIsNotNone(masterpass_card_details.product_id) self.assertIsNotNone(masterpass_card_details.token) braintree_python-3.57.1/tests/integration/test_braintree_gateway.py0000644000175000017500000000461613545202423024066 0ustar hlehlefrom unittest import TestCase from braintree.braintree_gateway import BraintreeGateway from braintree.configuration import Configuration from braintree.environment import Environment class TestBraintreeGateway(TestCase): @staticmethod def get_gateway(): config = Configuration("development", "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key") return BraintreeGateway(config) def test_can_make_tokenize_credit_card_via_graphql(self): definition = """ mutation ExampleServerSideSingleUseToken($input: TokenizeCreditCardInput!) { tokenizeCreditCard(input: $input) { paymentMethod { id usage details { ... on CreditCardDetails { bin brandCode last4 expirationYear expirationMonth } } } } } """ variables = { "input" : { "creditCard" : { "number" : "4005519200000004", "expirationYear": "2024", "expirationMonth": "05", "cardholderName": "Joe Bloggs" } } } gateway = self.get_gateway() response = gateway.graphql_client.query(definition, variables) payment_method = response["data"]["tokenizeCreditCard"]["paymentMethod"] details = payment_method["details"] self.assertTrue("data" in response) self.assertTrue("id" in payment_method) self.assertEqual(details["bin"], "400551") self.assertEqual(details["last4"], "0004"); self.assertEqual(details["brandCode"], "VISA"); self.assertEqual(details["expirationMonth"], "05"); self.assertEqual(details["expirationYear"], "2024"); def test_can_make_graphql_queries_without_variables(self): definition = """ query { ping } """ gateway = self.get_gateway() response = gateway.graphql_client.query(definition) self.assertTrue("data" in response) self.assertTrue("ping" in response["data"]) self.assertEqual("pong", response["data"]["ping"]) braintree_python-3.57.1/tests/integration/test_payment_method_us_bank_account.py0000644000175000017500000002525013545202423026622 0ustar hlehlefrom tests.test_helper import * from braintree.us_bank_account_verification import UsBankAccountVerification class PaymentMethodWithUsBankAccountTest(unittest.TestCase): def test_create_with_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertIsInstance(us_bank_account, UsBankAccount) self.assertEqual(us_bank_account.routing_number, "021000021") self.assertEqual(us_bank_account.last_4, "1234") self.assertEqual(us_bank_account.account_type, "checking") self.assertEqual(us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", us_bank_account.bank_name)) self.assertEqual(us_bank_account.default, True) self.assertEqual(us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(us_bank_account.ach_mandate.accepted_at, datetime) self.assertEqual(us_bank_account.verified, True) self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, "verified") self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.IndependentCheck) def test_create_with_verification(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce("021000021", "1000000000"), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck, } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertIsInstance(us_bank_account, UsBankAccount) self.assertEqual(us_bank_account.routing_number, "021000021") self.assertEqual(us_bank_account.last_4, "0000") self.assertEqual(us_bank_account.account_type, "checking") self.assertEqual(us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", us_bank_account.bank_name)) self.assertEqual(us_bank_account.default, True) self.assertEqual(us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(us_bank_account.ach_mandate.accepted_at, datetime) self.assertEqual(us_bank_account.verified, True) self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.NetworkCheck) def test_create_fails_with_invalid_us_bank_account_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_invalid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } }) self.assertFalse(result.is_success) error_code = result.errors.for_object("payment_method").on("payment_method_nonce")[0].code self.assertEqual(ErrorCodes.PaymentMethod.PaymentMethodNonceUnknown, error_code) def test_update_payment_method_with_verification(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce("021000021", "1000000000"), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.IndependentCheck) result = PaymentMethod.update(us_bank_account.token, { "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck, } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertEqual(len(us_bank_account.verifications), 2) class PaymentMethodWithUsBankAccountCompliantMerchantTest(unittest.TestCase): def setUp(self): braintree.Configuration.configure( braintree.Environment.Development, "integration2_merchant_id", "integration2_public_key", "integration2_private_key" ) def tearDown(self): braintree.Configuration.configure( braintree.Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) def test_create_with_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertIsInstance(us_bank_account, UsBankAccount) self.assertEqual(us_bank_account.routing_number, "021000021") self.assertEqual(us_bank_account.last_4, "1234") self.assertEqual(us_bank_account.account_type, "checking") self.assertEqual(us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", us_bank_account.bank_name)) self.assertEqual(us_bank_account.default, True) self.assertEqual(us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(us_bank_account.ach_mandate.accepted_at, datetime) self.assertEqual(us_bank_account.verified, False) self.assertEqual(len(us_bank_account.verifications), 0) def test_create_with_verification(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce("021000021", "1000000000"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertIsInstance(us_bank_account, UsBankAccount) self.assertEqual(us_bank_account.routing_number, "021000021") self.assertEqual(us_bank_account.last_4, "0000") self.assertEqual(us_bank_account.account_type, "checking") self.assertEqual(us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", us_bank_account.bank_name)) self.assertEqual(us_bank_account.default, True) self.assertEqual(us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(us_bank_account.ach_mandate.accepted_at, datetime) self.assertEqual(us_bank_account.verified, True) self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) def test_create_fails_with_invalid_us_bank_account_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_invalid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck, } }) self.assertFalse(result.is_success) error_code = result.errors.for_object("payment_method").on("payment_method_nonce")[0].code self.assertEqual(ErrorCodes.PaymentMethod.PaymentMethodNonceUnknown, error_code) def test_update_payment_method_with_verification(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce("021000021", "1000000000"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.IndependentCheck } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.IndependentCheck) result = PaymentMethod.update(us_bank_account.token, { "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck, } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertEqual(len(us_bank_account.verifications), 2) braintree_python-3.57.1/tests/integration/test_credit_card_verification_search.py0000644000175000017500000001324613545202423026723 0ustar hlehlefrom tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestVerificationSearch(unittest.TestCase): def test_advanced_search_no_results(self): collection = CreditCardVerification.search([ CreditCardVerificationSearch.credit_card_cardholder_name == "no such person"]) self.assertEqual(0, collection.maximum_size) def test_search_on_verification_id(self): customer_id = "%s" % random.randint(1, 10000) result = Customer.create({ "id": customer_id, "credit_card": { "expiration_date": "10/2018", "number": CreditCardNumbers.FailsSandboxVerification.Visa, "options": { "verify_card": True } } }) verification_id = result.credit_card_verification.id found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.id == verification_id ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(verification_id, found_verifications.first.id) def test_all_text_fields(self): email = "mark.a@example.com" cardholder_name = "Tom %s" % random.randint(1, 10000) customer_id = "%s" % random.randint(1, 10000) expiration_date = "10/2012" number = CreditCardNumbers.MasterCard postal_code = "44444" customer = Customer.create({ "id": customer_id, "email": email, "credit_card": { "cardholder_name": cardholder_name, "expiration_date": expiration_date, "number": number, "billing_address": { "postal_code": postal_code }, "options": { "verify_card": True } } }).customer found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.credit_card_expiration_date == expiration_date, CreditCardVerificationSearch.credit_card_cardholder_name == cardholder_name, CreditCardVerificationSearch.credit_card_number == number, CreditCardVerificationSearch.customer_email == email, CreditCardVerificationSearch.customer_id == customer_id, CreditCardVerificationSearch.billing_postal_code == postal_code ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(customer.credit_cards[0].token, found_verifications.first.credit_card["token"]) def test_multiple_value_fields(self): cardholder_name = "Tom %s" % random.randint(1, 10000) number = CreditCardNumbers.FailsSandboxVerification.MasterCard unsuccessful_result1 = Customer.create({"credit_card": { "cardholder_name": cardholder_name, "expiration_date": "10/2013", "number": number, "options": {"verify_card": True} }}) cardholder_name = "Tom %s" % random.randint(1, 10000) number = CreditCardNumbers.FailsSandboxVerification.Visa unsuccessful_result2 = Customer.create({"credit_card": { "cardholder_name": cardholder_name, "expiration_date": "10/2012", "number": number, "options": {"verify_card": True} }}) verification1 = unsuccessful_result1.credit_card_verification verification2 = unsuccessful_result2.credit_card_verification search_results = CreditCardVerification.search( CreditCardVerificationSearch.ids.in_list([ verification1.id, verification2.id]), CreditCardVerificationSearch.credit_card_card_type.in_list([ verification1.credit_card["card_type"], verification2.credit_card["card_type"]]), CreditCardVerificationSearch.status.in_list([ verification1.status, verification2.status]) ) self.assertEqual(2, search_results.maximum_size) def test_range_field(self): cardholder_name = "Tom %s" % random.randint(1, 10000) number = CreditCardNumbers.FailsSandboxVerification.MasterCard unsuccessful_result = Customer.create({"credit_card": { "cardholder_name": cardholder_name, "expiration_date": "10/2013", "number": number, "options": {"verify_card": True} }}) created_verification = unsuccessful_result.credit_card_verification created_time = created_verification.created_at before_creation = created_time - timedelta(minutes=10) after_creation = created_time + timedelta(minutes=10) found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.id == created_verification.id, CreditCardVerificationSearch.created_at.between(before_creation, after_creation)) self.assertEqual(1, found_verifications.maximum_size) way_before_creation = created_time - timedelta(minutes=10) just_before_creation = created_time - timedelta(minutes=1) found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.id == created_verification.id, CreditCardVerificationSearch.created_at.between(way_before_creation, just_before_creation)) self.assertEqual(0, found_verifications.maximum_size) found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.id == created_verification.id, CreditCardVerificationSearch.created_at == created_time) self.assertEqual(1, found_verifications.maximum_size) braintree_python-3.57.1/tests/integration/test_customer_search.py0000644000175000017500000001252413545202423023555 0ustar hlehlefrom tests.test_helper import * class TestCustomerSearch(unittest.TestCase): def test_advanced_search_no_results(self): collection = Transaction.search([ TransactionSearch.billing_first_name == "no_such_person" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_finds_duplicate_cards_given_payment_method_token(self): credit_card_dict = { "number": "63049580000009", "expiration_date": "05/2010" } jim_dict = { "first_name": "Jim", "credit_card": credit_card_dict } joe_dict = { "first_name": "Joe", "credit_card": credit_card_dict } jim = Customer.create(jim_dict).customer joe = Customer.create(joe_dict).customer collection = Customer.search( CustomerSearch.payment_method_token_with_duplicates == jim.credit_cards[0].token, ) customer_ids = [customer.id for customer in collection.items] self.assertTrue(jim.id in customer_ids) self.assertTrue(joe.id in customer_ids) def test_advanced_search_searches_all_text_fields(self): token = "creditcard%s" % random.randint(1, 100000) customer = Customer.create({ "first_name": "Timmy", "last_name": "O'Toole", "company": "O'Toole and Son(s)", "email": "timmy@example.com", "fax": "3145551234", "phone": "5551231234", "website": "http://example.com", "credit_card": { "cardholder_name": "Tim Toole", "number": "4111111111111111", "expiration_date": "05/2010", "token": token, "billing_address": { "first_name": "Thomas", "last_name": "Otool", "street_address": "1 E Main St", "extended_address": "Suite 3", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America" } } }).customer search_criteria = { "first_name": "Timmy", "last_name": "O'Toole", "company": "O'Toole and Son(s)", "email": "timmy@example.com", "phone": "5551231234", "fax": "3145551234", "website": "http://example.com", "address_first_name": "Thomas", "address_last_name": "Otool", "address_street_address": "1 E Main St", "address_postal_code": "60622", "address_extended_address": "Suite 3", "address_locality": "Chicago", "address_region": "Illinois", "address_country_name": "United States of America", "payment_method_token": token, "cardholder_name": "Tim Toole", "credit_card_number": "4111111111111111", "credit_card_expiration_date": "05/2010" } criteria = [getattr(CustomerSearch, search_field) == value for search_field, value in search_criteria.items()] criteria.append(CustomerSearch.id == customer.id) collection = Customer.search(criteria) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) for search_field, value in search_criteria.items(): collection = Customer.search( CustomerSearch.id == customer.id, getattr(CustomerSearch, search_field) == value ) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) def test_advanced_search_range_node_created_at(self): customer = Customer.create().customer past = customer.created_at - timedelta(minutes=10) future = customer.created_at + timedelta(minutes=10) collection = Customer.search( CustomerSearch.id == customer.id, CustomerSearch.created_at.between(past, future) ) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) collection = Customer.search( CustomerSearch.id == customer.id, CustomerSearch.created_at <= future ) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) collection = Customer.search( CustomerSearch.id == customer.id, CustomerSearch.created_at >= past ) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) def test_search_on_paypal_account_email(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "options": {"validate": False} }) self.assertEqual(202, status_code) customer = Customer.create({"payment_method_nonce": nonce}).customer collection = Customer.search( CustomerSearch.paypal_account_email == "jane.doe@example.com", CustomerSearch.id == customer.id ) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) braintree_python-3.57.1/tests/integration/test_dispute_search.py0000644000175000017500000001121013545202423023360 0ustar hlehlefrom tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestDisputeSearch(unittest.TestCase): def create_sample_disputed_transaction(self): customer = Customer.create({ "first_name": "Jen", "last_name": "Smith", "company": "Braintree", "email": "jen@example.com", "phone": "312.555.1234", "fax": "614.555.5678", "website": "www.example.com", }).customer return Transaction.sale({ "amount": "100.00", "credit_card": { "number": CreditCardNumbers.Disputes.Chargeback, "expiration_date": "12/2019", }, "customer_id": customer.id, "merchant_account_id": "14LaddersLLC_instant", "options": { "submit_for_settlement": True, }, }).transaction def test_advanced_search_no_results(self): collection = Dispute.search([ DisputeSearch.id == "non_existent_dispute" ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEquals(0, len(disputes)) def test_advanced_search_returns_single_dispute_by_customer_id(self): transaction = self.create_sample_disputed_transaction() collection = Dispute.search([ DisputeSearch.customer_id == transaction.customer_details.id ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEquals(1, len(disputes)) dispute = disputes[0] self.assertEquals(dispute.id, transaction.disputes[0].id) self.assertEquals(dispute.status, Dispute.Status.Open) def test_advanced_search_returns_single_dispute_by_id(self): collection = Dispute.search([ DisputeSearch.id == "open_dispute" ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEquals(1, len(disputes)) dispute = disputes[0] self.assertEquals(dispute.id, "open_dispute") self.assertEquals(dispute.status, Dispute.Status.Open) def test_advanced_search_returns_disputes_by_multiple_reasons(self): collection = Dispute.search([ DisputeSearch.reason.in_list([ braintree.Dispute.Reason.ProductUnsatisfactory, braintree.Dispute.Reason.Retrieval ]) ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEquals(2, len(disputes)) def test_advanced_search_returns_disputes_by_date_range(self): collection = Dispute.search([ DisputeSearch.received_date.between("03/03/2014", "03/05/2014") ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEquals(1, len(disputes)) self.assertEquals(disputes[0].received_date, date(2014, 3, 4)) def test_advanced_search_returns_disputes_by_disbursement_date_range(self): transaction = self.create_sample_disputed_transaction() disbursement_date = transaction.disputes[0].status_history[0].disbursement_date collection = Dispute.search([ DisputeSearch.disbursement_date.between(disbursement_date, disbursement_date) ]) disputes = [dispute for dispute in collection.disputes.items] self.assertGreaterEqual(len(disputes), 1) self.assertEquals(disputes[0].status_history[0].disbursement_date, disbursement_date) def test_advanced_search_returns_disputes_by_effective_date_range(self): transaction = self.create_sample_disputed_transaction() effective_date = transaction.disputes[0].status_history[0].effective_date collection = Dispute.search([ DisputeSearch.effective_date.between(effective_date, effective_date) ]) disputes = [dispute for dispute in collection.disputes.items] self.assertGreaterEqual(len(disputes), 1) self.assertEquals(disputes[0].status_history[0].effective_date, effective_date) def test_advanced_search_returns_disputes_by_amount_and_status(self): collection = Dispute.search([ DisputeSearch.amount_disputed.between("1.00", "100.00"), DisputeSearch.id == "open_dispute" ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEquals(1, len(disputes)) def test_advanced_search_can_take_one_criteria(self): collection = Dispute.search( DisputeSearch.id == "non_existent_dispute" ) disputes = [dispute for dispute in collection.disputes.items] self.assertEquals(0, len(disputes)) braintree_python-3.57.1/tests/integration/test_add_ons.py0000644000175000017500000000227613545202423022001 0ustar hlehlefrom tests.test_helper import * class TestAddOn(unittest.TestCase): def test_all_returns_all_add_ons(self): new_id = str(random.randint(1, 1000000)) attributes = { "amount": "100.00", "description": "some description", "id": new_id, "kind": "add_on", "name": "python_add_on", "never_expires": False, "number_of_billing_cycles": 1 } Configuration.instantiate().http().post(Configuration.instantiate().base_merchant_path() + "/modifications/create_modification_for_tests", {"modification": attributes}) add_ons = AddOn.all() for add_on in add_ons: if add_on.id == new_id: break else: add_on = None self.assertNotEqual(None, add_on) self.assertEqual(Decimal("100.00"), add_on.amount) self.assertEqual("some description", add_on.description) self.assertEqual(new_id, add_on.id) self.assertEqual("add_on", add_on.kind) self.assertEqual("python_add_on", add_on.name) self.assertEqual(False, add_on.never_expires) self.assertEqual(add_on.number_of_billing_cycles, 1) braintree_python-3.57.1/tests/integration/test_address.py0000644000175000017500000001624413545202423022017 0ustar hlehlefrom tests.test_helper import * class TestAddress(unittest.TestCase): def test_create_returns_successful_result_if_valid(self): customer = Customer.create().customer result = Address.create({ "customer_id": customer.id, "first_name": "Ben", "last_name": "Moore", "company": "Moore Co.", "street_address": "1811 E Main St", "extended_address": "Suite 200", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America", "country_code_alpha2": "US", "country_code_alpha3": "USA", "country_code_numeric": "840" }) self.assertTrue(result.is_success) address = result.address self.assertEqual(customer.id, address.customer_id) self.assertEqual("Ben", address.first_name) self.assertEqual("Moore", address.last_name) self.assertEqual("Moore Co.", address.company) self.assertEqual("1811 E Main St", address.street_address) self.assertEqual("Suite 200", address.extended_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60622", address.postal_code) self.assertEqual("US", address.country_code_alpha2) self.assertEqual("USA", address.country_code_alpha3) self.assertEqual("840", address.country_code_numeric) self.assertEqual("United States of America", address.country_name) def test_error_response_if_invalid(self): customer = Customer.create().customer result = Address.create({ "customer_id": customer.id, "country_name": "zzzzzz", "country_code_alpha2": "zz", "country_code_alpha3": "zzz", "country_code_numeric": "000" }) self.assertFalse(result.is_success) country_name_errors = result.errors.for_object("address").on("country_name") self.assertEqual(1, len(country_name_errors)) self.assertEqual(ErrorCodes.Address.CountryNameIsNotAccepted, country_name_errors[0].code) country_code_alpha2_errors = result.errors.for_object("address").on("country_code_alpha2") self.assertEqual(1, len(country_code_alpha2_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, country_code_alpha2_errors[0].code) country_code_alpha3_errors = result.errors.for_object("address").on("country_code_alpha3") self.assertEqual(1, len(country_code_alpha3_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha3IsNotAccepted, country_code_alpha3_errors[0].code) country_code_numeric_errors = result.errors.for_object("address").on("country_code_numeric") self.assertEqual(1, len(country_code_numeric_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeNumericIsNotAccepted, country_code_numeric_errors[0].code) def test_error_response_if_inconsistent_country(self): customer = Customer.create().customer result = Address.create({ "customer_id": customer.id, "country_code_alpha2": "US", "country_code_alpha3": "MEX" }) self.assertFalse(result.is_success) address_errors = result.errors.for_object("address").on("base") self.assertEqual(1, len(address_errors)) self.assertEqual(ErrorCodes.Address.InconsistentCountry, address_errors[0].code) def test_delete_with_valid_customer_id_and_address_id(self): customer = Customer.create().customer address = Address.create({"customer_id": customer.id, "street_address": "123 Main St."}).address result = Address.delete(customer.id, address.id) self.assertTrue(result.is_success) @raises(NotFoundError) def test_delete_with_valid_customer_id_and_non_existing_address(self): customer = Customer.create().customer Address.delete(customer.id, "notreal") def test_find_with_valid_customer_id_and_address_id(self): customer = Customer.create().customer address = Address.create({"customer_id": customer.id, "street_address": "123 Main St."}).address found_address = Address.find(customer.id, address.id) self.assertEqual(address.street_address, found_address.street_address) @raises_with_regexp(NotFoundError, "address for customer 'notreal' with id 'badaddress' not found") def test_find_with_invalid_customer_id_and_address_id(self): Address.find("notreal", "badaddress") def test_update_with_valid_values(self): customer = Customer.create().customer address = Address.create({ "customer_id": customer.id, "street_address": "1811 E Main St", "extended_address": "Suite 200", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America" }).address result = Address.update(customer.id, address.id, { "street_address": "123 E New St", "extended_address": "New Suite 3", "locality": "Chicago", "region": "Illinois", "postal_code": "60621", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484", "country_name": "Mexico" }) self.assertTrue(result.is_success) address = result.address self.assertEqual(customer.id, address.customer_id) self.assertEqual("123 E New St", address.street_address) self.assertEqual("New Suite 3", address.extended_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60621", address.postal_code) self.assertEqual("MX", address.country_code_alpha2) self.assertEqual("MEX", address.country_code_alpha3) self.assertEqual("484", address.country_code_numeric) self.assertEqual("Mexico", address.country_name) def test_update_with_invalid_values(self): customer = Customer.create().customer address = Address.create({ "customer_id": customer.id, "street_address": "1811 E Main St", "extended_address": "Suite 200", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America" }).address result = Address.update(customer.id, address.id, { "street_address": "123 E New St", "country_name": "United States of Invalid" }) self.assertFalse(result.is_success) country_name_errors = result.errors.for_object("address").on("country_name") self.assertEqual(1, len(country_name_errors)) self.assertEqual(ErrorCodes.Address.CountryNameIsNotAccepted, country_name_errors[0].code) @raises(NotFoundError) def test_update_raises_not_found_error_if_given_bad_address(self): customer = Customer.create().customer Address.update(customer.id, "notfound", {"street_address": "123 Main St."}) braintree_python-3.57.1/tests/integration/test_document_upload.py0000644000175000017500000001021413545202423023543 0ustar hlehleimport os from nose.exc import SkipTest from tests.test_helper import * from braintree.test.nonces import Nonces class TestDocumentUpload(unittest.TestCase): def setUp(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/bt_logo.png") self.png_file = open(file_path, "rb") def test_create_returns_successful_result_if_valid(self): result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": self.png_file }) self.assertTrue(result.is_success) self.assertTrue(result.document_upload.id != None) self.assertEqual(result.document_upload.content_type, "image/png") self.assertEqual(result.document_upload.kind, braintree.DocumentUpload.Kind.EvidenceDocument) self.assertEqual(result.document_upload.name, "bt_logo.png") self.assertEqual(result.document_upload.size, 2443) def test_create_returns_error_with_unsupported_file_type(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/gif_extension_bt_logo.gif") gif_file = open(file_path, "rb") result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": gif_file }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.FileTypeIsInvalid) def test_create_returns_error_with_malformed_file(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/malformed_pdf.pdf") bad_pdf_file = open(file_path, "rb") result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": bad_pdf_file }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.FileIsMalformedOrEncrypted) def test_create_returns_error_with_invalid_kind(self): result = DocumentUpload.create({ "kind": "invalid_kind", "file": self.png_file }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.KindIsInvalid) def test_create_returns_error_when_file_is_over_4mb(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/large_file.png") try: f = open(file_path, 'w+') for i in range(1048577 * 4): f.write('a') f.close() large_file = open(file_path, 'rb') result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": large_file }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.FileIsTooLarge) finally: os.remove(file_path) def test_create_returns_error_with_malformed_file(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/too_long.pdf") too_long_pdf = open(file_path, "rb") result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": too_long_pdf }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.FileIsTooLong) @raises_with_regexp(KeyError, "'Invalid keys: invalid_key'") def test_create_returns_invalid_keys_errors_with_invalid_signature(self): result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "invalid_key": "do not add" }) @raises_with_regexp(ValueError, "file must be a file handle") def test_create_throws_error_when_not_valid_file(self): result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": "not_a_file" }) @raises_with_regexp(ValueError, "file must be a file handle") def test_create_throws_error_when_none_file(self): result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": None }) braintree_python-3.57.1/tests/integration/test_transaction_line_item.py0000644000175000017500000000217313545202423024740 0ustar hlehlefrom tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestTransactionLineItem(unittest.TestCase): def test_transaction_line_item_find_all_returns_line_items(self): transaction = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "total_amount": "45.15", }] }).transaction line_items = TransactionLineItem.find_all(transaction.id) self.assertEqual(1, len(line_items)) lineItem = line_items[0] self.assertEqual("1.0232", lineItem.quantity) self.assertEqual("Name #1", lineItem.name) self.assertEqual(TransactionLineItem.Kind.Debit, lineItem.kind) self.assertEqual("45.1232", lineItem.unit_amount) self.assertEqual("45.15", lineItem.total_amount) braintree_python-3.57.1/tests/integration/test_visa_checkout.py0000644000175000017500000001224013545202423023211 0ustar hlehlefrom tests.test_helper import * class TestVisaCheckout(unittest.TestCase): def test_create_from_nonce(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.VisaCheckoutVisa }) self.assertTrue(result.is_success) visa_checkout_card = result.payment_method self.assertEqual("abc123", visa_checkout_card.call_id) self.assertIsNotNone(visa_checkout_card.billing_address) self.assertIsNotNone(visa_checkout_card.bin) self.assertIsNotNone(visa_checkout_card.card_type) self.assertIsNotNone(visa_checkout_card.cardholder_name) self.assertIsNotNone(visa_checkout_card.commercial) self.assertIsNotNone(visa_checkout_card.country_of_issuance) self.assertIsNotNone(visa_checkout_card.created_at) self.assertIsNotNone(visa_checkout_card.customer_id) self.assertIsNotNone(visa_checkout_card.customer_location) self.assertIsNotNone(visa_checkout_card.debit) self.assertIsNotNone(visa_checkout_card.default) self.assertIsNotNone(visa_checkout_card.durbin_regulated) self.assertIsNotNone(visa_checkout_card.expiration_date) self.assertIsNotNone(visa_checkout_card.expiration_month) self.assertIsNotNone(visa_checkout_card.expiration_year) self.assertIsNotNone(visa_checkout_card.expired) self.assertIsNotNone(visa_checkout_card.healthcare) self.assertIsNotNone(visa_checkout_card.image_url) self.assertIsNotNone(visa_checkout_card.issuing_bank) self.assertIsNotNone(visa_checkout_card.last_4) self.assertIsNotNone(visa_checkout_card.masked_number) self.assertIsNotNone(visa_checkout_card.payroll) self.assertIsNotNone(visa_checkout_card.prepaid) self.assertIsNotNone(visa_checkout_card.product_id) self.assertIsNotNone(visa_checkout_card.subscriptions) self.assertIsNotNone(visa_checkout_card.token) self.assertIsNotNone(visa_checkout_card.unique_number_identifier) self.assertIsNotNone(visa_checkout_card.updated_at) customer = Customer.find(customer.id) self.assertEqual(len(customer.visa_checkout_cards), 1) self.assertEqual(result.payment_method.token, customer.visa_checkout_cards[0].token) def test_create_with_verification(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.VisaCheckoutVisa, "options": { "verify_card": "true" } }) self.assertTrue(result.is_success) verification = result.payment_method.verification self.assertEqual(CreditCardVerification.Status.Verified, verification.status) def test_search_for_transaction(self): result = Transaction.sale({ "payment_method_nonce": Nonces.VisaCheckoutVisa, "amount": "1.23" }) self.assertTrue(result.is_success) transaction = result.transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == PaymentInstrumentType.VisaCheckoutCard ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_create_transaction_from_nonce_and_vault(self): customer = Customer.create().customer result = Transaction.sale({ "payment_method_nonce": Nonces.VisaCheckoutVisa, "customer_id": customer.id, "amount": "1.23", "options": { "store_in_vault": "true" } }) self.assertTrue(result.is_success) visa_checkout_card_details = result.transaction.visa_checkout_card_details self.assertEqual("abc123", visa_checkout_card_details.call_id) self.assertIsNotNone(visa_checkout_card_details.bin) self.assertIsNotNone(visa_checkout_card_details.card_type) self.assertIsNotNone(visa_checkout_card_details.cardholder_name) self.assertIsNotNone(visa_checkout_card_details.commercial) self.assertIsNotNone(visa_checkout_card_details.country_of_issuance) self.assertIsNotNone(visa_checkout_card_details.debit) self.assertIsNotNone(visa_checkout_card_details.durbin_regulated) self.assertIsNotNone(visa_checkout_card_details.expiration_date) self.assertIsNotNone(visa_checkout_card_details.expiration_year) self.assertIsNotNone(visa_checkout_card_details.expiration_month) self.assertIsNotNone(visa_checkout_card_details.healthcare) self.assertIsNotNone(visa_checkout_card_details.image_url) self.assertIsNotNone(visa_checkout_card_details.issuing_bank) self.assertIsNotNone(visa_checkout_card_details.last_4) self.assertIsNotNone(visa_checkout_card_details.payroll) self.assertIsNotNone(visa_checkout_card_details.prepaid) self.assertIsNotNone(visa_checkout_card_details.product_id) self.assertIsNotNone(visa_checkout_card_details.token) braintree_python-3.57.1/tests/integration/test_coinbase.py0000644000175000017500000000233213545202423022146 0ustar hlehlefrom tests.test_helper import * from braintree.test.nonces import Nonces from braintree.exceptions.not_found_error import NotFoundError from braintree.error_codes import ErrorCodes class TestCoinbase(unittest.TestCase): def test_customer(self): result = Customer.create({"payment_method_nonce": Nonces.Coinbase}) self.assertFalse(result.is_success) self.assertEquals(ErrorCodes.PaymentMethod.PaymentMethodNoLongerSupported, result.errors.for_object("coinbase_account").on("base")[0].code) def test_vault(self): result = Customer.create() result = PaymentMethod.create({ "customer_id": result.customer.id, "payment_method_nonce": Nonces.Coinbase }) self.assertFalse(result.is_success) self.assertEquals(ErrorCodes.PaymentMethod.PaymentMethodNoLongerSupported, result.errors.for_object("coinbase_account").on("base")[0].code) def test_transaction(self): result = Transaction.sale({"payment_method_nonce": Nonces.Coinbase, "amount": "1.00"}) self.assertFalse(result.is_success) self.assertEquals(ErrorCodes.PaymentMethod.PaymentMethodNoLongerSupported, result.errors.for_object("transaction").on("base")[0].code) braintree_python-3.57.1/tests/integration/test_payment_method_nonce.py0000644000175000017500000001455413545202423024573 0ustar hlehlefrom tests.test_helper import * class TestPaymentMethodNonce(unittest.TestCase): def test_create_nonce_from_payment_method(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2014", }) result = PaymentMethodNonce.create(credit_card_result.credit_card.token) self.assertTrue(result.is_success) self.assertNotEqual(None, result.payment_method_nonce) self.assertNotEqual(None, result.payment_method_nonce.nonce) def test_create_raises_not_found_when_404(self): self.assertRaises(NotFoundError, PaymentMethodNonce.create, "not-a-token") def test_find_nonce_shows_details(self): config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key" ) gateway = BraintreeGateway(config) nonce = PaymentMethodNonce.find("fake-valid-visa-nonce") self.assertEqual("401288", nonce.details["bin"]) def test_find_nonce_shows_3ds_details(self): config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key" ) gateway = BraintreeGateway(config) credit_card = { "credit_card": { "number": "4111111111111111", "expiration_month": "12", "expiration_year": "2020" } } nonce = TestHelper.generate_three_d_secure_nonce(gateway, credit_card) found_nonce = PaymentMethodNonce.find(nonce) three_d_secure_info = found_nonce.three_d_secure_info self.assertEqual("CreditCard", found_nonce.type) self.assertEqual(nonce, found_nonce.nonce) self.assertEqual("Y", three_d_secure_info.enrolled) self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertEqual("test_cavv", three_d_secure_info.cavv) self.assertEqual("test_xid", three_d_secure_info.xid) self.assertEqual("test_eci", three_d_secure_info.eci_flag) self.assertEqual("1.0.2", three_d_secure_info.three_d_secure_version) def test_find_nonce_shows_paypal_details(self): found_nonce = PaymentMethodNonce.find("fake-google-pay-paypal-nonce") self.assertNotEqual(None, found_nonce.details["payer_info"]["first_name"]) self.assertNotEqual(None, found_nonce.details["payer_info"]["last_name"]) self.assertNotEqual(None, found_nonce.details["payer_info"]["email"]) self.assertNotEqual(None, found_nonce.details["payer_info"]["payer_id"]) def test_find_nonce_shows_venmo_details(self): found_nonce = PaymentMethodNonce.find("fake-venmo-account-nonce") self.assertEquals("99", found_nonce.details["last_two"]) self.assertEquals("venmojoe", found_nonce.details["username"]) self.assertEquals("Venmo-Joe-1", found_nonce.details["venmo_user_id"]) def test_exposes_null_3ds_info_if_none_exists(self): http = ClientApiHttp.create() _, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "access-token": "access-token", "options": {"validate": False} }) found_nonce = PaymentMethodNonce.find(nonce) self.assertEqual(nonce, found_nonce.nonce) self.assertEqual(None, found_nonce.three_d_secure_info) def test_find_raises_not_found_when_404(self): self.assertRaises(NotFoundError, PaymentMethodNonce.find, "not-a-nonce") def test_bin_data_has_commercial(self): found_nonce = PaymentMethodNonce.find("fake-valid-commercial-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.Commercial.Yes, bin_data.commercial) def test_bin_data_has_country_of_issuance(self): found_nonce = PaymentMethodNonce.find("fake-valid-country-of-issuance-cad-nonce") bin_data = found_nonce.bin_data self.assertEqual("CAN", bin_data.country_of_issuance) def test_bin_data_debit(self): found_nonce = PaymentMethodNonce.find("fake-valid-debit-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.Debit.Yes, bin_data.debit) def test_bin_data_durbin_regulated(self): found_nonce = PaymentMethodNonce.find("fake-valid-durbin-regulated-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.DurbinRegulated.Yes, bin_data.durbin_regulated) def test_bin_data_issuing_bank(self): found_nonce = PaymentMethodNonce.find("fake-valid-issuing-bank-network-only-nonce") bin_data = found_nonce.bin_data self.assertEqual("NETWORK ONLY", bin_data.issuing_bank) def test_bin_data_payroll(self): found_nonce = PaymentMethodNonce.find("fake-valid-payroll-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.Payroll.Yes, bin_data.payroll) def test_bin_data_prepaid(self): found_nonce = PaymentMethodNonce.find("fake-valid-prepaid-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.Prepaid.Yes, bin_data.prepaid) def test_bin_data_unknown_values(self): found_nonce = PaymentMethodNonce.find("fake-valid-unknown-indicators-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.Commercial.Unknown, bin_data.commercial) self.assertEqual(CreditCard.CountryOfIssuance.Unknown, bin_data.country_of_issuance) self.assertEqual(CreditCard.Debit.Unknown, bin_data.debit) self.assertEqual(CreditCard.DurbinRegulated.Unknown, bin_data.durbin_regulated) self.assertEqual(CreditCard.Healthcare.Unknown, bin_data.healthcare) self.assertEqual(CreditCard.IssuingBank.Unknown, bin_data.issuing_bank) self.assertEqual(CreditCard.Payroll.Unknown, bin_data.payroll) self.assertEqual(CreditCard.Prepaid.Unknown, bin_data.prepaid) self.assertEqual(CreditCard.ProductId.Unknown, bin_data.product_id) braintree_python-3.57.1/tests/integration/test_disputes.py0000644000175000017500000003315413545202423022231 0ustar hlehleimport re import time import datetime from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestDisputes(unittest.TestCase): def create_evidence_document(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/bt_logo.png") png_file = open(file_path, "rb") return DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": png_file }).document_upload def create_sample_dispute(self): return Transaction.sale({ "amount": "100.00", "credit_card": { "number": CreditCardNumbers.Disputes.Chargeback, "expiration_date": "12/2019" } }).transaction.disputes[0] def test_accept_changes_dispute_status_to_accepted(self): dispute = self.create_sample_dispute() result = Dispute.accept(dispute.id) self.assertTrue(result.is_success) updated_dispute = Dispute.find(dispute.id) self.assertEqual(updated_dispute.status, Dispute.Status.Accepted) dispute_from_transaction = Transaction.find(dispute.transaction.id).disputes[0] self.assertEqual(dispute_from_transaction.status, Dispute.Status.Accepted) def test_accept_errors_when_dispute_not_open(self): result = Dispute.accept("wells_dispute") self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyAcceptOpenDispute) self.assertEqual(result.errors.for_object("dispute")[0].message, "Disputes can only be accepted when they are in an Open state") @raises_with_regexp(NotFoundError, "dispute with id 'invalid-id' not found") def test_accept_raises_error_when_dispute_not_found(self): dispute = Dispute.accept("invalid-id") def test_add_file_evidence_adds_evidence(self): dispute = self.create_sample_dispute() document = self.create_evidence_document() result = Dispute.add_file_evidence(dispute.id, document.id) self.assertTrue(result.is_success) updated_dispute = Dispute.find(dispute.id) self.assertEqual(updated_dispute.evidence[0].id, result.evidence.id) def test_add_file_evidence_adds_category_file_evidence(self): dispute = self.create_sample_dispute() document = self.create_evidence_document() result = Dispute.add_file_evidence(dispute.id, { "document_id": document.id, "category": "GENERAL" }) self.assertTrue(result.is_success) self.assertEqual(result.evidence.category, "GENERAL") @raises_with_regexp(NotFoundError, "dispute with id 'unknown_dispute_id' not found") def test_add_file_evidence_raises_error_when_dispute_not_found(self): dispute = Dispute.add_file_evidence("unknown_dispute_id", "text evidence") def test_add_file_evidence_raises_error_when_dispute_not_open(self): dispute = self.create_sample_dispute() document = self.create_evidence_document() Dispute.accept(dispute.id) result = Dispute.add_file_evidence(dispute.id, document.id) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyAddEvidenceToOpenDispute) self.assertEqual(result.errors.for_object("dispute")[0].message, "Evidence can only be attached to disputes that are in an Open state") def test_categorized_file_evidence_for_text_only_category(self): dispute = self.create_sample_dispute() document = self.create_evidence_document() result = Dispute.add_file_evidence(dispute.id, { "document_id": document.id, "category": "DEVICE_ID" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.EvidenceCategoryTextOnly) self.assertEqual(result.errors.for_object("dispute")[0].message, "Only text evidence can be provided for this category") def test_categorized_file_evidence_with_unsupported_category(self): dispute = self.create_sample_dispute() document = self.create_evidence_document() result = Dispute.add_file_evidence(dispute.id, { "document_id": document.id, "category": "DOESNOTEXIST" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyCreateEvidenceWithValidCategory) self.assertEqual(result.errors.for_object("dispute")[0].message, "The category you supplied on the evidence record is not valid") def test_add_text_evidence_adds_text_evidence(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, "text evidence") evidence = result.evidence self.assertTrue(result.is_success) self.assertEqual(evidence.comment, "text evidence") self.assertIsNotNone(evidence.created_at) self.assertTrue(re.match("^\w{16,}$", evidence.id)) self.assertIsNone(evidence.sent_to_processor_at) self.assertIsNone(evidence.url) self.assertIsNone(evidence.category) self.assertIsNone(evidence.sequence_number) def test_add_text_evidence_adds_tag_and_sequence_number_text_evidence(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "PROOF_OF_FULFILLMENT", "tag": "EVIDENCE_TYPE" }) result_carrier_name = Dispute.add_text_evidence(dispute.id, { "content": "UPS", "tag": "CARRIER_NAME", "sequence_number": "0" }) result_tracking_number = Dispute.add_text_evidence(dispute.id, { "content": "UPS-1243", "tag": "TRACKING_NUMBER", "sequence_number": "0" }) self.assertTrue(result.is_success) evidence = result.evidence self.assertEqual(evidence.comment, "PROOF_OF_FULFILLMENT") self.assertEqual(evidence.tag, "EVIDENCE_TYPE") self.assertIsNone(evidence.sequence_number) self.assertTrue(result_carrier_name.is_success) evidence = result_carrier_name.evidence self.assertEqual(evidence.comment, "UPS") self.assertEqual(evidence.tag, "CARRIER_NAME") self.assertEqual(evidence.sequence_number, 0) self.assertTrue(result_tracking_number.is_success) evidence = result_tracking_number.evidence self.assertEqual(evidence.comment, "UPS-1243") self.assertEqual(evidence.tag, "TRACKING_NUMBER") self.assertEqual(evidence.sequence_number, 0) def test_add_text_evidence_adds_category_text_evidence(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "device id" , "category": "DEVICE_ID" }) self.assertTrue(result.is_success) evidence = result.evidence self.assertEqual(evidence.comment, "device id") self.assertEqual(evidence.category, "DEVICE_ID") @raises_with_regexp(NotFoundError, "Dispute with ID 'unknown_dispute_id' not found") def test_add_text_evidence_raises_error_when_dispute_not_found(self): dispute = Dispute.add_text_evidence("unknown_dispute_id", "text evidence") def test_add_text_evidence_raises_error_when_dispute_not_open(self): dispute = self.create_sample_dispute() Dispute.accept(dispute.id) result = Dispute.add_text_evidence(dispute.id, "text evidence") self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyAddEvidenceToOpenDispute) self.assertEqual(result.errors.for_object("dispute")[0].message, "Evidence can only be attached to disputes that are in an Open state") def test_add_text_evidence_shows_new_record_in_find(self): dispute = self.create_sample_dispute() evidence = Dispute.add_text_evidence(dispute.id, "text evidence").evidence refreshed_dispute = Dispute.find(dispute.id) self.assertEqual(refreshed_dispute.evidence[0].id, evidence.id) self.assertEqual(refreshed_dispute.evidence[0].comment, "text evidence") def test_categorized_text_evidence_with_unsupported_category(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "evidence", "category": "DOESNOTEXIST" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyCreateEvidenceWithValidCategory) self.assertEqual(result.errors.for_object("dispute")[0].message, "The category you supplied on the evidence record is not valid") def test_categorized_text_evidence_with_file_category(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "evidence", "category": "MERCHANT_WEBSITE_OR_APP_ACCESS" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.EvidenceCategoryDocumentOnly) self.assertEqual(result.errors.for_object("dispute")[0].message, "Only document evidence can be provided for this category") def test_categorized_text_evidence_with_invalid_date_time_format(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "not a date", "category": "DOWNLOAD_DATE_TIME" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.EvidenceContentDateInvalid) def test_categorized_text_evidence_with_valid_date_time_format(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "2018-10-20T18:00:00-0500", "category": "DOWNLOAD_DATE_TIME" }) self.assertTrue(result.is_success) def test_finalize_changes_dispute_status_to_disputed(self): dispute = self.create_sample_dispute() result = Dispute.finalize(dispute.id) self.assertTrue(result.is_success) updated_dispute = Dispute.find(dispute.id) self.assertEqual(updated_dispute.status, Dispute.Status.Disputed) def test_finalize_errors_when_dispute_not_open(self): result = Dispute.finalize("wells_dispute") self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyFinalizeOpenDispute) self.assertEqual(result.errors.for_object("dispute")[0].message, "Disputes can only be finalized when they are in an Open state") def test_finalize_when_digital_goods_missing(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "device_id", "category": "DEVICE_ID" }) self.assertTrue(result.is_success) result = dispute.finalize(dispute.id) self.assertFalse(result.is_success) error_codes = [error.code for error in result.errors.for_object("dispute")] self.assertIn(ErrorCodes.Dispute.DigitalGoodsMissingDownloadDate, error_codes) self.assertIn(ErrorCodes.Dispute.DigitalGoodsMissingEvidence, error_codes) def test_finalize_when_missing_non_disputed_payments_date(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "123", "category": "PRIOR_NON_DISPUTED_TRANSACTION_ARN" }) self.assertTrue(result.is_success) result = dispute.finalize(dispute.id) self.assertFalse(result.is_success) error_codes = [error.code for error in result.errors.for_object("dispute")] self.assertIn(ErrorCodes.Dispute.NonDisputedPriorTransactionEvidenceMissingDate, error_codes) @raises_with_regexp(NotFoundError, "dispute with id 'invalid-id' not found") def test_finalize_raises_error_when_dispute_not_found(self): dispute = Dispute.finalize("invalid-id") def test_find_returns_dispute_with_given_id(self): dispute = Dispute.find("open_dispute") self.assertEqual(dispute.amount_disputed, 31.0) self.assertEqual(dispute.amount_won, 0.0) self.assertEqual(dispute.id, "open_dispute") self.assertEqual(dispute.status, Dispute.Status.Open) self.assertEqual(dispute.transaction.id, "open_disputed_transaction") @raises_with_regexp(NotFoundError, "dispute with id 'invalid-id' not found") def test_find_raises_error_when_dispute_not_found(self): dispute = Dispute.find("invalid-id") def test_remove_evidence_removes_evidence_from_the_dispute(self): dispute = self.create_sample_dispute() evidence = Dispute.add_text_evidence(dispute.id, "text evidence").evidence result = Dispute.remove_evidence(dispute.id, evidence.id) self.assertTrue(result.is_success) @raises_with_regexp(NotFoundError, "evidence with id 'unknown_evidence_id' for dispute with id 'unknown_dispute_id' not found") def test_remove_evidence_raises_error_when_dispute_or_evidence_not_found(self): Dispute.remove_evidence("unknown_dispute_id", "unknown_evidence_id") def test_remove_evidence_errors_when_dispute_not_open(self): dispute = self.create_sample_dispute() evidence = Dispute.add_text_evidence(dispute.id, "text evidence").evidence Dispute.accept(dispute.id) result = Dispute.remove_evidence(dispute.id, evidence.id) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyRemoveEvidenceFromOpenDispute) self.assertEqual(result.errors.for_object("dispute")[0].message, "Evidence can only be removed from disputes that are in an Open state") braintree_python-3.57.1/tests/integration/test_paypal_account.py0000644000175000017500000001423013545202423023365 0ustar hlehlefrom tests.test_helper import * import time from braintree.test.nonces import Nonces class TestPayPalAccount(unittest.TestCase): def test_find_returns_paypal_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) found_account = PayPalAccount.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(found_account.__class__, PayPalAccount) self.assertEqual(found_account.token, result.payment_method.token) self.assertNotEqual(None, found_account.image_url) self.assertNotEqual(None, found_account.created_at) self.assertNotEqual(None, found_account.updated_at) self.assertIsNone(found_account.revoked_at) def test_find_raises_on_not_found_token(self): self.assertRaises(NotFoundError, PayPalAccount.find, "non-existant-token") def test_find_will_not_return_credit_card(self): credit_card = CreditCard.create({ "customer_id": Customer.create().customer.id, "number": "4111111111111111", "expiration_date": "12/2099" }).credit_card self.assertRaises(NotFoundError, PayPalAccount.find, credit_card.token) def test_find_returns_subscriptions_associated_with_a_paypal_account(self): customer_id = Customer.create().customer.id payment_method_token = "paypal-account-" + str(int(time.time())) nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code", "token": payment_method_token }) result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id }) self.assertTrue(result.is_success) token = result.payment_method.token subscription1 = Subscription.create({ "payment_method_token": token, "plan_id": TestHelper.trialless_plan["id"] }).subscription subscription2 = Subscription.create({ "payment_method_token": token, "plan_id": TestHelper.trialless_plan["id"] }).subscription paypal_account = PayPalAccount.find(result.payment_method.token) self.assertTrue(subscription1.id in [s.id for s in paypal_account.subscriptions]) self.assertTrue(subscription2.id in [s.id for s in paypal_account.subscriptions]) def test_find_retuns_billing_agreement_id_with_a_paypal_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "payment_method_nonce": Nonces.PayPalBillingAgreement, "customer_id": customer_id }) self.assertTrue(result.is_success) paypal_account = PayPalAccount.find(result.payment_method.token) self.assertNotEqual(None, paypal_account.billing_agreement_id) def test_delete_deletes_paypal_account(self): result = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) paypal_account_token = result.payment_method.token delete_result = PayPalAccount.delete(paypal_account_token) self.assertTrue(delete_result.is_success) self.assertRaises(NotFoundError, PayPalAccount.find, paypal_account_token) def test_delete_raises_on_not_found(self): self.assertRaises(NotFoundError, PayPalAccount.delete, "non-existant-token") def test_delete_delete_wont_delete_credit_card(self): credit_card = CreditCard.create({ "customer_id": Customer.create().customer.id, "number": "4111111111111111", "expiration_date": "12/2099" }).credit_card self.assertRaises(NotFoundError, PayPalAccount.delete, credit_card.token) def test_update_can_update_token_and_default(self): customer_id = Customer.create().customer.id CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "12/2099" }) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) old_token = result.payment_method.token new_token = "new-token-%s" % int(round(time.time() * 1000)) result = PayPalAccount.update(old_token, { "token": new_token, "options": {"make_default": True} }) self.assertTrue(result.is_success) updated_account = PayPalAccount.find(new_token) self.assertEqual(updated_account.default, True) def test_update_returns_validation_errors(self): payment_method_token = "payment-token-%s" % int(round(time.time() * 1000)) customer_id = Customer.create().customer.id CreditCard.create({ "token": payment_method_token, "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "12/2099" }) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) old_token = result.payment_method.token result = PayPalAccount.update(old_token, { "token": payment_method_token, }) self.assertFalse(result.is_success) token_errors = result.errors.for_object("paypal_account").on("token") self.assertEqual(1, len(token_errors)) self.assertEqual(ErrorCodes.PayPalAccount.TokenIsInUse, token_errors[0].code) result = PayPalAccount.update(old_token, { "token": payment_method_token, }) self.assertFalse(result.is_success) token_errors = result.errors.for_object("paypal_account").on("token") self.assertEqual(1, len(token_errors)) self.assertEqual(ErrorCodes.PayPalAccount.TokenIsInUse, token_errors[0].code) braintree_python-3.57.1/tests/integration/test_test_helper.py0000644000175000017500000000222613545202423022703 0ustar hlehlefrom tests.test_helper import * from braintree.test.nonces import Nonces class TestTestHelper(unittest.TestCase): def setUp(self): self.transaction = Transaction.sale({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" }, "amount": "100.00", "options": { "submit_for_settlement": "true" } }).transaction def test_settle_transaction_settles_transaction(self): TestHelper.settle_transaction(self.transaction.id) self.assertEqual(Transaction.Status.Settled, Transaction.find(self.transaction.id).status) def test_settlement_confirm_transaction(self): TestHelper.settlement_confirm_transaction(self.transaction.id) self.assertEqual(Transaction.Status.SettlementConfirmed, Transaction.find(self.transaction.id).status) def test_settlement_decline_transaction(self): TestHelper.settlement_decline_transaction(self.transaction.id) self.assertEqual(Transaction.Status.SettlementDeclined, Transaction.find(self.transaction.id).status) braintree_python-3.57.1/tests/integration/test_customer.py0000644000175000017500000013177513545202423022242 0ustar hlehle# -*- coding: latin-1 -*- from tests.test_helper import * import braintree.test.venmo_sdk as venmo_sdk from braintree.test.nonces import Nonces class TestCustomer(unittest.TestCase): def test_all(self): collection = Customer.all() self.assertTrue(collection.maximum_size > 100) customer_ids = [c.id for c in collection.items] self.assertEqual(collection.maximum_size, len(TestHelper.unique(customer_ids))) self.assertEqual(Customer, type(collection.first)) def test_create(self): result = Customer.create({ "first_name": "Joe", "last_name": "Brown", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.1234", "fax": "614.555.5678", "website": "www.email.com" }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("Joe", customer.first_name) self.assertEqual("Brown", customer.last_name) self.assertEqual("Fake Company", customer.company) self.assertEqual("joe@email.com", customer.email) self.assertEqual("312.555.1234", customer.phone) self.assertEqual("614.555.5678", customer.fax) self.assertEqual("www.email.com", customer.website) self.assertNotEqual(None, customer.id) self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", customer.id)) def test_create_unicode(self): result = Customer.create({ "first_name": "Kimi", "last_name": u"Räikkönen", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.1234", "fax": "614.555.5678", "website": "www.email.com" }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("Kimi", customer.first_name) self.assertEqual(u"Räikkönen", customer.last_name) self.assertEqual("Fake Company", customer.company) self.assertEqual("joe@email.com", customer.email) self.assertEqual("312.555.1234", customer.phone) self.assertEqual("614.555.5678", customer.fax) self.assertEqual("www.email.com", customer.website) self.assertNotEqual(None, customer.id) def test_create_with_device_session_id_and_fraud_merchant_id(self): result = Customer.create({ "first_name": "Joe", "last_name": "Brown", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.1234", "fax": "614.555.5678", "website": "www.email.com", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100", "device_session_id": "abc123", "fraud_merchant_id": "456" } }) self.assertTrue(result.is_success) def test_create_with_risk_data_security_parameters(self): result = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "options": { "verify_card": True, } }, "risk_data": { "customer_browser": "IE7", "customer_ip": "192.168.0.1" } }) self.assertTrue(result.is_success) def test_create_and_update_with_verification_account_type(self): result_with_account_type_credit = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "05/2010", "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "credit", } }, }) update_with_account_type_credit = Customer.update(result_with_account_type_credit.customer.id, { "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "05/2010", "options": { "verification_account_type": "credit", } }, }) result_with_account_type_debit = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "05/2010", "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "debit", } }, }) update_with_account_type_debit = Customer.update(result_with_account_type_debit.customer.id, { "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "05/2010", "options": { "verification_account_type": "debit", } }, }) self.assertTrue(result_with_account_type_credit.is_success) self.assertTrue(result_with_account_type_debit.is_success) self.assertTrue(update_with_account_type_credit.is_success) self.assertTrue(update_with_account_type_debit.is_success) def test_create_using_access_token(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret", environment=Environment.Development ) code = TestHelper.create_grant(gateway, { "merchant_public_id": "integration_merchant_id", "scope": "read_write" }) result = gateway.oauth.create_token_from_code({ "code": code }) gateway = BraintreeGateway( access_token=result.credentials.access_token, environment=Environment.Development ) result = gateway.customer.create({ "first_name": "Joe", "last_name": "Brown" }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("Joe", customer.first_name) def test_create_with_unicode(self): result = Customer.create({ "first_name": u"Joe<&>", "last_name": u"G\u1F00t\u1F18s", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.1234", "fax": "614.555.5678", "website": "www.email.com" }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(u"Joe<&>", customer.first_name) self.assertEqual(u"G\u1f00t\u1F18s", customer.last_name) self.assertEqual("Fake Company", customer.company) self.assertEqual("joe@email.com", customer.email) self.assertEqual("312.555.1234", customer.phone) self.assertEqual("614.555.5678", customer.fax) self.assertEqual("www.email.com", customer.website) self.assertNotEqual(None, customer.id) self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", customer.id)) found_customer = Customer.find(customer.id) self.assertEqual(u"G\u1f00t\u1F18s", found_customer.last_name) def test_create_with_apple_pay_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.ApplePayVisa}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.apple_pay_cards)) self.assertIsInstance(customer.apple_pay_cards[0], ApplePayCard) def test_create_with_three_d_secure_nonce(self): result = Customer.create({ "payment_method_nonce": Nonces.ThreeDSecureVisaFullAuthentication, "credit_card": { "options": { "verify_card": True, }, }, }) self.assertTrue(result.is_success) three_d_secure_info = result.customer.payment_methods[0].verification.three_d_secure_info self.assertEqual("Y", three_d_secure_info.enrolled) self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertEqual("cavv_value", three_d_secure_info.cavv) self.assertEqual("xid_value", three_d_secure_info.xid) self.assertEqual(None, three_d_secure_info.ds_transaction_id) self.assertEqual("05", three_d_secure_info.eci_flag) self.assertEqual("1.0.2", three_d_secure_info.three_d_secure_version) def test_create_with_android_pay_proxy_card_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.AndroidPayCardDiscover}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.android_pay_cards)) self.assertIsInstance(customer.android_pay_cards[0], AndroidPayCard) def test_create_with_android_pay_network_token_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.AndroidPayCardMasterCard}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.android_pay_cards)) self.assertIsInstance(customer.android_pay_cards[0], AndroidPayCard) def test_create_with_amex_express_checkout_card_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.AmexExpressCheckoutCard}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.amex_express_checkout_cards)) self.assertIsInstance(customer.amex_express_checkout_cards[0], AmexExpressCheckoutCard) def test_create_with_venmo_account_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.VenmoAccount}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.venmo_accounts)) self.assertIsInstance(customer.venmo_accounts[0], VenmoAccount) def test_create_with_us_bank_account_nonce(self): result = Customer.create({ "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "credit_card": { "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } } }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.us_bank_accounts)) self.assertIsInstance(customer.us_bank_accounts[0], UsBankAccount) def test_create_with_paypal_future_payments_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.PayPalFuturePayment}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.paypal_accounts)) self.assertIsInstance(customer.paypal_accounts[0], PayPalAccount) def test_create_with_paypal_order_payment_nonce(self): http = ClientApiHttp.create() status_code, payment_method_nonce = http.get_paypal_nonce({ "intent": "order", "payment-token": "fake-paypal-payment-token", "payer-id": "fake-paypal-payer-id" }) result = Customer.create({"payment_method_nonce": payment_method_nonce}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.paypal_accounts)) self.assertIsInstance(customer.paypal_accounts[0], PayPalAccount) def test_create_with_paypal_order_payment_nonce_and_paypal_options(self): http = ClientApiHttp.create() status_code, payment_method_nonce = http.get_paypal_nonce({ "intent": "order", "payment-token": "fake-paypal-payment-token", "payer-id": "fake-paypal-payer-id" }) result = Customer.create({ "payment_method_nonce": payment_method_nonce, "options": { "paypal": { "payee_email": "payee@example.com", "order_id": "merchant-order-id", "custom_field": "custom merchant field", "description": "merchant description", "amount": "1.23", "shipping": { "first_name": "Andrew", "last_name": "Mason", "company": "Braintree", "street_address": "456 W Main St", "extended_address": "Apt 2F", "locality": "Bartlett", "region": "IL", "postal_code": "60103", "country_name": "Mexico", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484" }, }, }, }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.paypal_accounts)) self.assertIsInstance(customer.paypal_accounts[0], PayPalAccount) def test_create_with_paypal_one_time_nonce_fails(self): result = Customer.create({"payment_method_nonce": Nonces.PayPalOneTimePayment}) self.assertFalse(result.is_success) paypal_account_errors = result.errors.for_object("customer").for_object("paypal_account").on("base") self.assertEqual(1, len(paypal_account_errors)) self.assertEqual(ErrorCodes.PayPalAccount.CannotVaultOneTimeUsePayPalAccount, paypal_account_errors[0].code) def test_create_with_no_attributes(self): result = Customer.create() self.assertTrue(result.is_success) self.assertNotEqual(None, result.customer.id) def test_create_with_special_chars(self): result = Customer.create({"first_name": "XML Chars <>&'\""}) self.assertTrue(result.is_success) self.assertEqual("XML Chars <>&'\"", result.customer.first_name) def test_create_returns_an_error_response_if_invalid(self): result = Customer.create({ "email": "@invalid.com", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "billing_address": { "country_code_alpha2": "MX", "country_code_alpha3": "USA" } } }) self.assertFalse(result.is_success) customer_email_errors = result.errors.for_object("customer").on("email") self.assertEqual(1, len(customer_email_errors)) self.assertEqual(ErrorCodes.Customer.EmailIsInvalid, customer_email_errors[0].code) billing_address_errors = result.errors.for_object("customer").for_object("credit_card").for_object("billing_address").on("base") self.assertEqual(1, len(billing_address_errors)) self.assertEqual(ErrorCodes.Address.InconsistentCountry, billing_address_errors[0].code) def test_create_customer_and_payment_method_at_the_same_time(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("Mike", customer.first_name) self.assertEqual("Jones", customer.last_name) credit_card = customer.credit_cards[0] self.assertEqual("411111", credit_card.bin) self.assertEqual("1111", credit_card.last_4) self.assertEqual("05/2010", credit_card.expiration_date) def test_create_customer_and_verify_payment_method(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4000111111111115", "expiration_date": "05/2010", "cvv": "100", "options": {"verify_card": True} } }) self.assertFalse(result.is_success) self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, result.credit_card_verification.status) def test_create_customer_and_verify_payment_method_with_verification_amount(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100", "options": {"verify_card": True, "verification_amount": "6.00"} } }) self.assertTrue(result.is_success) def test_create_customer_with_check_duplicate_payment_method(self): attributes = { "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4000111111111115", "expiration_date": "05/2010", "cvv": "100", "options": {"fail_on_duplicate_payment_method": True} } } Customer.create(attributes) result = Customer.create(attributes) self.assertFalse(result.is_success) self.assertEqual("Duplicate card exists in the vault.", result.message) card_number_errors = result.errors.for_object("customer").for_object("credit_card").on("number") self.assertEqual(1, len(card_number_errors)) self.assertEqual(ErrorCodes.CreditCard.DuplicateCardExists, card_number_errors[0].code) def test_create_customer_with_payment_method_and_billing_address(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100", "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_code_alpha2": "US", "country_code_alpha3": "USA", "country_code_numeric": "840", "country_name": "United States of America" } } }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("Mike", customer.first_name) self.assertEqual("Jones", customer.last_name) address = customer.credit_cards[0].billing_address self.assertEqual("123 Abc Way", address.street_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60622", address.postal_code) self.assertEqual("US", address.country_code_alpha2) self.assertEqual("USA", address.country_code_alpha3) self.assertEqual("840", address.country_code_numeric) self.assertEqual("United States of America", address.country_name) def test_create_with_customer_fields(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "custom_fields": { "store_me": "custom value" } }) self.assertTrue(result.is_success) self.assertEqual("custom value", result.customer.custom_fields["store_me"]) def test_create_returns_nested_errors(self): result = Customer.create({ "email": "invalid", "credit_card": { "number": "invalid", "billing_address": { "country_name": "invalid" } } }) self.assertFalse(result.is_success) email_errors = result.errors.for_object("customer").on("email") self.assertEqual(1, len(email_errors)) self.assertEqual(ErrorCodes.Customer.EmailIsInvalid, email_errors[0].code) card_number_errors = result.errors.for_object("customer").for_object("credit_card").on("number") self.assertEqual(1, len(card_number_errors)) self.assertEqual(ErrorCodes.CreditCard.NumberHasInvalidLength, card_number_errors[0].code) country_name_errors = result.errors.for_object("customer").for_object("credit_card").for_object("billing_address").on("country_name") self.assertEqual(1, len(country_name_errors)) self.assertEqual(ErrorCodes.Address.CountryNameIsNotAccepted, country_name_errors[0].code) def test_create_returns_errors_if_custom_fields_are_not_registered(self): result = Customer.create({ "first_name": "Jack", "last_name": "Kennedy", "custom_fields": { "spouse_name": "Jacqueline" } }) self.assertFalse(result.is_success) custom_fields_errors = result.errors.for_object("customer").on("custom_fields") self.assertEqual(1, len(custom_fields_errors)) self.assertEqual(ErrorCodes.Customer.CustomFieldIsInvalid, custom_fields_errors[0].code) def test_create_with_venmo_sdk_session(self): result = Customer.create({ "first_name": "Jack", "last_name": "Kennedy", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "options": { "venmo_sdk_session": venmo_sdk.Session } } }) self.assertTrue(result.is_success) self.assertFalse(result.customer.credit_cards[0].venmo_sdk) def test_create_with_venmo_sdk_payment_method_code(self): result = Customer.create({ "first_name": "Jack", "last_name": "Kennedy", "credit_card": { "venmo_sdk_payment_method_code": venmo_sdk.generate_test_payment_method_code("4111111111111111") } }) self.assertTrue(result.is_success) self.assertEqual("411111", result.customer.credit_cards[0].bin) def test_create_with_payment_method_nonce(self): config = Configuration.instantiate() authorization_fingerprint = json.loads(TestHelper.generate_decoded_client_token())["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) _, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) nonce = json.loads(response)["creditCards"][0]["nonce"] result = Customer.create({ "credit_card": { "payment_method_nonce": nonce } }) self.assertTrue(result.is_success) self.assertEqual("411111", result.customer.credit_cards[0].bin) def test_delete_with_valid_customer(self): customer = Customer.create().customer result = Customer.delete(customer.id) self.assertTrue(result.is_success) @raises(NotFoundError) def test_delete_with_invalid_customer(self): customer = Customer.create().customer Customer.delete(customer.id) Customer.delete(customer.id) def test_find_with_valid_customer(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Cool" }).customer found_customer = Customer.find(customer.id) self.assertEqual(customer.id, found_customer.id) self.assertEqual(customer.first_name, found_customer.first_name) self.assertEqual(customer.last_name, found_customer.last_name) def test_find_customer_with_us_bank_account(self): customer = Customer.create({ "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "credit_card": { "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } } }).customer found_customer = Customer.find(customer.id) self.assertEqual(customer.id, found_customer.id) self.assertEqual(customer.first_name, found_customer.first_name) self.assertEqual(customer.last_name, found_customer.last_name) self.assertEqual(1, len(found_customer.us_bank_accounts)) self.assertIsInstance(found_customer.us_bank_accounts[0], UsBankAccount) @raises_with_regexp(NotFoundError, "customer with id 'badid' not found") def test_find_with_invalid_customer(self): Customer.find("badid") def test_find_customer_with_all_filterable_associations_filtered_out(self): customer = Customer.create({ "custom_fields": { "store_me": "custom value" } }).customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America" } }).credit_card subscription_id = "id_" + str(random.randint(1, 1000000)) subscription = Subscription.create({ "id": subscription_id, "plan_id": "integration_trialless_plan", "payment_method_token": credit_card.token, "price": Decimal("1.00") }).subscription found_customer = Customer.find(customer.id, "customernoassociations") self.assertEqual(len(found_customer.credit_cards), 0) self.assertEqual(len(found_customer.payment_methods), 0) self.assertEqual(len(found_customer.addresses), 0) self.assertEqual(len(found_customer.custom_fields), 0) def test_find_customer_with_nested_filterable_associations_filtered_out(self): customer = Customer.create({ "custom_fields": { "store_me": "custom value" } }).customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America" } }).credit_card subscription_id = "id_" + str(random.randint(1, 1000000)) subscription = Subscription.create({ "id": subscription_id, "plan_id": "integration_trialless_plan", "payment_method_token": credit_card.token, "price": Decimal("1.00") }).subscription found_customer = Customer.find(customer.id, "customertoplevelassociations") self.assertEqual(len(found_customer.credit_cards), 1) self.assertEqual(len(found_customer.credit_cards[0].subscriptions), 0) self.assertEqual(len(found_customer.payment_methods), 1) self.assertEqual(len(found_customer.payment_methods[0].subscriptions), 0) self.assertEqual(len(found_customer.addresses), 1) self.assertEqual(len(found_customer.custom_fields), 1) def test_update_with_valid_options(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.5555", "fax": "614.555.5555", "website": "www.email.com" }).customer result = Customer.update(customer.id, { "first_name": "Joe", "last_name": "Brown", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.1234", "fax": "614.555.5678", "website": "www.email.com" }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("Joe", customer.first_name) self.assertEqual("Brown", customer.last_name) self.assertEqual("Fake Company", customer.company) self.assertEqual("joe@email.com", customer.email) self.assertEqual("312.555.1234", customer.phone) self.assertEqual("614.555.5678", customer.fax) self.assertEqual("www.email.com", customer.website) self.assertNotEqual(None, customer.id) self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", customer.id)) def test_update_with_default_payment_method(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", }).customer token1 = str(random.randint(1, 1000000)) payment_method1 = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.TransactableVisa, "token": token1 }).payment_method payment_method1 = PaymentMethod.find(payment_method1.token) self.assertTrue(payment_method1.default) token2 = str(random.randint(1, 1000000)) payment_method2 = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.TransactableMasterCard, "token": token2 }).payment_method Customer.update(customer.id, { "default_payment_method_token": payment_method2.token }) payment_method2 = PaymentMethod.find(payment_method2.token) self.assertTrue(payment_method2.default) def test_update_with_default_payment_method_in_options(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", }).customer token1 = str(random.randint(1, 1000000)) payment_method1 = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.TransactableVisa, "token": token1 }).payment_method payment_method1 = PaymentMethod.find(payment_method1.token) self.assertTrue(payment_method1.default) token2 = str(random.randint(1, 1000000)) payment_method2 = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.TransactableMasterCard, "token": token2 }).payment_method Customer.update(customer.id, { "credit_card": { "options": { "update_existing_token": token2, "make_default": True } } }) payment_method2 = PaymentMethod.find(payment_method2.token) self.assertTrue(payment_method2.default) def test_update_with_nested_values(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": "4111111111111111", "expiration_date": "10/10", "billing_address": { "postal_code": "11111" } } }).customer credit_card = customer.credit_cards[0] address = credit_card.billing_address updated_customer = Customer.update(customer.id, { "first_name": "Joe", "last_name": "Brown", "credit_card": { "expiration_date": "12/12", "options": { "update_existing_token": credit_card.token }, "billing_address": { "postal_code": "44444", "country_code_alpha2": "US", "country_code_alpha3": "USA", "country_code_numeric": "840", "country_name": "United States of America", "options": { "update_existing": True } } } }).customer updated_credit_card = CreditCard.find(credit_card.token) updated_address = Address.find(customer.id, address.id) self.assertEqual("Joe", updated_customer.first_name) self.assertEqual("Brown", updated_customer.last_name) self.assertEqual("12/2012", updated_credit_card.expiration_date) self.assertEqual("44444", updated_address.postal_code) self.assertEqual("US", updated_address.country_code_alpha2) self.assertEqual("USA", updated_address.country_code_alpha3) self.assertEqual("840", updated_address.country_code_numeric) self.assertEqual("United States of America", updated_address.country_name) def test_update_with_nested_billing_address_id(self): customer = Customer.create().customer address = Address.create({ "customer_id": customer.id, "postal_code": "11111" }).address updated_customer = Customer.update(customer.id, { "credit_card": { "number": "4111111111111111", "expiration_date": "12/12", "billing_address_id": address.id } }).customer credit_card = updated_customer.credit_cards[0] self.assertEqual(address.id, credit_card.billing_address.id) self.assertEqual("11111", credit_card.billing_address.postal_code) def test_update_with_invalid_options(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.5555", "fax": "614.555.5555", "website": "www.email.com" }).customer result = Customer.update(customer.id, { "email": "@email.com", }) self.assertFalse(result.is_success) email_errors = result.errors.for_object("customer").on("email") self.assertEqual(1, len(email_errors)) self.assertEqual(ErrorCodes.Customer.EmailIsInvalid, email_errors[0].code) def test_update_with_paypal_future_payments_nonce(self): customer = Customer.create().customer result = Customer.update(customer.id, { "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) customer = result.customer self.assertNotEqual(None, customer.paypal_accounts[0]) def test_update_with_paypal_one_time_nonce_fails(self): customer = Customer.create().customer result = Customer.update(customer.id, { "payment_method_nonce": Nonces.PayPalOneTimePayment }) self.assertFalse(result.is_success) paypal_account_errors = result.errors.for_object("customer").for_object("paypal_account").on("base") self.assertEqual(1, len(paypal_account_errors)) self.assertEqual(ErrorCodes.PayPalAccount.CannotVaultOneTimeUsePayPalAccount, paypal_account_errors[0].code) def test_update_with_paypal_order_nonce(self): customer = Customer.create().customer http = ClientApiHttp.create() status_code, payment_method_nonce = http.get_paypal_nonce({ "intent": "order", "payment-token": "fake-paypal-payment-token", "payer-id": "fake-paypal-payer-id" }) result = Customer.update(customer.id, { "payment_method_nonce": payment_method_nonce, "options": { "paypal": { "payee_email": "payee@example.com", "order_id": "merchant-order-id", "custom_field": "custom merchant field", "description": "merchant description", "amount": "1.23", "shipping": { "first_name": "Andrew", "last_name": "Mason", "company": "Braintree", "street_address": "456 W Main St", "extended_address": "Apt 2F", "locality": "Bartlett", "region": "IL", "postal_code": "60103", "country_name": "Mexico", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484" }, }, }, }) self.assertTrue(result.is_success) customer = result.customer self.assertNotEqual(None, customer.paypal_accounts[0]) self.assertEqual(1, len(customer.paypal_accounts)) self.assertIsInstance(customer.paypal_accounts[0], PayPalAccount) def test_update_with_nested_verification_amount(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": "4111111111111111", "expiration_date": "10/10", "billing_address": { "postal_code": "11111" } } }).customer result = Customer.update(customer.id, { "credit_card": { "number": "4111111111111111", "expiration_date": "10/10", "options": { "verify_card": True, "verification_amount": "2.00" }, } }) self.assertTrue(result.is_success) def test_create_from_transparent_redirect_with_successful_result(self): tr_data = { "customer": { "first_name": "John", "last_name": "Doe", "company": "Doe Co", } } post_params = { "tr_data": Customer.tr_data_for_create(tr_data, "http://example.com/path"), "customer[email]": "john@doe.com", "customer[phone]": "312.555.2323", "customer[fax]": "614.555.5656", "customer[website]": "www.johndoe.com", "customer[credit_card][number]": "4111111111111111", "customer[credit_card][expiration_date]": "05/2012", "customer[credit_card][billing_address][country_code_alpha2]": "MX", "customer[credit_card][billing_address][country_code_alpha3]": "MEX", "customer[credit_card][billing_address][country_code_numeric]": "484", "customer[credit_card][billing_address][country_name]": "Mexico", } query_string = TestHelper.simulate_tr_form_post(post_params, Customer.transparent_redirect_create_url()) result = Customer.confirm_transparent_redirect(query_string) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("John", customer.first_name) self.assertEqual("Doe", customer.last_name) self.assertEqual("Doe Co", customer.company) self.assertEqual("john@doe.com", customer.email) self.assertEqual("312.555.2323", customer.phone) self.assertEqual("614.555.5656", customer.fax) self.assertEqual("www.johndoe.com", customer.website) self.assertEqual("05/2012", customer.credit_cards[0].expiration_date) self.assertEqual("MX", customer.credit_cards[0].billing_address.country_code_alpha2) self.assertEqual("MEX", customer.credit_cards[0].billing_address.country_code_alpha3) self.assertEqual("484", customer.credit_cards[0].billing_address.country_code_numeric) self.assertEqual("Mexico", customer.credit_cards[0].billing_address.country_name) def test_create_from_transparent_redirect_with_error_result(self): tr_data = { "customer": { "company": "Doe Co", } } post_params = { "tr_data": Customer.tr_data_for_create(tr_data, "http://example.com/path"), "customer[email]": "john#doe.com", } query_string = TestHelper.simulate_tr_form_post(post_params, Customer.transparent_redirect_create_url()) result = Customer.confirm_transparent_redirect(query_string) self.assertFalse(result.is_success) email_errors = result.errors.for_object("customer").on("email") self.assertEqual(1, len(email_errors)) self.assertEqual(ErrorCodes.Customer.EmailIsInvalid, email_errors[0].code) def test_update_from_transparent_redirect_with_successful_result(self): customer = Customer.create({ "first_name": "Jane", }).customer tr_data = { "customer_id": customer.id, "customer": { "first_name": "John", } } post_params = { "tr_data": Customer.tr_data_for_update(tr_data, "http://example.com/path"), "customer[email]": "john@doe.com", } query_string = TestHelper.simulate_tr_form_post(post_params, Customer.transparent_redirect_update_url()) result = Customer.confirm_transparent_redirect(query_string) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("John", customer.first_name) self.assertEqual("john@doe.com", customer.email) def test_update_with_nested_values_via_transparent_redirect(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": "4111111111111111", "expiration_date": "10/10", "billing_address": { "postal_code": "11111" } } }).customer credit_card = customer.credit_cards[0] address = credit_card.billing_address tr_data = { "customer_id": customer.id, "customer": { "first_name": "Joe", "last_name": "Brown", "credit_card": { "expiration_date": "12/12", "options": { "update_existing_token": credit_card.token }, "billing_address": { "postal_code": "44444", "options": { "update_existing": True } } } } } post_params = { "tr_data": Customer.tr_data_for_update(tr_data, "http://example.com/path"), } query_string = TestHelper.simulate_tr_form_post(post_params, Customer.transparent_redirect_update_url()) updated_customer = Customer.confirm_transparent_redirect(query_string).customer updated_credit_card = CreditCard.find(credit_card.token) updated_address = Address.find(customer.id, address.id) self.assertEqual("Joe", updated_customer.first_name) self.assertEqual("Brown", updated_customer.last_name) self.assertEqual("12/2012", updated_credit_card.expiration_date) self.assertEqual("44444", updated_address.postal_code) def test_update_from_transparent_redirect_with_error_result(self): customer = Customer.create({ "first_name": "Jane", }).customer tr_data = { "customer_id": customer.id, "customer": { "first_name": "John", } } post_params = { "tr_data": Customer.tr_data_for_update(tr_data, "http://example.com/path"), "customer[email]": "john#doe.com", } query_string = TestHelper.simulate_tr_form_post(post_params, Customer.transparent_redirect_update_url()) result = Customer.confirm_transparent_redirect(query_string) self.assertFalse(result.is_success) customer_email_errors = result.errors.for_object("customer").on("email") self.assertEqual(1, len(customer_email_errors)) self.assertEqual(ErrorCodes.Customer.EmailIsInvalid, customer_email_errors[0].code) def test_customer_payment_methods(self): customer = Customer("gateway", { "credit_cards": [{"token": "credit_card"}], "paypal_accounts": [{"token": "paypal_account"}], "apple_pay_cards": [{"token": "apple_pay_card"}], "android_pay_cards": [{"token": "android_pay_card"}], "us_bank_accounts": [{"token": "us_bank_account"}] }) payment_method_tokens = [ pm.token for pm in customer.payment_methods ] self.assertEqual(sorted(payment_method_tokens), ["android_pay_card", "apple_pay_card", "credit_card", "paypal_account", "us_bank_account"]) braintree_python-3.57.1/tests/integration/test_transaction_with_us_bank_account.py0000644000175000017500000001442713545202423027171 0ustar hlehlefrom tests.test_helper import * from braintree.payment_instrument_type import PaymentInstrumentType from braintree.us_bank_account_verification import UsBankAccountVerification class TestTransactionWithUsBankAccount(unittest.TestCase): def test_nonce_transactions(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "submit_for_settlement": True, "store_in_vault": True } }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.us_bank_account.routing_number, "021000021") self.assertEqual(result.transaction.us_bank_account.last_4, "1234") self.assertEqual(result.transaction.us_bank_account.account_type, "checking") self.assertEqual(result.transaction.us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", result.transaction.us_bank_account.bank_name)) self.assertEqual(result.transaction.us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(result.transaction.us_bank_account.ach_mandate.accepted_at, datetime) def test_nonce_transactions_with_vaulted_token(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "submit_for_settlement": True, "store_in_vault": True } }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.us_bank_account.routing_number, "021000021") self.assertEqual(result.transaction.us_bank_account.last_4, "1234") self.assertEqual(result.transaction.us_bank_account.account_type, "checking") self.assertEqual(result.transaction.us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", result.transaction.us_bank_account.bank_name)) self.assertEqual(result.transaction.us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(result.transaction.us_bank_account.ach_mandate.accepted_at, datetime) token = result.transaction.us_bank_account.token result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, "payment_method_token": token, "options": { "submit_for_settlement": True, } }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.us_bank_account.routing_number, "021000021") self.assertEqual(result.transaction.us_bank_account.last_4, "1234") self.assertEqual(result.transaction.us_bank_account.account_type, "checking") self.assertEqual(result.transaction.us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", result.transaction.us_bank_account.bank_name)) self.assertEqual(result.transaction.us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(result.transaction.us_bank_account.ach_mandate.accepted_at, datetime) def test_token_transactions_not_found(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, "payment_method_nonce": TestHelper.generate_invalid_us_bank_account_nonce(), "options": { "submit_for_settlement": True, "store_in_vault": True } }) self.assertFalse(result.is_success) error_code = result.errors.for_object("transaction").on("payment_method_nonce")[0].code self.assertEqual(error_code, ErrorCodes.Transaction.PaymentMethodNonceUnknown) def test_verification_create_with_plaid_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, "payment_method_nonce": TestHelper.generate_plaid_us_bank_account_nonce(), "options": { "submit_for_settlement": True, "store_in_vault": True } }) self.assertTrue(result.is_success) token = result.transaction.us_bank_account.token us_bank_account = PaymentMethod.find(token) self.assertEqual(result.transaction.payment_instrument_type, PaymentInstrumentType.UsBankAccount) self.assertEqual(len(us_bank_account.verifications), 1) self.assertEqual(us_bank_account.verifications[0].verification_method, UsBankAccountVerification.VerificationMethod.TokenizedCheck) self.assertEqual(us_bank_account.verifications[0].status, UsBankAccountVerification.Status.Verified) class TestTransactionWithUsBankAccountCompliantMerchant(unittest.TestCase): def setUp(self): braintree.Configuration.configure( braintree.Environment.Development, "integration2_merchant_id", "integration2_public_key", "integration2_private_key" ) def tearDown(self): braintree.Configuration.configure( braintree.Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) def test_reject_non_plaid_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": "another_us_bank_merchant_account", "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "submit_for_settlement": True, "store_in_vault": True } }) self.assertFalse(result.is_success) error_code = result.errors.for_object("transaction").on("payment_method_nonce")[0].code self.assertEqual(ErrorCodes.Transaction.UsBankAccountNonceMustBePlaidVerified, error_code) braintree_python-3.57.1/tests/integration/test_client_token.py0000644000175000017500000001410213545202423023037 0ustar hlehlefrom tests.test_helper import * import json import urllib import datetime import braintree from braintree.util import Http from base64 import b64decode class TestClientTokenGenerate(unittest.TestCase): def test_allows_client_token_version_to_be_specified(self): client_token = ClientToken.generate({"version": 1}) version = json.loads(client_token)["version"] self.assertEqual(1, version) def test_error_in_generate_raises_value_error(self): self.assertRaises(ValueError, ClientToken.generate, { "customer_id": "i_am_not_a_real_customer" }) class TestClientToken(unittest.TestCase): def test_is_authorized_with_authorization_fingerprint(self): config = Configuration.instantiate() client_token = TestHelper.generate_decoded_client_token() authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, _ = http.get_cards() self.assertEqual(200, status_code) def test_client_token_version_defaults_to_two(self): client_token = TestHelper.generate_decoded_client_token() version = json.loads(client_token)["version"] self.assertEqual(2, version) def test_can_pass_verify_card(self): config = Configuration.instantiate() result = braintree.Customer.create() customer_id = result.customer.id client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, "options": { "verify_card": True } }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, _ = http.add_card({ "credit_card": { "number": "4000111111111115", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(422, status_code) def test_can_pass_make_default(self): config = Configuration.instantiate() result = braintree.Customer.create() customer_id = result.customer.id client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, "options": { "make_default": True } }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, _ = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) status_code, _ = http.add_card({ "credit_card": { "number": "4005519200000004", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) customer = braintree.Customer.find(customer_id) self.assertEqual(2, len(customer.credit_cards)) for credit_card in customer.credit_cards: if credit_card.bin == "400551": self.assertTrue(credit_card.default) def test_can_pass_fail_on_duplicate_payment_method(self): config = Configuration.instantiate() result = braintree.Customer.create() customer_id = result.customer.id client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, _ = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, "options": { "fail_on_duplicate_payment_method": True } }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http.set_authorization_fingerprint(authorization_fingerprint) status_code, _ = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(422, status_code) customer = braintree.Customer.find(customer_id) self.assertEqual(1, len(customer.credit_cards)) def test_can_pass_merchant_account_id(self): expected_merchant_account_id = TestHelper.non_default_merchant_account_id client_token = TestHelper.generate_decoded_client_token({ "merchant_account_id": expected_merchant_account_id }) merchant_account_id = json.loads(client_token)["merchantAccountId"] self.assertEqual(expected_merchant_account_id, merchant_account_id) @raises_with_regexp(Exception, "'Invalid keys: merchant_id'") def test_required_data_cannot_be_overridden(self): TestHelper.generate_decoded_client_token({ "merchant_id": "1234" }) braintree_python-3.57.1/tests/integration/test_transaction.py0000644000175000017500000066526713545202423022736 0ustar hlehleimport json from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers from braintree.test.nonces import Nonces from braintree.dispute import Dispute from braintree.payment_instrument_type import PaymentInstrumentType import braintree.test.venmo_sdk as venmo_sdk class TestTransaction(unittest.TestCase): def test_sale(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, transaction.processor_response_type) def test_sale_returns_risk_data(self): with AdvancedFraudIntegrationMerchant(): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "device_session_id": "abc123", }) self.assertTrue(result.is_success) transaction = result.transaction self.assertIsInstance(transaction.risk_data, RiskData) self.assertNotEqual(transaction.risk_data.id, None) self.assertEqual(transaction.risk_data.decision, "Approve") self.assertTrue(hasattr(transaction.risk_data, 'device_data_captured')) def test_sale_receives_network_transaction_id_visa(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) self.assertTrue(len(result.transaction.network_transaction_id) > 0) def test_case_accepts_previous_network_transaction_id_mastercard(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.MasterCard, "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) self.assertTrue(len(result.transaction.network_transaction_id) > 0) def test_sale_does_not_accept_previous_network_transaction_id_elo(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Elo, "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) self.assertEqual(result.transaction, None) def test_sale_accepts_external_vault_status_visa(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "external_vault": { "status": "will_vault", } }) self.assertTrue(result.is_success) self.assertNotEqual(result.transaction.network_transaction_id, "") def test_sale_accepts_external_vault_status_mastercard(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.MasterCard, "expiration_date": "05/2009" }, "external_vault": { "status": "will_vault", } }) self.assertTrue(result.is_success) self.assertTrue(len(result.transaction.network_transaction_id) > 0) def test_sale_does_not_accept_external_vault_status_elo(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Elo, "expiration_date": "05/2009" }, "external_vault": { "status": "will_vault", } }) self.assertFalse(result.is_success) self.assertEqual(result.transaction, None) def test_sale_accepts_blank_external_vault_previous_network_transaction_id_non_visa(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.MasterCard, "expiration_date": "05/2009" }, "external_vault": { "status": "vaulted", "previous_network_transaction_id": "" } }) self.assertTrue(result.is_success) self.assertTrue(len(result.transaction.network_transaction_id) > 0) def test_sale_accepts_external_vault_status_vaulted_without_previous_network_transaction_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "external_vault": { "status": "vaulted", } }) self.assertTrue(result.is_success) self.assertNotEqual(result.transaction.network_transaction_id, "") def test_sale_accepts_external_vault_previous_network_transaction_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "external_vault": { "status": "vaulted", "previous_network_transaction_id": "123456789012345" } }) self.assertTrue(result.is_success) self.assertNotEqual(result.transaction.network_transaction_id, "") def test_sale_with_external_vault_validation_error_unsupported_payment_instrument_type(self): result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": Nonces.ApplePayVisa, "external_vault": { "status": "vaulted", "previous_network_transaction_id": "123456789012345" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.PaymentInstrumentWithExternalVaultIsInvalid, result.errors.for_object("transaction")[0].code ) def test_sale_with_external_vault_validation_error_invalid_status(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "external_vault": { "status": "bad value" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ExternalVault.StatusIsInvalid, result.errors.for_object("transaction").for_object("external_vault").on("status")[0].code ) def test_sale_with_external_vault_validation_error_invalid_status_with_previous_network_transaction_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "external_vault": { "status": "will_vault", "previous_network_transaction_id": "123456789012345" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ExternalVault.StatusWithPreviousNetworkTransactionIdIsInvalid, result.errors.for_object("transaction").for_object("external_vault").on("status")[0].code ) def test_sale_with_external_vault_discover_success(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Discover, "expiration_date": "05/2009" }, "external_vault": { "status": "vaulted", "previous_network_transaction_id": "123456789012345" } }) self.assertTrue(result.is_success) def test_sale_with_external_vault_validation_error_invalid_card_type(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Elo, "expiration_date": "05/2009" }, "external_vault": { "status": "vaulted", "previous_network_transaction_id": "123456789012345" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ExternalVault.CardTypeIsInvalid, result.errors.for_object("transaction").for_object("external_vault").on("previous_network_transaction_id")[0].code ) def test_sale_returns_a_successful_result_with_type_of_sale(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\w{6,}\Z", transaction.id)) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEqual("411111", transaction.credit_card_details.bin) self.assertEqual("1111", transaction.credit_card_details.last_4) self.assertEqual("05/2009", transaction.credit_card_details.expiration_date) self.assertEqual(None, transaction.voice_referral_number) def test_sale_allows_amount_as_a_decimal(self): result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\w{6,}\Z", transaction.id)) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEqual("411111", transaction.credit_card_details.bin) self.assertEqual("1111", transaction.credit_card_details.last_4) self.assertEqual("05/2009", transaction.credit_card_details.expiration_date) def test_sale_with_expiration_month_and_year_separately(self): result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2012" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual("05", transaction.credit_card_details.expiration_month) self.assertEqual("2012", transaction.credit_card_details.expiration_year) def test_sale_works_with_all_attributes(self): result = Transaction.sale({ "amount": "100.00", "order_id": "123", "channel": "MyShoppingCartProvider", "credit_card": { "cardholder_name": "The Cardholder", "number": "5105105105105100", "expiration_date": "05/2011", "cvv": "123" }, "customer": { "first_name": "Dan", "last_name": "Smith", "company": "Braintree", "email": "dan@example.com", "phone": "419-555-1234", "fax": "419-555-1235", "website": "http://braintreepayments.com" }, "billing": { "first_name": "Carl", "last_name": "Jones", "company": "Braintree", "street_address": "123 E Main St", "extended_address": "Suite 403", "locality": "Chicago", "region": "IL", "postal_code": "60622", "country_name": "United States of America", "country_code_alpha2": "US", "country_code_alpha3": "USA", "country_code_numeric": "840" }, "shipping": { "first_name": "Andrew", "last_name": "Mason", "company": "Braintree", "street_address": "456 W Main St", "extended_address": "Apt 2F", "locality": "Bartlett", "region": "IL", "postal_code": "60103", "country_name": "Mexico", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\w{6,}\Z", transaction.id)) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) self.assertEqual(Decimal("100.00"), transaction.amount) self.assertEqual("123", transaction.order_id) self.assertEqual("MyShoppingCartProvider", transaction.channel) self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(datetime, type(transaction.authorization_expires_at)) self.assertEqual(datetime, type(transaction.created_at)) self.assertEqual(datetime, type(transaction.updated_at)) self.assertEqual("510510", transaction.credit_card_details.bin) self.assertEqual("5100", transaction.credit_card_details.last_4) self.assertEqual("510510******5100", transaction.credit_card_details.masked_number) self.assertEqual("MasterCard", transaction.credit_card_details.card_type) self.assertEqual("The Cardholder", transaction.credit_card_details.cardholder_name) self.assertEqual(None, transaction.avs_error_response_code) self.assertEqual("M", transaction.avs_postal_code_response_code) self.assertEqual("M", transaction.avs_street_address_response_code) self.assertEqual("Dan", transaction.customer_details.first_name) self.assertEqual("Smith", transaction.customer_details.last_name) self.assertEqual("Braintree", transaction.customer_details.company) self.assertEqual("dan@example.com", transaction.customer_details.email) self.assertEqual("419-555-1234", transaction.customer_details.phone) self.assertEqual("419-555-1235", transaction.customer_details.fax) self.assertEqual("http://braintreepayments.com", transaction.customer_details.website) self.assertEqual("Carl", transaction.billing_details.first_name) self.assertEqual("Jones", transaction.billing_details.last_name) self.assertEqual("Braintree", transaction.billing_details.company) self.assertEqual("123 E Main St", transaction.billing_details.street_address) self.assertEqual("Suite 403", transaction.billing_details.extended_address) self.assertEqual("Chicago", transaction.billing_details.locality) self.assertEqual("IL", transaction.billing_details.region) self.assertEqual("60622", transaction.billing_details.postal_code) self.assertEqual("United States of America", transaction.billing_details.country_name) self.assertEqual("US", transaction.billing_details.country_code_alpha2) self.assertEqual("USA", transaction.billing_details.country_code_alpha3) self.assertEqual("840", transaction.billing_details.country_code_numeric) self.assertEqual("Andrew", transaction.shipping_details.first_name) self.assertEqual("Mason", transaction.shipping_details.last_name) self.assertEqual("Braintree", transaction.shipping_details.company) self.assertEqual("456 W Main St", transaction.shipping_details.street_address) self.assertEqual("Apt 2F", transaction.shipping_details.extended_address) self.assertEqual("Bartlett", transaction.shipping_details.locality) self.assertEqual("IL", transaction.shipping_details.region) self.assertEqual("60103", transaction.shipping_details.postal_code) self.assertEqual("Mexico", transaction.shipping_details.country_name) self.assertEqual("MX", transaction.shipping_details.country_code_alpha2) self.assertEqual("MEX", transaction.shipping_details.country_code_alpha3) self.assertEqual("484", transaction.shipping_details.country_code_numeric) self.assertEqual(None, transaction.additional_processor_response) def test_sale_with_vault_customer_and_credit_card_data(self): customer = Customer.create({ "first_name": "Pingu", "last_name": "Penguin", }).customer result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "customer_id": customer.id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.credit_card_details.masked_number, "411111******1111") self.assertEqual(None, transaction.vault_credit_card) def test_sale_with_vault_customer_and_credit_card_data_and_store_in_vault(self): customer = Customer.create({ "first_name": "Pingu", "last_name": "Penguin", }).customer result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "customer_id": customer.id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "store_in_vault": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("411111******1111", transaction.credit_card_details.masked_number) self.assertEqual("411111******1111", transaction.vault_credit_card.masked_number) def test_sale_with_venmo_merchant_data(self): result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "venmo_merchant_data": { "venmo_merchant_public_id": "12345", "originating_transaction_id": "abc123", "originating_merchant_id": "xyz123", "originating_merchant_kind": "braintree", } } }) self.assertTrue(result.is_success) def test_sale_with_custom_fields(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "custom_fields": { "store_me": "some extra stuff" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("some extra stuff", transaction.custom_fields["store_me"]) def test_sale_with_merchant_account_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(TestHelper.non_default_merchant_account_id, transaction.merchant_account_id) def test_sale_without_merchant_account_id_falls_back_to_default(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(TestHelper.default_merchant_account_id, transaction.merchant_account_id) def test_sale_with_shipping_address_id(self): result = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010" } }) self.assertTrue(result.is_success) customer = result.customer result = Address.create({ "customer_id": customer.id, "street_address": "123 Fake St." }) self.assertTrue(result.is_success) address = result.address result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "customer_id": customer.id, "shipping_address_id": address.id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("123 Fake St.", transaction.shipping_details.street_address) self.assertEqual(address.id, transaction.shipping_details.id) def test_sale_with_risk_data_security_parameters(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "risk_data": { "customer_browser": "IE7", "customer_ip": "192.168.0.1" } }) self.assertTrue(result.is_success) def test_sale_with_billing_address_id(self): result = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010" } }) self.assertTrue(result.is_success) customer = result.customer result = Address.create({ "customer_id": customer.id, "street_address": "123 Fake St." }) self.assertTrue(result.is_success) address = result.address result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "customer_id": customer.id, "billing_address_id": address.id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("123 Fake St.", transaction.billing_details.street_address) self.assertEqual(address.id, transaction.billing_details.id) def test_sale_with_device_session_id_and_fraud_merchant_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010" }, "device_session_id": "abc123", "fraud_merchant_id": "456" }) self.assertTrue(result.is_success) def test_sale_with_level_2(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "purchase_order_number": "12345", "tax_amount": Decimal("10.00"), "tax_exempt": True, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("12345", transaction.purchase_order_number) self.assertEqual(Decimal("10.00"), transaction.tax_amount) self.assertEqual(True, transaction.tax_exempt) def test_create_with_invalid_tax_amount(self): result = Transaction.sale({ "amount": Decimal("100"), "tax_amount": "asdf", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) tax_amount_errors = result.errors.for_object("transaction").on("tax_amount") self.assertEqual(1, len(tax_amount_errors)) self.assertEqual(ErrorCodes.Transaction.TaxAmountFormatIsInvalid, tax_amount_errors[0].code) def test_create_with_too_long_purchase_order_number(self): result = Transaction.sale({ "amount": Decimal("100"), "purchase_order_number": "aaaaaaaaaaaaaaaaaa", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) purchase_order_number_errors = result.errors.for_object("transaction").on("purchase_order_number") self.assertEqual(1, len(purchase_order_number_errors)) self.assertEqual(ErrorCodes.Transaction.PurchaseOrderNumberIsTooLong, purchase_order_number_errors[0].code) def test_create_with_invalid_purchase_order_number(self): result = Transaction.sale({ "amount": Decimal("100"), "purchase_order_number": "\xc3\x9f\xc3\xa5\xe2\x88\x82", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) purchase_order_number_errors = result.errors.for_object("transaction").on("purchase_order_number") self.assertEqual(1, len(purchase_order_number_errors)) self.assertEqual(ErrorCodes.Transaction.PurchaseOrderNumberIsInvalid, purchase_order_number_errors[0].code) def test_sale_with_level_3(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "purchase_order_number": "12345", "discount_amount": Decimal("1.00"), "shipping_amount": Decimal("2.00"), "ships_from_postal_code": "12345", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal("1.00"), transaction.discount_amount) self.assertEqual(Decimal("2.00"), transaction.shipping_amount) self.assertEqual("12345", transaction.ships_from_postal_code) def test_create_with_discount_amount_invalid(self): result = Transaction.sale({ "amount": Decimal("100"), "discount_amount": "asdf", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("discount_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.DiscountAmountFormatIsInvalid, errors[0].code) def test_create_with_discount_amount_negative(self): result = Transaction.sale({ "amount": Decimal("100"), "discount_amount": Decimal("-100"), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("discount_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.DiscountAmountCannotBeNegative, errors[0].code) def test_create_with_discount_amount_too_large(self): result = Transaction.sale({ "amount": Decimal("100"), "discount_amount": Decimal("999999999"), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("discount_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.DiscountAmountIsTooLarge, errors[0].code) def test_create_with_shipping_amount_invalid(self): result = Transaction.sale({ "amount": Decimal("100"), "shipping_amount": "asdf", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("shipping_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ShippingAmountFormatIsInvalid, errors[0].code) def test_create_with_shipping_amount_negative(self): result = Transaction.sale({ "amount": Decimal("100"), "shipping_amount": Decimal("-100"), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("shipping_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ShippingAmountCannotBeNegative, errors[0].code) def test_create_with_shipping_amount_too_large(self): result = Transaction.sale({ "amount": Decimal("100"), "shipping_amount": Decimal("999999999"), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("shipping_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ShippingAmountIsTooLarge, errors[0].code) def test_create_with_ships_from_postal_code_is_too_long(self): result = Transaction.sale({ "amount": Decimal("100"), "ships_from_postal_code": "0000000000", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("ships_from_postal_code") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ShipsFromPostalCodeIsTooLong, errors[0].code) def test_create_with_ships_from_postal_code_invalid_characters(self): result = Transaction.sale({ "amount": Decimal("100"), "ships_from_postal_code": "1$345", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("ships_from_postal_code") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ShipsFromPostalCodeInvalidCharacters, errors[0].code) def test_sale_with_soft_declined(self): result = Transaction.sale({ "amount": TransactionAmounts.Decline, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Status.ProcessorDeclined, transaction.status) self.assertEqual(ProcessorResponseTypes.SoftDeclined, transaction.processor_response_type) self.assertEqual("2000 : Do Not Honor", transaction.additional_processor_response) def test_sale_with_hard_declined(self): result = Transaction.sale({ "amount": TransactionAmounts.HardDecline, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Status.ProcessorDeclined, transaction.status) self.assertEqual(ProcessorResponseTypes.HardDeclined, transaction.processor_response_type) self.assertEqual("2015 : Transaction Not Allowed", transaction.additional_processor_response) def test_sale_with_gateway_rejected_with_incomplete_application(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret", environment=Environment.Development ) result = gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, environment=Environment.Development ) result = gateway.transaction.sale({ "amount": "4000.00", "billing": { "street_address": "200 Fake Street" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.GatewayRejectionReason.ApplicationIncomplete, transaction.gateway_rejection_reason) def test_sale_with_gateway_rejected_with_avs(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "billing": { "street_address": "200 Fake Street" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.GatewayRejectionReason.Avs, transaction.gateway_rejection_reason) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_sale_with_gateway_rejected_with_avs_and_cvv(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "billing": { "postal_code": "20000" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "200" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.GatewayRejectionReason.AvsAndCvv, transaction.gateway_rejection_reason) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_sale_with_gateway_rejected_with_cvv(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "200" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.GatewayRejectionReason.Cvv, transaction.gateway_rejection_reason) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_sale_with_gateway_rejected_with_fraud(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4000111111111511", "expiration_date": "05/2017", "cvv": "333" } }) self.assertFalse(result.is_success) self.assertEqual(Transaction.GatewayRejectionReason.Fraud, result.transaction.gateway_rejection_reason) def test_sale_with_gateway_rejected_token_issuance(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.fake_venmo_account_merchant_account_id, "payment_method_nonce": Nonces.VenmoAccountTokenIssuanceError }) self.assertFalse(result.is_success) self.assertEqual(Transaction.GatewayRejectionReason.TokenIssuance, result.transaction.gateway_rejection_reason) def test_sale_with_service_fee(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "service_fee_amount": "1.00" }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.service_fee_amount, "1.00") def test_sale_on_master_merchant_accoount_is_invalid_with_service_fee(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "service_fee_amount": "1.00" }) self.assertFalse(result.is_success) amount_errors = result.errors.for_object("transaction").on("service_fee_amount") self.assertEqual(1, len(amount_errors)) self.assertEqual(ErrorCodes.Transaction.ServiceFeeAmountNotAllowedOnMasterMerchantAccount, amount_errors[0].code) def test_sale_on_submerchant_is_invalid_without_with_service_fee(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.SubMerchantAccountRequiresServiceFeeAmount, result.errors.for_object("transaction").on("merchant_account_id")[0].code ) def test_sale_with_hold_in_escrow_option(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "hold_in_escrow": True }, "service_fee_amount": "1.00" }) self.assertTrue(result.is_success) self.assertEqual( Transaction.EscrowStatus.HoldPending, result.transaction.escrow_status ) def test_sale_with_hold_in_escrow_option_fails_for_master_merchant_account(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "hold_in_escrow": True } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotHoldInEscrow, result.errors.for_object("transaction").on("base")[0].code ) def test_hold_in_escrow_after_sale(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "service_fee_amount": "1.00" }) self.assertTrue(result.is_success) result = Transaction.hold_in_escrow(result.transaction.id) self.assertTrue(result.is_success) self.assertEqual( Transaction.EscrowStatus.HoldPending, result.transaction.escrow_status ) def test_hold_in_escrow_after_sale_fails_for_master_merchant_account(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) result = Transaction.hold_in_escrow(result.transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotHoldInEscrow, result.errors.for_object("transaction").on("base")[0].code ) def test_release_from_escrow_from_escrow(self): transaction = self.__create_escrowed_transaction() result = Transaction.release_from_escrow(transaction.id) self.assertTrue(result.is_success) self.assertEqual( Transaction.EscrowStatus.ReleasePending, result.transaction.escrow_status ) def test_release_from_escrow_from_escrow_fails_when_transaction_not_in_escrow(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) result = Transaction.release_from_escrow(result.transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotReleaseFromEscrow, result.errors.for_object("transaction").on("base")[0].code ) def test_cancel_release_from_escrow(self): transaction = self.__create_escrowed_transaction() submit_result = Transaction.release_from_escrow(transaction.id) result = Transaction.cancel_release(submit_result.transaction.id) self.assertTrue(result.is_success) self.assertEqual( Transaction.EscrowStatus.Held, result.transaction.escrow_status ) def test_cancel_release_from_escrow_fails_if_transaction_is_not_pending_release(self): transaction = self.__create_escrowed_transaction() result = Transaction.cancel_release(transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotCancelRelease, result.errors.for_object("transaction").on("base")[0].code ) def test_sale_with_venmo_sdk_session(self): result = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "venmo_sdk_session": venmo_sdk.Session } }) self.assertTrue(result.is_success) self.assertFalse(result.transaction.credit_card_details.venmo_sdk) def test_sale_with_venmo_sdk_payment_method_code(self): result = Transaction.sale({ "amount": "10.00", "venmo_sdk_payment_method_code": venmo_sdk.VisaPaymentMethodCode }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("411111", transaction.credit_card_details.bin) def test_sale_with_payment_method_nonce(self): config = Configuration.instantiate() parsed_client_token = TestHelper.generate_decoded_client_token() authorization_fingerprint = json.loads(parsed_client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) _, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) nonce = json.loads(response)["creditCards"][0]["nonce"] result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": nonce }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("411111", transaction.credit_card_details.bin) def test_sale_with_fake_apple_pay_nonce(self): result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": Nonces.ApplePayAmEx }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.amount, 10.00) self.assertEqual(result.transaction.payment_instrument_type, PaymentInstrumentType.ApplePayCard) apple_pay_details = result.transaction.apple_pay_details self.assertNotEqual(None, apple_pay_details) self.assertEqual(ApplePayCard.CardType.AmEx, apple_pay_details.card_type) self.assertEqual("AmEx 41002", apple_pay_details.payment_instrument_name) self.assertTrue(int(apple_pay_details.expiration_month) > 0) self.assertTrue(int(apple_pay_details.expiration_year) > 0) self.assertNotEqual(None, apple_pay_details.cardholder_name) def test_sale_with_fake_android_pay_proxy_card_nonce(self): result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": Nonces.AndroidPayCardDiscover }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.amount, 10.00) self.assertEqual(result.transaction.payment_instrument_type, PaymentInstrumentType.AndroidPayCard) android_pay_card_details = result.transaction.android_pay_card_details self.assertNotEqual(None, android_pay_card_details) self.assertEqual(CreditCard.CardType.Discover, android_pay_card_details.card_type) self.assertTrue(int(android_pay_card_details.expiration_month) > 0) self.assertTrue(int(android_pay_card_details.expiration_year) > 0) def test_sale_with_fake_android_pay_network_token_nonce(self): result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": Nonces.AndroidPayCardMasterCard }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.amount, 10.00) self.assertEqual(result.transaction.payment_instrument_type, PaymentInstrumentType.AndroidPayCard) android_pay_card_details = result.transaction.android_pay_card_details self.assertNotEqual(None, android_pay_card_details) self.assertEqual(CreditCard.CardType.MasterCard, android_pay_card_details.card_type) self.assertTrue(int(android_pay_card_details.expiration_month) > 0) self.assertTrue(int(android_pay_card_details.expiration_year) > 0) def test_sale_with_fake_amex_express_checkout_card_nonce(self): result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": Nonces.AmexExpressCheckoutCard, "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.amount, 10.00) self.assertEqual(result.transaction.payment_instrument_type, PaymentInstrumentType.AmexExpressCheckoutCard) amex_express_checkout_card_details = result.transaction.amex_express_checkout_card_details self.assertNotEqual(None, amex_express_checkout_card_details) self.assertEqual(CreditCard.CardType.AmEx, amex_express_checkout_card_details.card_type) self.assertTrue(int(amex_express_checkout_card_details.expiration_month) > 0) self.assertTrue(int(amex_express_checkout_card_details.expiration_year) > 0) def test_sale_with_fake_venmo_account_nonce(self): result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": Nonces.VenmoAccount, "merchant_account_id": TestHelper.fake_venmo_account_merchant_account_id, }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.amount, 10.00) self.assertEqual(result.transaction.payment_instrument_type, PaymentInstrumentType.VenmoAccount) venmo_account_details = result.transaction.venmo_account_details self.assertIsNotNone(venmo_account_details) self.assertEqual(venmo_account_details.username, "venmojoe") self.assertEqual(venmo_account_details.venmo_user_id, "Venmo-Joe-1") def test_sale_with_fake_venmo_account_nonce_and_profile_id(self): result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": Nonces.VenmoAccount, "merchant_account_id": TestHelper.fake_venmo_account_merchant_account_id, "options": { "venmo": { "profile_id": "integration_venmo_merchant_public_id", }, }, }) self.assertTrue(result.is_success) def test_sale_with_advanced_fraud_checking_skipped(self): with AdvancedFraudIntegrationMerchant(): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "skip_advanced_fraud_checking": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.risk_data, None) def test_sale_with_skip_cvv_option_set(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "skip_cvv": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.cvv_response_code, "B") def test_sale_with_skip_avs_option_set(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "skip_avs": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.avs_error_response_code, None) self.assertEqual(transaction.avs_street_address_response_code, "B") def test_sale_with_line_items_zero(self): result = Transaction.sale({ "amount": "45.15", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", } }) self.assertTrue(result.is_success) transaction = result.transaction line_items = transaction.line_items self.assertEqual(0, len(line_items)) def test_sale_with_line_items_single_only_required_fields(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "total_amount": "45.15", }] }) self.assertTrue(result.is_success) transaction = result.transaction line_items = transaction.line_items self.assertEqual(1, len(line_items)) lineItem = line_items[0] self.assertEqual("1.0232", lineItem.quantity) self.assertEqual("Name #1", lineItem.name) self.assertEqual(TransactionLineItem.Kind.Debit, lineItem.kind) self.assertEqual("45.1232", lineItem.unit_amount) self.assertEqual("45.15", lineItem.total_amount) def test_sale_with_line_items_single(self): result = Transaction.sale({ "amount": "45.15", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "description": "Description #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_tax_amount": "1.23", "unit_of_measure": "gallon", "discount_amount": "1.02", "tax_amount": "4.50", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", "url": "https://example.com/products/23434", }] }) self.assertTrue(result.is_success) transaction = result.transaction line_items = transaction.line_items self.assertEqual(1, len(line_items)) lineItem = line_items[0] self.assertEqual("1.0232", lineItem.quantity) self.assertEqual("Name #1", lineItem.name) self.assertEqual("Description #1", lineItem.description) self.assertEqual(TransactionLineItem.Kind.Debit, lineItem.kind) self.assertEqual("45.1232", lineItem.unit_amount) self.assertEqual("1.23", lineItem.unit_tax_amount) self.assertEqual("gallon", lineItem.unit_of_measure) self.assertEqual("1.02", lineItem.discount_amount) self.assertEqual("4.50", lineItem.tax_amount) self.assertEqual("45.15", lineItem.total_amount) self.assertEqual("23434", lineItem.product_code) self.assertEqual("9SAASSD8724", lineItem.commodity_code) self.assertEqual("https://example.com/products/23434", lineItem.url) def test_sale_with_line_items_multiple(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "description": "Description #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "tax_amount": "4.50", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "2.02", "name": "Name #2", "description": "Description #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "5", "unit_of_measure": "gallon", "tax_amount": "4.50", "total_amount": "45.15", }] }) self.assertTrue(result.is_success) transaction = result.transaction line_items = transaction.line_items self.assertEqual(2, len(line_items)) line_item_1 = None for line_item in line_items: if line_item.name == "Name #1": line_item_1 = line_item break if line_item_1 is None: self.fail("TransactionLineItem with name \"Name #1\" not returned.") self.assertEqual("1.0232", line_item_1.quantity) self.assertEqual("Name #1", line_item_1.name) self.assertEqual("Description #1", line_item_1.description) self.assertEqual(TransactionLineItem.Kind.Debit, line_item_1.kind) self.assertEqual("45.1232", line_item_1.unit_amount) self.assertEqual("gallon", line_item_1.unit_of_measure) self.assertEqual("1.02", line_item_1.discount_amount) self.assertEqual("45.15", line_item_1.total_amount) self.assertEqual("23434", line_item_1.product_code) self.assertEqual("9SAASSD8724", line_item_1.commodity_code) line_item_2 = None for line_item in line_items: if line_item.name == "Name #2": line_item_2 = line_item break if line_item_2 is None: self.fail("TransactionLineItem with name \"Name #2\" not returned.") self.assertEqual("2.02", line_item_2.quantity) self.assertEqual("Name #2", line_item_2.name) self.assertEqual("Description #2", line_item_2.description) self.assertEqual(TransactionLineItem.Kind.Credit, line_item_2.kind) self.assertEqual("5", line_item_2.unit_amount) self.assertEqual("gallon", line_item_2.unit_of_measure) self.assertEqual("45.15", line_item_2.total_amount) self.assertEqual(None, line_item_2.discount_amount) self.assertEqual(None, line_item_2.product_code) self.assertEqual(None, line_item_2.commodity_code) def test_sale_with_line_items_with_zero_amount_fields(self): result = Transaction.sale({ "amount": "45.15", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "total_amount": "45.15", "discount_amount": "0", "unit_tax_amount": "0", "tax_amount": "0", }] }) self.assertTrue(result.is_success) transaction = result.transaction line_items = transaction.line_items lineItem = line_items[0] self.assertEqual("0.00", lineItem.unit_tax_amount) self.assertEqual("0.00", lineItem.discount_amount) self.assertEqual("0.00", lineItem.tax_amount) def test_sale_with_line_items_validation_error_commodity_code_is_too_long(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "0123456789123", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.CommodityCodeIsTooLong, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("commodity_code")[0].code ) def test_sale_with_line_items_validation_error_description_is_too_long(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "description": "This is a line item description which is far too long. Like, way too long to be practical. We don't like how long this line item description is.", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.DescriptionIsTooLong, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("description")[0].code ) def test_sale_with_line_items_validation_error_discount_amount_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "2147483648", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.DiscountAmountIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("discount_amount")[0].code ) def test_sale_with_line_items_validation_error_discount_amount_cannot_be_negative(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "-1.23", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.DiscountAmountCannotBeNegative, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("discount_amount")[0].code ) def test_sale_with_line_items_validation_error_tax_amount_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "tax_amount": "2147483648", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TaxAmountIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_0").on("tax_amount")[0].code ) def test_sale_with_line_items_validation_error_tax_amount_cannot_be_negative(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "tax_amount": "-1.23", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TaxAmountCannotBeNegative, result.errors.for_object("transaction").for_object("line_items").for_object("index_0").on("tax_amount")[0].code ) def test_sale_with_line_items_validation_error_tax_amount_format_is_invalid(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "tax_amount": "4.555", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TaxAmountFormatIsInvalid, result.errors.for_object("transaction").for_object("line_items").for_object("index_0").on("tax_amount")[0].code ) def test_sale_with_line_items_validation_error_kind_is_required(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.KindIsRequired, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("kind")[0].code ) def test_sale_with_line_items_validation_error_name_is_required(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.NameIsRequired, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("name")[0].code ) def test_sale_with_line_items_validation_error_name_is_too_long(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "123456789012345678901234567890123456", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.NameIsTooLong, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("name")[0].code ) def test_sale_with_line_items_validation_error_product_code_is_too_long(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "123456789012345678901234567890123456", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.ProductCodeIsTooLong, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("product_code")[0].code ) def test_sale_with_line_items_validation_error_quantity_is_required(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.QuantityIsRequired, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("quantity")[0].code ) def test_sale_with_line_items_validation_error_quantity_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "2147483648", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.QuantityIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("quantity")[0].code ) def test_sale_with_line_items_validation_error_total_amount_is_required(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TotalAmountIsRequired, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("total_amount")[0].code ) def test_sale_with_line_items_validation_error_total_amount_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "2147483648", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TotalAmountIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("total_amount")[0].code ) def test_sale_with_line_items_validation_error_total_amount_must_be_greater_than_zero(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "-2", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TotalAmountMustBeGreaterThanZero, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("total_amount")[0].code ) def test_sale_with_line_items_validation_error_unit_amount_is_required(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitAmountIsRequired, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_amount")[0].code ) def test_sale_with_line_items_validation_error_unit_amount_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "2147483648", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitAmountIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_amount")[0].code ) def test_sale_with_line_items_validation_error_unit_amount_must_be_greater_than_zero(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "-2", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitAmountMustBeGreaterThanZero, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_amount")[0].code ) def test_sale_with_amount_not_supported_by_processor(self): result = Transaction.sale({ "amount": "0.2", "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.AmountNotSupportedByProcessor, result.errors.for_object("transaction")[0].code ) def test_sale_with_line_items_validation_error_unit_of_measure_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "1234567890123", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitOfMeasureIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_of_measure")[0].code ) def test_sale_with_line_items_validation_error_unit_tax_amount_format_is_invalid(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.2322", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.2322", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.0122", "unit_tax_amount": "2.012", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitTaxAmountFormatIsInvalid, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_tax_amount")[0].code ) def test_sale_with_line_items_validation_error_unit_tax_amount_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.2322", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_tax_amount": "1.23", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.2322", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.0122", "unit_tax_amount": "2147483648", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitTaxAmountIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_tax_amount")[0].code ) def test_sale_with_line_items_validation_error_unit_tax_amount_cannot_be_negative(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.2322", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.2322", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.0122", "unit_tax_amount": "-1.23", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitTaxAmountCannotBeNegative, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_tax_amount")[0].code ) def test_sale_with_line_items_validation_error_too_many_live_items(self): sale_params = { "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [], } for i in range(250): sale_params["line_items"].append({ "quantity": "2.02", "name": "Line item #" + str(i), "kind": TransactionLineItem.Kind.Credit, "unit_amount": "5", "unit_of_measure": "gallon", "total_amount": "10.1", }) result = Transaction.sale(sale_params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.TooManyLineItems, result.errors.for_object("transaction").on("line_items")[0].code ) def test_validation_error_on_invalid_custom_fields(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "custom_fields": { "invalid_key": "some extra stuff" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CustomFieldIsInvalid, result.errors.for_object("transaction").on("custom_fields")[0].code ) def test_card_type_indicators(self): result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": CreditCardNumbers.CardTypeIndicators.Unknown, "expiration_month": "05", "expiration_year": "2012" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(CreditCard.Prepaid.Unknown, transaction.credit_card_details.prepaid) self.assertEqual(CreditCard.Debit.Unknown, transaction.credit_card_details.debit) self.assertEqual(CreditCard.Commercial.Unknown, transaction.credit_card_details.commercial) self.assertEqual(CreditCard.Healthcare.Unknown, transaction.credit_card_details.healthcare) self.assertEqual(CreditCard.Payroll.Unknown, transaction.credit_card_details.payroll) self.assertEqual(CreditCard.DurbinRegulated.Unknown, transaction.credit_card_details.durbin_regulated) self.assertEqual(CreditCard.CardTypeIndicator.Unknown, transaction.credit_card_details.issuing_bank) self.assertEqual(CreditCard.CardTypeIndicator.Unknown, transaction.credit_card_details.country_of_issuance) self.assertEqual(CreditCard.ProductId.Unknown, transaction.credit_card_details.product_id) def test_create_can_set_recurring_flag(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "recurring": True }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(True, transaction.recurring) def test_create_can_set_transaction_source_flag_recurring_first(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "recurring_first" }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(True, transaction.recurring) def test_create_can_set_transaction_source_flag_recurring(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "recurring" }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(True, transaction.recurring) def test_create_can_set_transaction_source_flag_merchant(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "merchant" }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(False, transaction.recurring) def test_create_can_set_transaction_source_flag_moto(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "moto" }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(False, transaction.recurring) def test_create_can_set_transaction_source_flag_invalid(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "invalid_value" }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.TransactionSourceIsInvalid, result.errors.for_object("transaction").on("transaction_source")[0].code ) def test_create_can_store_customer_and_credit_card_in_the_vault(self): result = Transaction.sale({ "amount": "100", "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "store_in_vault": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", transaction.customer_details.id)) self.assertEqual(transaction.customer_details.id, transaction.vault_customer.id) self.assertNotEqual(None, re.search(r"\A\w{4,}\Z", transaction.credit_card_details.token)) self.assertEqual(transaction.credit_card_details.token, transaction.vault_credit_card.token) def test_create_can_store_customer_and_credit_card_in_the_vault_on_success(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "store_in_vault_on_success": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", transaction.customer_details.id)) self.assertEqual(transaction.customer_details.id, transaction.vault_customer.id) self.assertNotEqual(None, re.search(r"\A\w{4,}\Z", transaction.credit_card_details.token)) self.assertEqual(transaction.credit_card_details.token, transaction.vault_credit_card.token) def test_create_does_not_store_customer_and_credit_card_in_the_vault_on_failure(self): result = Transaction.sale({ "amount": TransactionAmounts.Decline, "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "store_in_vault_on_success": True } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(None, transaction.customer_details.id) self.assertEqual(None, transaction.credit_card_details.token) self.assertEqual(None, transaction.vault_customer) self.assertEqual(None, transaction.vault_credit_card) def test_create_associated_a_billing_address_with_credit_card_in_vault(self): result = Transaction.sale({ "amount": "100", "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "5105105105105100", "expiration_date": "05/2012" }, "billing": { "first_name": "Carl", "last_name": "Jones", "company": "Braintree", "street_address": "123 E Main St", "extended_address": "Suite 403", "locality": "Chicago", "region": "IL", "postal_code": "60622", "country_name": "United States of America" }, "options": { "store_in_vault": True, "add_billing_address_to_payment_method": True, } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", transaction.customer_details.id)) self.assertEqual(transaction.customer_details.id, transaction.vault_customer.id) credit_card = CreditCard.find(transaction.vault_credit_card.token) self.assertEqual(credit_card.billing_address.id, transaction.billing_details.id) self.assertEqual(credit_card.billing_address.id, transaction.vault_billing_address.id) self.assertEqual("Carl", credit_card.billing_address.first_name) self.assertEqual("Jones", credit_card.billing_address.last_name) self.assertEqual("Braintree", credit_card.billing_address.company) self.assertEqual("123 E Main St", credit_card.billing_address.street_address) self.assertEqual("Suite 403", credit_card.billing_address.extended_address) self.assertEqual("Chicago", credit_card.billing_address.locality) self.assertEqual("IL", credit_card.billing_address.region) self.assertEqual("60622", credit_card.billing_address.postal_code) self.assertEqual("United States of America", credit_card.billing_address.country_name) def test_create_and_store_the_shipping_address_in_the_vault(self): result = Transaction.sale({ "amount": "100", "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "5105105105105100", "expiration_date": "05/2012" }, "shipping": { "first_name": "Carl", "last_name": "Jones", "company": "Braintree", "street_address": "123 E Main St", "extended_address": "Suite 403", "locality": "Chicago", "region": "IL", "postal_code": "60622", "country_name": "United States of America" }, "options": { "store_in_vault": True, "store_shipping_address_in_vault": True, } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", transaction.customer_details.id)) self.assertEqual(transaction.customer_details.id, transaction.vault_customer.id) shipping_address = transaction.vault_customer.addresses[0] self.assertEqual("Carl", shipping_address.first_name) self.assertEqual("Jones", shipping_address.last_name) self.assertEqual("Braintree", shipping_address.company) self.assertEqual("123 E Main St", shipping_address.street_address) self.assertEqual("Suite 403", shipping_address.extended_address) self.assertEqual("Chicago", shipping_address.locality) self.assertEqual("IL", shipping_address.region) self.assertEqual("60622", shipping_address.postal_code) self.assertEqual("United States of America", shipping_address.country_name) def test_create_submits_for_settlement_if_given_submit_for_settlement_option(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2012" }, "options": { "submit_for_settlement": True } }) self.assertTrue(result.is_success) self.assertEqual(Transaction.Status.SubmittedForSettlement, result.transaction.status) def test_create_does_not_submit_for_settlement_if_submit_for_settlement_is_false(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2012" }, "options": { "submit_for_settlement": False } }) self.assertTrue(result.is_success) self.assertEqual(Transaction.Status.Authorized, result.transaction.status) def test_create_can_specify_the_customer_id_and_payment_method_token(self): customer_id = "customer_" + str(random.randint(1, 1000000)) payment_method_token = "credit_card_" + str(random.randint(1, 1000000)) result = Transaction.sale({ "amount": "100", "customer": { "id": customer_id, "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "token": payment_method_token, "number": "5105105105105100", "expiration_date": "05/2012" }, "options": { "store_in_vault": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(customer_id, transaction.customer_details.id) self.assertEqual(customer_id, transaction.vault_customer.id) self.assertEqual(payment_method_token, transaction.credit_card_details.token) self.assertEqual(payment_method_token, transaction.vault_credit_card.token) def test_create_using_customer_id(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }) self.assertTrue(result.is_success) customer = result.customer credit_card = customer.credit_cards[0] result = Transaction.sale({ "amount": "100", "customer_id": customer.id }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(customer.id, transaction.customer_details.id) self.assertEqual(customer.id, transaction.vault_customer.id) self.assertEqual(credit_card.token, transaction.credit_card_details.token) self.assertEqual(credit_card.token, transaction.vault_credit_card.token) def test_create_using_payment_method_token(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }) self.assertTrue(result.is_success) customer = result.customer credit_card = customer.credit_cards[0] result = Transaction.sale({ "amount": "100", "payment_method_token": credit_card.token }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(customer.id, transaction.customer_details.id) self.assertEqual(customer.id, transaction.vault_customer.id) self.assertEqual(credit_card.token, transaction.credit_card_details.token) self.assertEqual(credit_card.token, transaction.vault_credit_card.token) def test_create_using_payment_method_token_with_cvv(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }) self.assertTrue(result.is_success) customer = result.customer credit_card = customer.credit_cards[0] result = Transaction.sale({ "amount": "100", "payment_method_token": credit_card.token, "credit_card": { "cvv": "301" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(customer.id, transaction.customer_details.id) self.assertEqual(customer.id, transaction.vault_customer.id) self.assertEqual(credit_card.token, transaction.credit_card_details.token) self.assertEqual(credit_card.token, transaction.vault_credit_card.token) self.assertEqual("S", transaction.cvv_response_code) def test_create_with_failing_validations(self): params = { "transaction": { "amount": None, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } } } result = Transaction.sale(params["transaction"]) params["transaction"]["credit_card"].pop("number") self.assertFalse(result.is_success) self.assertEqual(params, result.params) self.assertEqual( ErrorCodes.Transaction.AmountIsRequired, result.errors.for_object("transaction").on("amount")[0].code ) def test_credit_with_a_successful_result(self): result = Transaction.credit({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\w{6,}\Z", transaction.id)) self.assertEqual(Transaction.Type.Credit, transaction.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) cc_details = transaction.credit_card_details self.assertEqual("411111", cc_details.bin) self.assertEqual("1111", cc_details.last_4) self.assertEqual("05/2009", cc_details.expiration_date) def test_credit_with_unsuccessful_result(self): result = Transaction.credit({ "amount": None, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) params = { "transaction": { "type": Transaction.Type.Credit, "amount": None, "credit_card": { "expiration_date": "05/2009" } } } self.assertFalse(result.is_success) self.assertEqual(params, result.params) self.assertEqual( ErrorCodes.Transaction.AmountIsRequired, result.errors.for_object("transaction").on("amount")[0].code ) def test_credit_card_payment_instrument_type_is_credit_card(self): result = Transaction.credit({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual( PaymentInstrumentType.CreditCard, transaction.payment_instrument_type ) def test_service_fee_not_allowed_with_credits(self): result = Transaction.credit({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "service_fee_amount": "1.00" }) self.assertFalse(result.is_success) self.assertTrue( ErrorCodes.Transaction.ServiceFeeIsNotAllowedOnCredits in [error.code for error in result.errors.for_object("transaction").on("base")] ) def test_credit_with_merchant_account_id(self): result = Transaction.credit({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(TestHelper.non_default_merchant_account_id, transaction.merchant_account_id) def test_credit_without_merchant_account_id_falls_back_to_default(self): result = Transaction.credit({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(TestHelper.default_merchant_account_id, transaction.merchant_account_id) def test_find_returns_a_found_transaction(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Fail, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction TestHelper.settle_transaction(transaction.id) found_transaction = Transaction.find(transaction.id) self.assertEqual(transaction.id, found_transaction.id) @raises_with_regexp(NotFoundError, "transaction with id 'notreal' not found") def test_find_for_bad_transaction_raises_not_found_error(self): Transaction.find("notreal") def test_void_with_successful_result(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction result = Transaction.void(transaction.id) self.assertTrue(result.is_success) self.assertEqual(transaction.id, result.transaction.id) self.assertEqual(Transaction.Status.Voided, result.transaction.status) def test_void_with_unsuccessful_result(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Decline, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction result = Transaction.void(transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotBeVoided, result.errors.for_object("transaction").on("base")[0].code ) def test_create_with_successful_result(self): result = Transaction.create({ "type": Transaction.Type.Sale, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) def test_create_with_error_result(self): result = Transaction.create({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "billing": { "country_code_alpha2": "ZZ", "country_code_alpha3": "ZZZ", "country_code_numeric": "000", "country_name": "zzzzzz" } }) self.assertFalse(result.is_success) self.assertEqual(ErrorCodes.Transaction.TypeIsRequired, result.errors.for_object("transaction").on("type")[0].code) self.assertEqual( ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_code_alpha2")[0].code ) self.assertEqual( ErrorCodes.Address.CountryCodeAlpha3IsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_code_alpha3")[0].code ) self.assertEqual( ErrorCodes.Address.CountryCodeNumericIsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_code_numeric")[0].code ) self.assertEqual( ErrorCodes.Address.CountryNameIsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_name")[0].code ) def test_sale_from_transparent_redirect_with_successful_result(self): tr_data = { "transaction": { "amount": TransactionAmounts.Authorize, } } post_params = { "tr_data": Transaction.tr_data_for_sale(tr_data, "http://example.com/path"), "transaction[credit_card][number]": "4111111111111111", "transaction[credit_card][expiration_date]": "05/2010", } query_string = TestHelper.simulate_tr_form_post(post_params, Transaction.transparent_redirect_create_url()) result = Transaction.confirm_transparent_redirect(query_string) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual("411111", transaction.credit_card_details.bin) self.assertEqual("1111", transaction.credit_card_details.last_4) self.assertEqual("05/2010", transaction.credit_card_details.expiration_date) def test_sale_from_transparent_redirect_with_error_result(self): tr_data = { "transaction": { "amount": TransactionAmounts.Authorize, } } post_params = { "tr_data": Transaction.tr_data_for_sale(tr_data, "http://example.com/path"), "transaction[credit_card][number]": "booya", "transaction[credit_card][expiration_date]": "05/2010", } query_string = TestHelper.simulate_tr_form_post(post_params, Transaction.transparent_redirect_create_url()) result = Transaction.confirm_transparent_redirect(query_string) self.assertFalse(result.is_success) self.assertTrue(len(result.errors.for_object("transaction").for_object("credit_card").on("number")) > 0) def test_sale_from_transparent_redirect_with_403_and_message(self): tr_data = { "transaction": { "amount": TransactionAmounts.Authorize } } post_params = { "tr_data": Transaction.tr_data_for_sale(tr_data, "http://example.com/path"), "transaction[credit_card][number]": "booya", "transaction[credit_card][expiration_date]": "05/2010", "transaction[bad]": "value" } query_string = TestHelper.simulate_tr_form_post(post_params, Transaction.transparent_redirect_create_url()) try: Transaction.confirm_transparent_redirect(query_string) self.fail() except AuthorizationError as e: self.assertEqual("Invalid params: transaction[bad]", str(e)) def test_credit_from_transparent_redirect_with_successful_result(self): tr_data = { "transaction": { "amount": TransactionAmounts.Authorize, } } post_params = { "tr_data": Transaction.tr_data_for_credit(tr_data, "http://example.com/path"), "transaction[credit_card][number]": "4111111111111111", "transaction[credit_card][expiration_date]": "05/2010", "transaction[billing][country_code_alpha2]": "US", "transaction[billing][country_code_alpha3]": "USA", "transaction[billing][country_code_numeric]": "840", "transaction[billing][country_name]": "United States of America" } query_string = TestHelper.simulate_tr_form_post(post_params, Transaction.transparent_redirect_create_url()) result = Transaction.confirm_transparent_redirect(query_string) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEqual(Transaction.Type.Credit, transaction.type) self.assertEqual("411111", transaction.credit_card_details.bin) self.assertEqual("1111", transaction.credit_card_details.last_4) self.assertEqual("05/2010", transaction.credit_card_details.expiration_date) self.assertEqual("US", transaction.billing_details.country_code_alpha2) self.assertEqual("USA", transaction.billing_details.country_code_alpha3) self.assertEqual("840", transaction.billing_details.country_code_numeric) self.assertEqual("United States of America", transaction.billing_details.country_name) def test_credit_from_transparent_redirect_with_error_result(self): tr_data = { "transaction": { "amount": TransactionAmounts.Authorize, } } post_params = { "tr_data": Transaction.tr_data_for_credit(tr_data, "http://example.com/path"), "transaction[credit_card][number]": "booya", "transaction[credit_card][expiration_date]": "05/2010", } query_string = TestHelper.simulate_tr_form_post(post_params, Transaction.transparent_redirect_create_url()) result = Transaction.confirm_transparent_redirect(query_string) self.assertFalse(result.is_success) self.assertTrue(len(result.errors.for_object("transaction").for_object("credit_card").on("number")) > 0) def test_submit_for_settlement_without_amount(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual(Decimal(TransactionAmounts.Authorize), submitted_transaction.amount) def test_submit_for_settlement_with_amount(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction submitted_transaction = Transaction.submit_for_settlement(transaction.id, Decimal("900")).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual(Decimal("900.00"), submitted_transaction.amount) def test_submit_for_settlement_with_order_id(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = {"order_id": "ABC123"} submitted_transaction = Transaction.submit_for_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual("ABC123", submitted_transaction.order_id) def test_submit_for_settlement_with_descriptor(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = { "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" } } submitted_transaction = Transaction.submit_for_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual("123*123456789012345678", submitted_transaction.descriptor.name) self.assertEqual("3334445555", submitted_transaction.descriptor.phone) self.assertEqual("ebay.com", submitted_transaction.descriptor.url) @raises_with_regexp(KeyError, "'Invalid keys: invalid_param'") def test_submit_for_settlement_with_invalid_params(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = { "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" }, "invalid_param": "foo", } Transaction.submit_for_settlement(transaction.id, Decimal("900"), params) def test_submit_for_settlement_with_validation_error(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction result = Transaction.submit_for_settlement(transaction.id, Decimal("1200")) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.SettlementAmountIsTooLarge, result.errors.for_object("transaction").on("amount")[0].code ) def test_submit_for_settlement_with_validation_error_on_service_fee(self): transaction = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "service_fee_amount": "5.00" }).transaction result = Transaction.submit_for_settlement(transaction.id, "1.00") self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.SettlementAmountIsLessThanServiceFeeAmount, result.errors.for_object("transaction").on("amount")[0].code ) def test_update_details_with_valid_params(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } }).transaction params = { "amount" : "9.00", "order_id": "123", "descriptor": { "name": "456*123456789012345678", "phone": "3334445555", "url": "ebay.com" } } result = Transaction.update_details(transaction.id, params) self.assertTrue(result.is_success) self.assertEqual(Decimal("9.00"), result.transaction.amount) self.assertEqual(Transaction.Status.SubmittedForSettlement, result.transaction.status) self.assertEqual("123", result.transaction.order_id) self.assertEqual("456*123456789012345678", result.transaction.descriptor.name) self.assertEqual("3334445555", result.transaction.descriptor.phone) self.assertEqual("ebay.com", result.transaction.descriptor.url) @raises_with_regexp(KeyError, "'Invalid keys: invalid_key'") def test_update_details_with_invalid_params(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True }, }).transaction params = { "amount" : "9.00", "invalid_key": "invalid_value", "order_id": "123", "descriptor": { "name": "456*123456789012345678", "phone": "3334445555", "url": "ebay.com" } } Transaction.update_details(transaction.id, params) def test_update_details_with_invalid_order_id(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True }, }).transaction params = { "amount" : "9.00", "order_id": "A" * 256, "descriptor": { "name": "456*123456789012345678", "phone": "3334445555", "url": "ebay.com" } } result = Transaction.update_details(transaction.id, params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.OrderIdIsTooLong, result.errors.for_object("transaction").on("order_id")[0].code ) def test_update_details_with_invalid_descriptor(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True }, }).transaction params = { "amount" : "9.00", "order_id": "123", "descriptor": { "name": "invalid name", "phone": "invalid phone", "url": "12345678901234567890" } } result = Transaction.update_details(transaction.id, params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Descriptor.NameFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("name")[0].code ) self.assertEqual( ErrorCodes.Descriptor.PhoneFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("phone")[0].code ) self.assertEqual( ErrorCodes.Descriptor.UrlFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("url")[0].code ) def test_update_details_with_invalid_amount(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True }, }).transaction params = { "amount" : "999.00", "order_id": "123", } result = Transaction.update_details(transaction.id, params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.SettlementAmountIsTooLarge, result.errors.for_object("transaction").on("amount")[0].code ) def test_update_details_with_invalid_status(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, }).transaction params = { "amount" : "9.00", "order_id": "123", } result = Transaction.update_details(transaction.id, params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotUpdateTransactionDetailsNotSubmittedForSettlement, result.errors.for_object("transaction").on("base")[0].code ) def test_update_details_with_invalid_processor(self): transaction = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.Success, "expiration_date": "05/2020" }, "options": { "submit_for_settlement": True }, }).transaction params = { "amount" : "9.00", "order_id": "123", } result = Transaction.update_details(transaction.id, params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ProcessorDoesNotSupportUpdatingTransactionDetails, result.errors.for_object("transaction").on("base")[0].code ) def test_status_history(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEqual(2, len(submitted_transaction.status_history)) self.assertEqual(Transaction.Status.Authorized, submitted_transaction.status_history[0].status) self.assertEqual(Decimal(TransactionAmounts.Authorize), submitted_transaction.status_history[0].amount) self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status_history[1].status) self.assertEqual(Decimal(TransactionAmounts.Authorize), submitted_transaction.status_history[1].amount) def test_successful_refund(self): transaction = self.__create_transaction_to_refund() result = Transaction.refund(transaction.id) self.assertTrue(result.is_success) refund = result.transaction self.assertEqual(Transaction.Type.Credit, refund.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), refund.amount) self.assertEqual(transaction.id, refund.refunded_transaction_id) self.assertEqual(refund.id, Transaction.find(transaction.id).refund_id) def test_successful_partial_refund(self): transaction = self.__create_transaction_to_refund() result = Transaction.refund(transaction.id, Decimal("500.00")) self.assertTrue(result.is_success) self.assertEqual(Transaction.Type.Credit, result.transaction.type) self.assertEqual(Decimal("500.00"), result.transaction.amount) def test_multiple_successful_partial_refunds(self): transaction = self.__create_transaction_to_refund() refund1 = Transaction.refund(transaction.id, Decimal("500.00")).transaction self.assertEqual(Transaction.Type.Credit, refund1.type) self.assertEqual(Decimal("500.00"), refund1.amount) refund2 = Transaction.refund(transaction.id, Decimal("500.00")).transaction self.assertEqual(Transaction.Type.Credit, refund2.type) self.assertEqual(Decimal("500.00"), refund2.amount) transaction = Transaction.find(transaction.id) self.assertEqual(2, len(transaction.refund_ids)) self.assertTrue(TestHelper.in_list(transaction.refund_ids, refund1.id)) self.assertTrue(TestHelper.in_list(transaction.refund_ids, refund2.id)) def test_refund_already_refunded_transation_fails(self): transaction = self.__create_transaction_to_refund() Transaction.refund(transaction.id) result = Transaction.refund(transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.HasAlreadyBeenRefunded, result.errors.for_object("transaction").on("base")[0].code ) def test_refund_with_options_params(self): transaction = self.__create_transaction_to_refund() options = { "amount": Decimal("1.00"), "order_id": "abcd" } result = Transaction.refund(transaction.id, options) self.assertTrue(result.is_success) self.assertEqual( "abcd", result.transaction.order_id ) self.assertEqual( Decimal("1.00"), result.transaction.amount ) def test_refund_returns_an_error_if_unsettled(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } }).transaction result = Transaction.refund(transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotRefundUnlessSettled, result.errors.for_object("transaction").on("base")[0].code ) @staticmethod def __create_transaction_to_refund(): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } }).transaction TestHelper.settle_transaction(transaction.id) return transaction @staticmethod def __create_paypal_transaction(): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": { "submit_for_settlement": True } }).transaction return transaction @staticmethod def __create_escrowed_transaction(): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" }, "service_fee_amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "options": { "hold_in_escrow": True } }).transaction TestHelper.escrow_transaction(transaction.id) return transaction def test_snapshot_plan_id_add_ons_and_discounts_from_subscription(self): credit_card = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }).customer.credit_cards[0] result = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "add_ons": { "add": [ { "amount": Decimal("11.00"), "inherited_from_id": "increase_10", "quantity": 2, "number_of_billing_cycles": 5 }, { "amount": Decimal("21.00"), "inherited_from_id": "increase_20", "quantity": 3, "number_of_billing_cycles": 6 } ] }, "discounts": { "add": [ { "amount": Decimal("7.50"), "inherited_from_id": "discount_7", "quantity": 2, "never_expires": True } ] } }) transaction = result.subscription.transactions[0] self.assertEqual(TestHelper.trialless_plan["id"], transaction.plan_id) self.assertEqual(2, len(transaction.add_ons)) add_ons = sorted(transaction.add_ons, key=lambda add_on: add_on.id) self.assertEqual("increase_10", add_ons[0].id) self.assertEqual(Decimal("11.00"), add_ons[0].amount) self.assertEqual(2, add_ons[0].quantity) self.assertEqual(5, add_ons[0].number_of_billing_cycles) self.assertFalse(add_ons[0].never_expires) self.assertEqual("increase_20", add_ons[1].id) self.assertEqual(Decimal("21.00"), add_ons[1].amount) self.assertEqual(3, add_ons[1].quantity) self.assertEqual(6, add_ons[1].number_of_billing_cycles) self.assertFalse(add_ons[1].never_expires) self.assertEqual(1, len(transaction.discounts)) discounts = transaction.discounts self.assertEqual("discount_7", discounts[0].id) self.assertEqual(Decimal("7.50"), discounts[0].amount) self.assertEqual(2, discounts[0].quantity) self.assertEqual(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) def test_transactions_accept_lodging_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "industry": { "industry_type": Transaction.IndustryType.Lodging, "data": { "folio_number": "aaa", "check_in_date": "2014-07-07", "check_out_date": "2014-07-11", "room_rate": "170.00", "room_tax": "30.00", "no_show": False, "advanced_deposit": False, "fire_safe": True, "property_phone": "1112223345", "additional_charges": [ { "kind": Transaction.AdditionalCharge.Restaurant, "amount": "50.00" }, { "kind": Transaction.AdditionalCharge.Other, "amount": "150.00" } ] } } }) self.assertTrue(result.is_success) def test_transactions_return_validation_errors_on_lodging_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "industry": { "industry_type": Transaction.IndustryType.Lodging, "data": { "folio_number": "aaa", "check_in_date": "2014-07-07", "check_out_date": "2014-06-06", "room_rate": "asdfsdf", "additional_charges": [ { "kind": "unknown", "amount": "20.00" } ] } } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Industry.Lodging.CheckOutDateMustFollowCheckInDate, result.errors.for_object("transaction").for_object("industry").on("check_out_date")[0].code ) self.assertEqual( ErrorCodes.Transaction.Industry.Lodging.RoomRateFormatIsInvalid, result.errors.for_object("transaction").for_object("industry").on("room_rate")[0].code ) self.assertEqual( ErrorCodes.Transaction.Industry.AdditionalCharge.KindIsInvalid, result.errors.for_object("transaction").for_object("industry").for_object("additional_charges").for_object("index_0").on("kind")[0].code ) def test_transactions_accept_travel_cruise_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "industry": { "industry_type": Transaction.IndustryType.TravelAndCruise, "data": { "travel_package": "flight", "departure_date": "2014-07-07", "lodging_check_in_date": "2014-07-07", "lodging_check_out_date": "2014-09-07", "lodging_name": "Royal Caribbean" } } }) self.assertTrue(result.is_success) def test_transactions_return_validation_errors_on_travel_cruise_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "industry": { "industry_type": Transaction.IndustryType.TravelAndCruise, "data": { "travel_package": "roadtrip", "departure_date": "2014-07-07", "lodging_check_in_date": "2014-07-07", "lodging_check_out_date": "2014-09-07", "lodging_name": "Royal Caribbean" } } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Industry.TravelCruise.TravelPackageIsInvalid, result.errors.for_object("transaction").for_object("industry").on("travel_package")[0].code ) def test_transactions_accept_travel_flight_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"submit_for_settlement": True}, "industry": { "industry_type": Transaction.IndustryType.TravelAndFlight, "data": { "passenger_first_name": "John", "passenger_last_name": "Doe", "passenger_middle_initial": "M", "passenger_title": "Mr.", "issued_date": date(2018, 1, 1), "travel_agency_name": "Expedia", "travel_agency_code": "12345678", "ticket_number": "ticket-number", "issuing_carrier_code": "AA", "customer_code": "customer-code", "fare_amount": "70.00", "fee_amount": "10.00", "tax_amount": "20.00", "restricted_ticket": False, "legs": [ { "conjunction_ticket": "CJ0001", "exchange_ticket": "ET0001", "coupon_number": "1", "service_class": "Y", "carrier_code": "AA", "fare_basis_code": "W", "flight_number": "AA100", "departure_date": date(2018, 1, 2), "departure_airport_code": "MDW", "departure_time": "08:00", "arrival_airport_code": "ATX", "arrival_time": "10:00", "stopover_permitted": False, "fare_amount": "35.00", "fee_amount": "5.00", "tax_amount": "10.00", "endorsement_or_restrictions": "NOT REFUNDABLE" }, { "conjunction_ticket": "CJ0002", "exchange_ticket": "ET0002", "coupon_number": "1", "service_class": "Y", "carrier_code": "AA", "fare_basis_code": "W", "flight_number": "AA200", "departure_date": date(2018, 1, 3), "departure_airport_code": "ATX", "departure_time": "12:00", "arrival_airport_code": "MDW", "arrival_time": "14:00", "stopover_permitted": False, "fare_amount": "35.00", "fee_amount": "5.00", "tax_amount": "10.00", "endorsement_or_restrictions": "NOT REFUNDABLE" } ] } } }) self.assertTrue(result.is_success) def test_transactions_return_validation_errors_on_travel_flight_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"submit_for_settlement": True}, "industry": { "industry_type": Transaction.IndustryType.TravelAndFlight, "data": { "fare_amount": "-1.23", "legs": [ { "fare_amount": "-1.23" } ] } } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Industry.TravelFlight.FareAmountCannotBeNegative, result.errors.for_object("transaction").for_object("industry").on("fare_amount")[0].code ) self.assertEqual( ErrorCodes.Transaction.Industry.Leg.TravelFlight.FareAmountCannotBeNegative, result.errors.for_object("transaction").for_object("industry").for_object("legs").for_object("index_0").on("fare_amount")[0].code ) def test_descriptors_accepts_name_phone_and_url(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("123*123456789012345678", transaction.descriptor.name) self.assertEqual("3334445555", transaction.descriptor.phone) self.assertEqual("ebay.com", transaction.descriptor.url) def test_descriptors_has_validation_errors_if_format_is_invalid(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "descriptor": { "name": "badcompanyname12*badproduct12", "phone": "%bad4445555", "url": "12345678901234" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Descriptor.NameFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("name")[0].code ) self.assertEqual( ErrorCodes.Descriptor.PhoneFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("phone")[0].code ) self.assertEqual( ErrorCodes.Descriptor.UrlFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("url")[0].code ) def test_clone_transaction(self): result = Transaction.sale({ "amount": "100.00", "order_id": "123", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2011", }, "customer": { "first_name": "Dan", }, "billing": { "first_name": "Carl", }, "shipping": { "first_name": "Andrew", } }) self.assertTrue(result.is_success) transaction = result.transaction clone_result = Transaction.clone_transaction( transaction.id, { "amount": "123.45", "channel": "MyShoppingCartProvider", "options": {"submit_for_settlement": "false"} }) self.assertTrue(clone_result.is_success) clone_transaction = clone_result.transaction self.assertNotEqual(transaction.id, clone_transaction.id) self.assertEqual(Transaction.Type.Sale, clone_transaction.type) self.assertEqual(Transaction.Status.Authorized, clone_transaction.status) self.assertEqual(Decimal("123.45"), clone_transaction.amount) self.assertEqual("MyShoppingCartProvider", clone_transaction.channel) self.assertEqual("123", clone_transaction.order_id) self.assertEqual("510510******5100", clone_transaction.credit_card_details.masked_number) self.assertEqual("Dan", clone_transaction.customer_details.first_name) self.assertEqual("Carl", clone_transaction.billing_details.first_name) self.assertEqual("Andrew", clone_transaction.shipping_details.first_name) def test_clone_transaction_submits_for_settlement(self): result = Transaction.sale({ "amount": "100.00", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2011", } }) self.assertTrue(result.is_success) transaction = result.transaction clone_result = Transaction.clone_transaction(transaction.id, {"amount": "123.45", "options": {"submit_for_settlement": "true"}}) self.assertTrue(clone_result.is_success) clone_transaction = clone_result.transaction self.assertEqual(Transaction.Type.Sale, clone_transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, clone_transaction.status) def test_clone_transaction_with_validations(self): result = Transaction.credit({ "amount": "100.00", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2011", } }) self.assertTrue(result.is_success) transaction = result.transaction clone_result = Transaction.clone_transaction(transaction.id, {"amount": "123.45"}) self.assertFalse(clone_result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotCloneCredit, clone_result.errors.for_object("transaction").on("base")[0].code ) def test_find_exposes_disbursement_details(self): transaction = Transaction.find("deposittransaction") disbursement_details = transaction.disbursement_details self.assertEqual(date(2013, 4, 10), disbursement_details.disbursement_date) self.assertEqual("USD", disbursement_details.settlement_currency_iso_code) self.assertEqual(Decimal("1"), disbursement_details.settlement_currency_exchange_rate) self.assertEqual(False, disbursement_details.funds_held) self.assertEqual(True, disbursement_details.success) self.assertEqual(Decimal("100.00"), disbursement_details.settlement_amount) def test_sale_with_three_d_secure_option(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "three_d_secure": { "required": True } } }) self.assertFalse(result.is_success) self.assertEqual(Transaction.Status.GatewayRejected, result.transaction.status) self.assertEqual(Transaction.GatewayRejectionReason.ThreeDSecure, result.transaction.gateway_rejection_reason) def test_sale_with_three_d_secure_token(self): three_d_secure_token = TestHelper.create_3ds_verification(TestHelper.three_d_secure_merchant_account_id, { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2009", }) result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_token": three_d_secure_token }) self.assertTrue(result.is_success) def test_sale_without_three_d_secure_token(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) def test_sale_returns_error_with_none_three_d_secure_token(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_token": None }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureTokenIsInvalid, result.errors.for_object("transaction").on("three_d_secure_token")[0].code ) def test_sale_returns_error_with_mismatched_3ds_verification_data(self): three_d_secure_token = TestHelper.create_3ds_verification(TestHelper.three_d_secure_merchant_account_id, { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2009", }) result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "5105105105105100", "expiration_date": "05/2009" }, "three_d_secure_token": three_d_secure_token }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureTransactionDataDoesntMatchVerify, result.errors.for_object("transaction").on("three_d_secure_token")[0].code ) def test_transaction_with_three_d_secure_pass_thru(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_pass_thru": { "eci_flag": "02", "cavv": "some-cavv", "xid": "some-xid" } }) self.assertTrue(result.is_success) self.assertEqual(Transaction.Status.Authorized, result.transaction.status) def test_transaction_with_three_d_secure_pass_thru_with_invalid_processor_settings(self): result = Transaction.sale({ "merchant_account_id": "heartland_ma", "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_pass_thru": { "eci_flag": "02", "cavv": "some-cavv", "xid": "some-xid" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureMerchantAccountDoesNotSupportCardType, result.errors.for_object("transaction").on("merchant_account_id")[0].code ) def test_transaction_with_three_d_secure_pass_thru_with_missing_eci_flag(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_pass_thru": { "eci_flag": "", "cavv": "some-cavv", "xid": "some-xid" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureEciFlagIsRequired, result.errors.for_object("transaction").for_object("three_d_secure_pass_thru").on("eci_flag")[0].code ) def test_transaction_with_three_d_secure_pass_thru_with_missing_cavv_and_xid(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_pass_thru": { "eci_flag": "05", "cavv": "", "xid": "" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureCavvIsRequired, result.errors.for_object("transaction").for_object("three_d_secure_pass_thru").on("cavv")[0].code ) def test_transaction_with_three_d_secure_pass_thru_with_invalid_eci_flag(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_pass_thru": { "eci_flag": "bad_eci_flag", "cavv": "some-cavv", "xid": "some-xid" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureEciFlagIsInvalid, result.errors.for_object("transaction").for_object("three_d_secure_pass_thru").on("eci_flag")[0].code ) def test_transaction_with_three_d_secure_adyen_pass_thru(self): result = Transaction.sale({ "merchant_account_id": TestHelper.adyen_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "10/2020", "cvv": "737" }, "three_d_secure_pass_thru": { "eci_flag": "02", "cavv": "some-cavv", "xid": "some-xid", "authentication_response": "Y", "directory_response": "Y", "cavv_algorithm": "2", "ds_transaction_id": "dstrxid-present", "three_d_secure_version": "1.0.2", } }) self.assertTrue(result.is_success) self.assertEqual(Transaction.Status.Authorized, result.transaction.status) def test_transaction_with_three_d_secure_adyen_pass_thru_missing_authentication_response(self): result = Transaction.sale({ "merchant_account_id": TestHelper.adyen_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "10/2020", "cvv": "737" }, "three_d_secure_pass_thru": { "eci_flag": "02", "cavv": "some-cavv", "xid": "some-xid", "authentication_response": "", "directory_response": "Y", "cavv_algorithm": "2", "ds_transaction_id": "dstrxid-present", "three_d_secure_version": "1.0.2", } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureAuthenticationResponseIsInvalid, result.errors.for_object("transaction").for_object("three_d_secure_pass_thru").on("authentication_response")[0].code ) def test_transaction_with_three_d_secure_adyen_pass_thru_missing_directory_response(self): result = Transaction.sale({ "merchant_account_id": TestHelper.adyen_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "10/2020", "cvv": "737" }, "three_d_secure_pass_thru": { "eci_flag": "02", "cavv": "some-cavv", "xid": "some-xid", "authentication_response": "Y", "directory_response": "", "cavv_algorithm": "2", "ds_transaction_id": "dstrxid-present", "three_d_secure_version": "1.0.2", } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureDirectoryResponseIsInvalid, result.errors.for_object("transaction").for_object("three_d_secure_pass_thru").on("directory_response")[0].code ) def test_transaction_with_three_d_secure_adyen_pass_thru_missing_cavv_algorithm(self): result = Transaction.sale({ "merchant_account_id": TestHelper.adyen_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "10/2020", "cvv": "737" }, "three_d_secure_pass_thru": { "eci_flag": "02", "cavv": "some-cavv", "xid": "some-xid", "authentication_response": "Y", "directory_response": "Y", "cavv_algorithm": "", "ds_transaction_id": "dstrxid-present", "three_d_secure_version": "1.0.2", } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureCavvAlgorithmIsInvalid, result.errors.for_object("transaction").for_object("three_d_secure_pass_thru").on("cavv_algorithm")[0].code ) def test_sale_with_amex_rewards_succeeds(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.Success, "expiration_date": "05/2020" }, "options" : { "submit_for_settlement" : True, "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) def test_sale_with_amex_rewards_succeeds_even_if_card_is_ineligible(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.IneligibleCard, "expiration_date": "05/2009" }, "options" : { "submit_for_settlement" : True, "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) def test_sale_with_amex_rewards_succeeds_even_if_card_balance_is_insufficient(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.InsufficientPoints, "expiration_date": "05/2009" }, "options" : { "submit_for_settlement" : True, "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) def test_submit_for_settlement_with_amex_rewards_succeeds(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.Success, "expiration_date": "05/2009" }, "options" : { "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) def test_submit_for_settlement_with_amex_rewards_succeeds_even_if_card_is_ineligible(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.IneligibleCard, "expiration_date": "05/2009" }, "options" : { "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) def test_submit_for_settlement_with_amex_rewards_succeeds_even_if_card_balance_is_insufficient(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.InsufficientPoints, "expiration_date": "05/2009" }, "options" : { "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) def test_find_exposes_authorization_adjustments(self): transaction = Transaction.find("authadjustmenttransaction") authorization_adjustment = transaction.authorization_adjustments[0] self.assertEqual(datetime, type(authorization_adjustment.timestamp)) self.assertEqual(Decimal("-20.00"), authorization_adjustment.amount) self.assertEqual(True, authorization_adjustment.success) self.assertEqual("1000", authorization_adjustment.processor_response_code) self.assertEqual("Approved", authorization_adjustment.processor_response_text) self.assertEqual(ProcessorResponseTypes.Approved, authorization_adjustment.processor_response_type) def test_find_exposes_authorization_adjustments_soft_declined(self): transaction = Transaction.find("authadjustmenttransactionsoftdeclined") authorization_adjustment = transaction.authorization_adjustments[0] self.assertEqual(datetime, type(authorization_adjustment.timestamp)) self.assertEqual(Decimal("-20.00"), authorization_adjustment.amount) self.assertEqual(False, authorization_adjustment.success) self.assertEqual("3000", authorization_adjustment.processor_response_code) self.assertEqual("Processor Network Unavailable - Try Again", authorization_adjustment.processor_response_text) self.assertEqual(ProcessorResponseTypes.SoftDeclined, authorization_adjustment.processor_response_type) def test_find_exposes_authorization_adjustments_hard_declined(self): transaction = Transaction.find("authadjustmenttransactionharddeclined") authorization_adjustment = transaction.authorization_adjustments[0] self.assertEqual(datetime, type(authorization_adjustment.timestamp)) self.assertEqual(Decimal("-20.00"), authorization_adjustment.amount) self.assertEqual(False, authorization_adjustment.success) self.assertEqual("2015", authorization_adjustment.processor_response_code) self.assertEqual("Transaction Not Allowed", authorization_adjustment.processor_response_text) self.assertEqual(ProcessorResponseTypes.HardDeclined, authorization_adjustment.processor_response_type) def test_find_exposes_disputes(self): transaction = Transaction.find("disputedtransaction") dispute = transaction.disputes[0] self.assertEqual(date(2014, 3, 1), dispute.received_date) self.assertEqual(date(2014, 3, 21), dispute.reply_by_date) self.assertEqual("USD", dispute.currency_iso_code) self.assertEqual(Decimal("250.00"), dispute.amount) self.assertEqual(Dispute.Status.Won, dispute.status) self.assertEqual(Dispute.Reason.Fraud, dispute.reason) self.assertEqual("disputedtransaction", dispute.transaction_details.id) self.assertEqual(Decimal("1000.00"), dispute.transaction_details.amount) self.assertEqual(Dispute.Kind.Chargeback, dispute.kind) self.assertEqual(date(2014, 3, 1), dispute.date_opened) self.assertEqual(date(2014, 3, 7), dispute.date_won) def test_find_exposes_three_d_secure_info(self): transaction = Transaction.find("threedsecuredtransaction") three_d_secure_info = transaction.three_d_secure_info self.assertEqual("Y", three_d_secure_info.enrolled) self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertEqual("somebase64value", three_d_secure_info.cavv) self.assertEqual("xidvalue", three_d_secure_info.xid) self.assertEqual("dstxnid", three_d_secure_info.ds_transaction_id) self.assertEqual("07", three_d_secure_info.eci_flag) self.assertEqual("1.0.2", three_d_secure_info.three_d_secure_version) def test_find_exposes_none_for_null_three_d_secure_info(self): transaction = Transaction.find("settledtransaction") three_d_secure_info = transaction.three_d_secure_info self.assertEqual(None, three_d_secure_info) def test_find_exposes_refund_from_transaction_fee(self): transaction = Transaction.find("settledtransaction") paypal_details = transaction.paypal_details self.assertNotEqual(None, paypal_details.refund_from_transaction_fee_amount) self.assertNotEqual(None, paypal_details.refund_from_transaction_fee_currency_iso_code) def test_find_exposes_retrievals(self): transaction = Transaction.find("retrievaltransaction") dispute = transaction.disputes[0] self.assertEqual("USD", dispute.currency_iso_code) self.assertEqual(Decimal("1000.00"), dispute.amount) self.assertEqual(Dispute.Status.Open, dispute.status) self.assertEqual(Dispute.Reason.Retrieval, dispute.reason) self.assertEqual("retrievaltransaction", dispute.transaction_details.id) self.assertEqual(Decimal("1000.00"), dispute.transaction_details.amount) def test_creating_paypal_transaction_with_one_time_use_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) def test_creating_local_payment_transaction_with_local_payment_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "payment_method_nonce": Nonces.LocalPayment, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, transaction.local_payment_details.payment_id) self.assertNotEqual(None, transaction.local_payment_details.payer_id) self.assertNotEqual(None, transaction.local_payment_details.funding_source) self.assertNotEqual(None, transaction.local_payment_details.capture_id) self.assertNotEqual(None, transaction.local_payment_details.debug_id) self.assertNotEqual(None, transaction.local_payment_details.transaction_fee_amount) self.assertNotEqual(None, transaction.local_payment_details.transaction_fee_currency_iso_code) def test_refunding_local_payment_transaction(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "payment_method_nonce": Nonces.LocalPayment, }) self.assertTrue(result.is_success) result = Transaction.refund(result.transaction.id) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, transaction.local_payment_details.payment_id) self.assertNotEqual(None, transaction.local_payment_details.payer_id) self.assertNotEqual(None, transaction.local_payment_details.funding_source) self.assertNotEqual(None, transaction.local_payment_details.refund_id) self.assertNotEqual(None, transaction.local_payment_details.debug_id) self.assertNotEqual(None, transaction.local_payment_details.refund_from_transaction_fee_amount) self.assertNotEqual(None, transaction.local_payment_details.refund_from_transaction_fee_currency_iso_code) def test_creating_local_payment_transaction_with_local_payment_webhook_content(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "paypal_account": { "payment_id": "PAY-1234", "payer_id": "PAYER-1234", }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payment_id, "PAY-1234") self.assertEqual(transaction.paypal_details.payer_id, "PAYER-1234") def test_creating_paypal_transaction_with_payee_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": { "payee_id": "fake-payee-id" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.payee_id, "fake-payee-id") def test_creating_paypal_transaction_with_payee_email(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": { "payee_email": "payee@example.com" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.payee_email, "payee@example.com") def test_creating_paypal_transaction_with_payee_email_in_options_params(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": {}, "options": { "payee_email": "payee@example.com" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.payee_email, "payee@example.com") def test_creating_paypal_transaction_with_payee_email_in_options_paypal_params(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": {}, "options": { "paypal": { "payee_email": "foo@paypal.com" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.payee_email, "foo@paypal.com") def test_creating_paypal_transaction_with_custom_field_in_options_paypal_params(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": {}, "options": { "paypal": { "custom_field": "custom field stuff" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.custom_field, "custom field stuff") def test_creating_paypal_transaction_with_supplementary_data_in_options_paypal_params(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": {}, "options": { "paypal": { "supplementary_data": { "key1": "value1", "key2": "value2" } } } }) # note - supplementary data is not returned in response self.assertTrue(result.is_success) def test_creating_paypal_transaction_with_description_in_options_paypal_params(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": {}, "options": { "paypal": { "description": "Product description" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.description, "Product description") def test_paypal_transaction_payment_instrument_type(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(PaymentInstrumentType.PayPalAccount, transaction.payment_instrument_type) def test_creating_paypal_transaction_with_one_time_use_nonce_and_store_in_vault(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"store_in_vault": True} }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertEqual(transaction.paypal_details.token, None) self.assertNotEqual(None, transaction.paypal_details.debug_id) def test_creating_paypal_transaction_with_future_payment_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.debug_id) def test_validation_failure_on_invalid_paypal_nonce(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "access-token": "access-token", "options": {"validate": False} }) self.assertEqual(202, status_code) result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": nonce }) self.assertFalse(result.is_success) error_code = result.errors.for_object("transaction").for_object("paypal_account").on("base")[0].code self.assertEqual(error_code, ErrorCodes.PayPalAccount.CannotHaveBothAccessTokenAndConsentCode) def test_validation_failure_on_non_existent_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": "doesnt-exist" }) self.assertFalse(result.is_success) error_code = result.errors.for_object("transaction").on("payment_method_nonce")[0].code self.assertEqual(error_code, ErrorCodes.Transaction.PaymentMethodNonceUnknown) def test_creating_paypal_transaction_with_vaulted_token(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) transaction_result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_token": result.payment_method.token }) self.assertTrue(transaction_result.is_success) transaction = transaction_result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, transaction.paypal_details.debug_id) def test_creating_paypal_transaction_with_one_time_nonce_and_store_in_vault_fails_gracefully(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"store_in_vault": True} }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(None, transaction.paypal_details.token) def test_creating_paypal_transaction_with_future_payment_nonce_and_store_in_vault(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalFuturePayment, "options": {"store_in_vault": True} }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, transaction.paypal_details.token) paypal_account = PaymentMethod.find(transaction.paypal_details.token) self.assertEqual(paypal_account.email, transaction.paypal_details.payer_email) def test_creating_paypal_transaction_and_submitting_for_settlement(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"submit_for_settlement": True} }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.status, Transaction.Status.Settling) def test_voiding_a_paypal_transaction(self): sale_result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, }) self.assertTrue(sale_result.is_success) sale_transaction = sale_result.transaction void_result = Transaction.void(sale_transaction.id) self.assertTrue(void_result.is_success) void_transaction = void_result.transaction self.assertEqual(void_transaction.id, sale_transaction.id) self.assertEqual(void_transaction.status, Transaction.Status.Voided) def test_paypal_transaction_successful_refund(self): transaction = self.__create_paypal_transaction() result = Transaction.refund(transaction.id) self.assertTrue(result.is_success) refund = result.transaction self.assertEqual(Transaction.Type.Credit, refund.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), refund.amount) self.assertEqual(transaction.id, refund.refunded_transaction_id) self.assertEqual(refund.id, Transaction.find(transaction.id).refund_id) def test_paypal_transaction_successful_partial_refund(self): transaction = self.__create_paypal_transaction() result = Transaction.refund(transaction.id, Decimal("500.00")) self.assertTrue(result.is_success) self.assertEqual(Transaction.Type.Credit, result.transaction.type) self.assertEqual(Decimal("500.00"), result.transaction.amount) def test_paypal_transaction_multiple_successful_partial_refunds(self): transaction = self.__create_paypal_transaction() refund1 = Transaction.refund(transaction.id, Decimal("500.00")).transaction self.assertEqual(Transaction.Type.Credit, refund1.type) self.assertEqual(Decimal("500.00"), refund1.amount) refund2 = Transaction.refund(transaction.id, Decimal("500.00")).transaction self.assertEqual(Transaction.Type.Credit, refund2.type) self.assertEqual(Decimal("500.00"), refund2.amount) transaction = Transaction.find(transaction.id) self.assertEqual(2, len(transaction.refund_ids)) self.assertTrue(TestHelper.in_list(transaction.refund_ids, refund1.id)) self.assertTrue(TestHelper.in_list(transaction.refund_ids, refund2.id)) def test_paypal_transaction_returns_required_fields(self): transaction = self.__create_paypal_transaction() self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertNotEqual(None, transaction.paypal_details.payer_email) self.assertNotEqual(None, transaction.paypal_details.authorization_id) self.assertNotEqual(None, transaction.paypal_details.payer_id) self.assertNotEqual(None, transaction.paypal_details.payer_first_name) self.assertNotEqual(None, transaction.paypal_details.payer_last_name) self.assertNotEqual(None, transaction.paypal_details.payer_status) self.assertNotEqual(None, transaction.paypal_details.seller_protection_status) self.assertNotEqual(None, transaction.paypal_details.capture_id) #self.assertNotEqual(None, transaction.paypal_details.refund_id) self.assertNotEqual(None, transaction.paypal_details.transaction_fee_amount) self.assertNotEqual(None, transaction.paypal_details.transaction_fee_currency_iso_code) def test_paypal_transaction_refund_returns_an_error_if_unsettled(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } }).transaction result = Transaction.refund(transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotRefundUnlessSettled, result.errors.for_object("transaction").on("base")[0].code ) def test_transaction_settlement_errors(self): sale_result = Transaction.sale({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" }, "amount": "100.00", }) transaction = sale_result.transaction settle_result = TestHelper.settle_transaction(transaction.id) self.assertFalse(settle_result.is_success) error_codes = [ error.code for error in settle_result.errors.for_object("transaction").on("base") ] self.assertTrue(ErrorCodes.Transaction.CannotSimulateTransactionSettlement in error_codes) def test_transaction_returns_settlement_declined_response(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"submit_for_settlement": True} }) self.assertTrue(result.is_success) TestHelper.settlement_decline_transaction(result.transaction.id) transaction = Transaction.find(result.transaction.id) self.assertTrue("4001", transaction.processor_settlement_response_code) self.assertTrue("Settlement Declined", transaction.processor_settlement_response_text) self.assertTrue(Transaction.Status.SettlementDeclined, transaction.status) def test_transaction_returns_settlement_pending_response(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"submit_for_settlement": True} }) self.assertTrue(result.is_success) TestHelper.settlement_pending_transaction(result.transaction.id) transaction = Transaction.find(result.transaction.id) self.assertTrue("4002", transaction.processor_settlement_response_code) self.assertTrue("Settlement Pending", transaction.processor_settlement_response_text) self.assertTrue(Transaction.Status.SettlementPending, transaction.status) def test_transaction_submit_for_partial_settlement(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) authorized_transaction = result.transaction partial_settlement_result = Transaction.submit_for_partial_settlement(authorized_transaction.id, Decimal("500.00")) partial_settlement_transaction = partial_settlement_result.transaction self.assertTrue(partial_settlement_result.is_success) self.assertEqual(partial_settlement_transaction.amount, Decimal("500.00")) self.assertEqual(Transaction.Type.Sale, partial_settlement_transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, partial_settlement_transaction.status) self.assertEqual(authorized_transaction.id, partial_settlement_transaction.authorized_transaction_id) partial_settlement_result_2 = Transaction.submit_for_partial_settlement(authorized_transaction.id, Decimal("500.00")) partial_settlement_transaction_2 = partial_settlement_result_2.transaction self.assertTrue(partial_settlement_result_2.is_success) self.assertEqual(partial_settlement_transaction_2.amount, Decimal("500.00")) self.assertEqual(Transaction.Type.Sale, partial_settlement_transaction_2.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, partial_settlement_transaction_2.status) self.assertEqual(authorized_transaction.id, partial_settlement_transaction_2.authorized_transaction_id) refreshed_authorized_transaction = Transaction.find(authorized_transaction.id) self.assertEqual(2, len(refreshed_authorized_transaction.partial_settlement_transaction_ids)) def test_transaction_submit_for_partial_settlement_unsuccessful(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) authorized_transaction = result.transaction partial_settlement_result = Transaction.submit_for_partial_settlement(authorized_transaction.id, Decimal("500.00")) partial_settlement_transaction = partial_settlement_result.transaction partial_settlement_result_2 = Transaction.submit_for_partial_settlement(partial_settlement_transaction.id, Decimal("250.00")) self.assertFalse(partial_settlement_result_2.is_success) error_code = partial_settlement_result_2.errors.for_object("transaction").on("base")[0].code self.assertEqual(ErrorCodes.Transaction.CannotSubmitForPartialSettlement, error_code) def test_submit_for_partial_settlement_with_order_id(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = {"order_id": "ABC123"} submitted_transaction = Transaction.submit_for_partial_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual("ABC123", submitted_transaction.order_id) def test_submit_for_partial_settlement_with_descriptor(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = { "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" } } submitted_transaction = Transaction.submit_for_partial_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual("123*123456789012345678", submitted_transaction.descriptor.name) self.assertEqual("3334445555", submitted_transaction.descriptor.phone) self.assertEqual("ebay.com", submitted_transaction.descriptor.url) @raises_with_regexp(KeyError, "'Invalid keys: invalid_param'") def test_submit_for_partial_settlement_with_invalid_params(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = { "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" }, "invalid_param": "foo", } Transaction.submit_for_partial_settlement(transaction.id, Decimal("900"), params) def test_facilitated_transaction(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, False) nonce = grant_result.payment_method_nonce.nonce result = Transaction.sale({ "payment_method_nonce": nonce, "amount": TransactionAmounts.Authorize, }) self.assertNotEqual(result.transaction.facilitated_details, None) self.assertEqual(result.transaction.facilitated_details.merchant_id, "integration_merchant_id") self.assertEqual(result.transaction.facilitated_details.merchant_name, "14ladders") self.assertEqual(result.transaction.facilitated_details.payment_method_nonce, nonce) self.assertTrue(result.transaction.facilitator_details is not None) self.assertEqual(result.transaction.facilitator_details.oauth_application_client_id, "client_id$development$integration_client_id") self.assertEqual(result.transaction.facilitator_details.oauth_application_name, "PseudoShop") self.assertTrue(result.transaction.billing["postal_code"] is None) def test_include_billing_postal_code(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, { "allow_vaulting": False, "include_billing_postal_code": True }) result = Transaction.sale({ "payment_method_nonce": grant_result.payment_method_nonce.nonce, "amount": TransactionAmounts.Authorize, }) self.assertTrue(result.transaction.billing["postal_code"], "95131") def test_shared_vault_transaction_with_nonce(self): config = Configuration( merchant_id="integration_merchant_public_id", public_key="oauth_app_partner_user_public_key", private_key="oauth_app_partner_user_private_key", environment=Environment.Development ) gateway = BraintreeGateway(config) customer = gateway.customer.create({"first_name": "Bob"}).customer address = gateway.address.create({ "customer_id": customer.id, "first_name": "Joe", }).address credit_card = gateway.credit_card.create( params={ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", } ).credit_card shared_nonce = gateway.payment_method_nonce.create( credit_card.token ).payment_method_nonce.nonce oauth_app_gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret", environment=Environment.Development ) code = TestHelper.create_grant(oauth_app_gateway, { "merchant_public_id": "integration_merchant_id", "scope": "grant_payment_method,shared_vault_transactions" }) access_token = oauth_app_gateway.oauth.create_token_from_code({ "code": code }).credentials.access_token recipient_gateway = BraintreeGateway(access_token=access_token) result = recipient_gateway.transaction.sale({ "shared_payment_method_nonce": shared_nonce, "shared_customer_id": customer.id, "shared_shipping_address_id": address.id, "shared_billing_address_id": address.id, "amount": "100" }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.shipping_details.first_name, address.first_name) self.assertEqual(result.transaction.billing_details.first_name, address.first_name) self.assertEqual(result.transaction.customer_details.first_name, customer.first_name) def test_shared_vault_transaction_with_token(self): config = Configuration( merchant_id="integration_merchant_public_id", public_key="oauth_app_partner_user_public_key", private_key="oauth_app_partner_user_private_key", environment=Environment.Development ) gateway = BraintreeGateway(config) customer = gateway.customer.create({"first_name": "Bob"}).customer address = gateway.address.create({ "customer_id": customer.id, "first_name": "Joe", }).address credit_card = gateway.credit_card.create( params={ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", } ).credit_card oauth_app_gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret", environment=Environment.Development ) code = TestHelper.create_grant(oauth_app_gateway, { "merchant_public_id": "integration_merchant_id", "scope": "grant_payment_method,shared_vault_transactions" }) access_token = oauth_app_gateway.oauth.create_token_from_code({ "code": code }).credentials.access_token recipient_gateway = BraintreeGateway( access_token=access_token, ) result = recipient_gateway.transaction.sale({ "shared_payment_method_token": credit_card.token, "shared_customer_id": customer.id, "shared_shipping_address_id": address.id, "shared_billing_address_id": address.id, "amount": "100" }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.shipping_details.first_name, address.first_name) self.assertEqual(result.transaction.billing_details.first_name, address.first_name) self.assertEqual(result.transaction.customer_details.first_name, customer.first_name) def test_sale_elo_card(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.adyen_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Elo, "expiration_date": "10/2020", "cvv": "737", } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(TestHelper.adyen_merchant_account_id, transaction.merchant_account_id) def test_sale_hiper_card(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(CreditCard.CardType.Hiper, transaction.credit_card_details.card_type) def test_sale_hipercard_card(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hipercard, "expiration_date": "10/2020", "cvv": "737", } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(CreditCard.CardType.Hipercard, transaction.credit_card_details.card_type) def test_account_type_credit(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hipercard, "expiration_date": "10/2020", "cvv": "737", }, "options": { "credit_card": { "account_type": "credit", }, }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("credit", transaction.credit_card_details.account_type) def test_account_type_debit(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "submit_for_settlement": True, "credit_card": { "account_type": "debit", }, }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("debit", transaction.credit_card_details.account_type) def test_account_type_debit_error_does_not_support_auths(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "credit_card": { "account_type": "debit", }, }, }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Options.CreditCard.AccountTypeDebitDoesNotSupportAuths, result.errors.for_object("transaction").for_object("options").for_object("credit_card").on("account_type")[0].code ) def test_account_type_debit_error_account_type_is_invalid(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "credit_card": { "account_type": "invalid", }, }, }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Options.CreditCard.AccountTypeIsInvalid, result.errors.for_object("transaction").for_object("options").for_object("credit_card").on("account_type")[0].code ) def test_account_type_debit_error_account_type_not_supported(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.MasterCard, "expiration_date": "05/2009" }, "options": { "credit_card": { "account_type": "debit", }, }, }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Options.CreditCard.AccountTypeNotSupported, result.errors.for_object("transaction").for_object("options").for_object("credit_card").on("account_type")[0].code ) def test_paypal_here_details_auth_capture(self): result = Transaction.find('paypal_here_auth_capture_id') self.assertIsNotNone(result.paypal_here_details) self.assertEqual(PaymentInstrumentType.PayPalHere, result.payment_instrument_type) details = result.paypal_here_details self.assertIsNotNone(details.authorization_id) self.assertIsNotNone(details.capture_id) self.assertIsNotNone(details.invoice_id) self.assertIsNotNone(details.last_4) self.assertIsNotNone(details.payment_type) self.assertIsNotNone(details.transaction_fee_amount) self.assertIsNotNone(details.transaction_fee_currency_iso_code) self.assertIsNotNone(details.transaction_initiation_date) self.assertIsNotNone(details.transaction_updated_date) def test_paypal_here_details_sale(self): result = Transaction.find('paypal_here_sale_id') self.assertIsNotNone(result.paypal_here_details) details = result.paypal_here_details self.assertIsNotNone(details.payment_id) def test_paypal_here_details_refund(self): result = Transaction.find('paypal_here_refund_id') self.assertIsNotNone(result.paypal_here_details) details = result.paypal_here_details self.assertIsNotNone(details.refund_id) def test_sale_network_response_code_text(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, transaction.processor_response_type) self.assertEqual("XX", transaction.network_response_code) self.assertEqual("sample network response text", transaction.network_response_text) braintree_python-3.57.1/tests/integration/test_search.py0000644000175000017500000003146613545202423021642 0ustar hlehlefrom tests.test_helper import * class TestSearch(unittest.TestCase): def test_text_node_is(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] trial_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription trialless_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id == "integration_trial_plan" ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_text_node_is_not(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] trial_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription trialless_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id != "integration_trialless_plan" ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_text_node_starts_with(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] trial_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription trialless_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id.starts_with("integration_trial_p") ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_text_node_ends_with(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] trial_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription trialless_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id.ends_with("trial_plan") ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_text_node_contains(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] trial_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription trialless_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id.contains("rial_pl") ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_multiple_value_node_in_list(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] active_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription canceled_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription Subscription.cancel(canceled_subscription.id) collection = Subscription.search([ SubscriptionSearch.status.in_list([Subscription.Status.Active, Subscription.Status.Canceled]) ]) self.assertTrue(TestHelper.includes(collection, active_subscription)) self.assertTrue(TestHelper.includes(collection, canceled_subscription)) def test_multiple_value_node_in_list_as_arg_list(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] active_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription canceled_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription Subscription.cancel(canceled_subscription.id) collection = Subscription.search([ SubscriptionSearch.status.in_list(Subscription.Status.Active, Subscription.Status.Canceled) ]) self.assertTrue(TestHelper.includes(collection, active_subscription)) self.assertTrue(TestHelper.includes(collection, canceled_subscription)) def test_multiple_value_node_is(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] active_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription canceled_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription Subscription.cancel(canceled_subscription.id) collection = Subscription.search([ SubscriptionSearch.status == Subscription.Status.Active ]) self.assertTrue(TestHelper.includes(collection, active_subscription)) self.assertFalse(TestHelper.includes(collection, canceled_subscription)) def test_range_node_min(self): name = "Henrietta Livingston%s" % random.randint(1, 100000) Transaction.sale({ "amount": "1500.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }) t_1800 = Transaction.sale({ "amount": "1800.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount >= "1700" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1800.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.greater_than_or_equal_to("1700") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1800.id, collection.first.id) def test_range_node_max(self): name = "Henrietta Livingston%s" % random.randint(1, 100000) t_1500 = Transaction.sale({ "amount": "1500.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction Transaction.sale({ "amount": "1800.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount <= "1700" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1500.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.less_than_or_equal_to("1700") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1500.id, collection.first.id) def test_range_node_is(self): name = "Henrietta Livingston%s" % random.randint(1, 100000) Transaction.sale({ "amount": "1500.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }) t_1800 = Transaction.sale({ "amount": "1800.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount == "1800" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1800.id, collection.first.id) def test_range_node_between(self): name = "Henrietta Livingston%s" % random.randint(1, 100000) Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }) t_1500 = Transaction.sale({ "amount": "1500.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction Transaction.sale({ "amount": "1800.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.between("1100", "1600") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1500.id, collection.first.id) def test_search_on_multiple_values(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] active_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription canceled_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription Subscription.cancel(canceled_subscription.id) collection = Subscription.search([ SubscriptionSearch.plan_id == "integration_trialless_plan", SubscriptionSearch.status.in_list([Subscription.Status.Active]) ]) self.assertTrue(TestHelper.includes(collection, active_subscription)) self.assertFalse(TestHelper.includes(collection, canceled_subscription)) braintree_python-3.57.1/tests/integration/test_us_bank_account_verification.py0000644000175000017500000002500213545202423026262 0ustar hlehlefrom tests.test_helper import * from braintree.us_bank_account_verification import UsBankAccountVerification from braintree.us_bank_account_verification_search import UsBankAccountVerificationSearch class TestUsBankAccountVerification(unittest.TestCase): def test_find_by_id(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.IndependentCheck } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) created_verification = result.payment_method.verifications[0] found_verification = UsBankAccountVerification.find(created_verification.id) self.assertEqual(created_verification, found_verification) def test_search_by_verification_method(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.IndependentCheck } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) created_verification = result.payment_method.verifications[0] found_verifications = UsBankAccountVerification.search( UsBankAccountVerificationSearch.verification_method.in_list( [UsBankAccountVerification.VerificationMethod.IndependentCheck] ), UsBankAccountVerificationSearch.customer_id == customer_id, ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(created_verification, found_verifications.first) def test_search_by_status(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.IndependentCheck } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) created_verification = result.payment_method.verifications[0] found_verifications = UsBankAccountVerification.search( UsBankAccountVerificationSearch.status.in_list([UsBankAccountVerification.Status.Verified]), UsBankAccountVerificationSearch.customer_id == customer_id, ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(created_verification, found_verifications.first) def test_search_by_account_number(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(account_number="1000000000"), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.IndependentCheck } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) created_verification = result.payment_method.verifications[0] found_verifications = UsBankAccountVerification.search( UsBankAccountVerificationSearch.account_number.ends_with("0000"), UsBankAccountVerificationSearch.customer_id == customer_id, ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(created_verification, found_verifications.first) class TestUsBankAccountVerificationCompliant(unittest.TestCase): def setUp(self): braintree.Configuration.configure( braintree.Environment.Development, "integration2_merchant_id", "integration2_public_key", "integration2_private_key" ) def tearDown(self): braintree.Configuration.configure( braintree.Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) def test_successfully_confirm_settled_micro_transfer_amounts(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(account_number="1000000000"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.MicroTransfers } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) verification = result.payment_method.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Pending) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.MicroTransfers) result = UsBankAccountVerification.confirm_micro_transfer_amounts(verification.id, [17, 29]) self.assertTrue(result.is_success) self.assertEqual(result.us_bank_account_verification.status, UsBankAccountVerification.Status.Verified) us_bank_account = UsBankAccount.find(result.us_bank_account_verification.us_bank_account.token) self.assertTrue(us_bank_account.verified) def test_successfully_confirm_unsettled_micro_transfer_amounts(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(account_number="1000000001"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.MicroTransfers } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) verification = result.payment_method.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Pending) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.MicroTransfers) result = UsBankAccountVerification.confirm_micro_transfer_amounts(verification.id, [17, 29]) self.assertTrue(result.is_success) self.assertEqual(result.us_bank_account_verification.status, UsBankAccountVerification.Status.Pending) us_bank_account = UsBankAccount.find(result.us_bank_account_verification.us_bank_account.token) self.assertFalse(us_bank_account.verified) def test_attempt_confirm_micro_transfer_amounts(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(account_number="1000000000"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.MicroTransfers } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) verification = result.payment_method.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Pending) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.MicroTransfers) result = UsBankAccountVerification.confirm_micro_transfer_amounts(verification.id, [1, 1]) self.assertFalse(result.is_success) error_code = result.errors.for_object("us_bank_account_verification").on("base")[0].code self.assertEqual(ErrorCodes.UsBankAccountVerification.AmountsDoNotMatch, error_code) def test_gateway_reject_confirm_micro_transfer_amounts(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(account_number="1000000000"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.MicroTransfers } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) verification = result.payment_method.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Pending) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.MicroTransfers) for i in range(4): result = UsBankAccountVerification.confirm_micro_transfer_amounts(verification.id, [1, 1]) self.assertFalse(result.is_success) error_code = result.errors.for_object("us_bank_account_verification").on("base")[0].code self.assertEqual(ErrorCodes.UsBankAccountVerification.AmountsDoNotMatch, error_code) result = UsBankAccountVerification.confirm_micro_transfer_amounts(verification.id, [1, 1]) self.assertFalse(result.is_success) error_code = result.errors.for_object("us_bank_account_verification").on("base")[0].code self.assertEqual(ErrorCodes.UsBankAccountVerification.TooManyConfirmationAttempts, error_code) braintree_python-3.57.1/tests/integration/__init__.py0000644000175000017500000000000013545202423021051 0ustar hlehlebraintree_python-3.57.1/tests/integration/test_us_bank_account.py0000644000175000017500000000501013545202423023515 0ustar hlehlefrom tests.test_helper import * class TestUsBankAccount(unittest.TestCase): def test_find_returns_us_bank_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } }) self.assertTrue(result.is_success) found_account = UsBankAccount.find(result.payment_method.token) self.assertEqual(found_account.routing_number, "021000021") self.assertEqual(found_account.last_4, "1234") self.assertEqual(found_account.account_type, "checking") self.assertEqual(found_account.account_holder_name, "Dan Schulman") self.assertRegexpMatches(found_account.bank_name, r".*CHASE.*") self.assertEqual(found_account.default, True) self.assertEqual(found_account.ach_mandate.text, "cl mandate text") self.assertIsNotNone(found_account.ach_mandate.accepted_at) self.assertIsInstance(found_account.ach_mandate.accepted_at, datetime) def test_find_does_not_return_invalid_us_bank_account(self): self.assertRaises(NotFoundError, UsBankAccount.find, TestHelper.generate_invalid_us_bank_account_nonce()) def test_sale_transacts_us_bank_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } }) self.assertTrue(result.is_success) params = { "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, } result = UsBankAccount.sale(result.payment_method.token, params) self.assertTrue(result.is_success) self.assertEqual(result.transaction.us_bank_account.routing_number, "021000021") self.assertEqual(result.transaction.us_bank_account.last_4, "1234") self.assertEqual(result.transaction.us_bank_account.account_type, "checking") self.assertEqual(result.transaction.us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", result.transaction.us_bank_account.bank_name)) braintree_python-3.57.1/tests/integration/test_credit_card.py0000644000175000017500000015761613545202423022646 0ustar hlehlefrom tests.test_helper import * from braintree.test.credit_card_defaults import CreditCardDefaults from braintree.test.credit_card_numbers import CreditCardNumbers import braintree.test.venmo_sdk as venmo_sdk class TestCreditCard(unittest.TestCase): def test_create_with_three_d_secure_nonce(self): customer_id = Customer.create().customer.id result = CreditCard.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.ThreeDSecureVisaFullAuthentication, "options": { "verify_card": "true", } }) self.assertTrue(result.is_success) three_d_secure_info = result.credit_card.verification.three_d_secure_info self.assertEqual("Y", three_d_secure_info.enrolled) self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertEqual("cavv_value", three_d_secure_info.cavv) self.assertEqual("xid_value", three_d_secure_info.xid) self.assertEqual(None, three_d_secure_info.ds_transaction_id) self.assertEqual("05", three_d_secure_info.eci_flag) self.assertEqual("1.0.2", three_d_secure_info.three_d_secure_version) def test_create_adds_credit_card_to_existing_customer(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertTrue(re.search(r"\A\w{4,}\Z", credit_card.token) is not None) self.assertEqual("411111", credit_card.bin) self.assertEqual("1111", credit_card.last_4) self.assertEqual("05", credit_card.expiration_month) self.assertEqual("2014", credit_card.expiration_year) self.assertEqual("05/2014", credit_card.expiration_date) self.assertEqual("John Doe", credit_card.cardholder_name) self.assertNotEqual(re.search(r"\A\w{32}\Z", credit_card.unique_number_identifier), None) self.assertFalse(credit_card.venmo_sdk) self.assertNotEqual(re.search("png", credit_card.image_url), None) def test_create_and_make_default(self): customer = Customer.create().customer card1 = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card self.assertTrue(card1.default) card2 = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe", "options": {"make_default": True} }).credit_card card1 = CreditCard.find(card1.token) self.assertFalse(card1.default) self.assertTrue(card2.default) def test_create_with_expiration_month_and_year(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertEqual("05/2014", credit_card.expiration_date) def test_create_with_security_params(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe", "device_session_id": "abc123", "fraud_merchant_id": "456" }) self.assertTrue(result.is_success) def test_create_can_specify_the_desired_token(self): token = str(random.randint(1, 1000000)) customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "token": token }) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertEqual(token, credit_card.token) def test_create_with_billing_address(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484", "country_name": "Mexico" } }) self.assertTrue(result.is_success) address = result.credit_card.billing_address self.assertEqual("123 Abc Way", address.street_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60622", address.postal_code) self.assertEqual("MX", address.country_code_alpha2) self.assertEqual("MEX", address.country_code_alpha3) self.assertEqual("484", address.country_code_numeric) self.assertEqual("Mexico", address.country_name) def test_create_with_billing_address_id(self): customer = Customer.create().customer address = Address.create({ "customer_id": customer.id, "street_address": "123 Abc Way" }).address result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address_id": address.id }) self.assertTrue(result.is_success) billing_address = result.credit_card.billing_address self.assertEqual(address.id, billing_address.id) self.assertEqual("123 Abc Way", billing_address.street_address) def test_create_without_billing_address_still_has_billing_address_method(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", }) self.assertTrue(result.is_success) self.assertEqual(None, result.credit_card.billing_address) def test_unsuccessful_create_with_card_verification_returns_risk_data(self): with AdvancedFraudIntegrationMerchant(): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": {"verify_card": True}, "device_session_id": "abc123" }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertIsInstance(verification.risk_data, RiskData) self.assertTrue(hasattr(verification.risk_data, 'id')) self.assertEqual("Approve", verification.risk_data.decision) self.assertTrue(hasattr(verification.risk_data, 'device_data_captured')) self.assertTrue(hasattr(verification.risk_data, 'fraud_service_provider')) def test_successful_create_with_card_verification_returns_risk_data(self): with AdvancedFraudIntegrationMerchant(): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "options": {"verify_card": True}, "device_session_id": "abc123" }) self.assertTrue(result.is_success) verification = result.credit_card.verification self.assertIsInstance(verification.risk_data, RiskData) self.assertTrue(hasattr(verification.risk_data, 'id')) self.assertEqual("Approve", verification.risk_data.decision) self.assertTrue(hasattr(verification.risk_data, 'device_data_captured')) self.assertTrue(hasattr(verification.risk_data, 'fraud_service_provider')) def test_create_with_card_verification(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": {"verify_card": True} }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, verification.status) self.assertEqual("2000", verification.processor_response_code) self.assertEqual("Do Not Honor", verification.processor_response_text) self.assertEqual("I", verification.cvv_response_code) self.assertEqual(None, verification.avs_error_response_code) self.assertEqual("I", verification.avs_postal_code_response_code) self.assertEqual("I", verification.avs_street_address_response_code) self.assertEqual(Decimal("0.00"), verification.amount) self.assertEqual("USD", verification.currency_iso_code) self.assertEqual(TestHelper.default_merchant_account_id, verification.merchant_account_id) def test_create_with_card_verification_with_overridden_amount(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": {"verify_card": True, "verification_amount": "1.02"} }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, verification.status) self.assertEqual("2000", verification.processor_response_code) self.assertEqual("Do Not Honor", verification.processor_response_text) self.assertEqual("I", verification.cvv_response_code) self.assertEqual(None, verification.avs_error_response_code) self.assertEqual("I", verification.avs_postal_code_response_code) self.assertEqual("I", verification.avs_street_address_response_code) self.assertEqual(Decimal("1.02"), verification.amount) self.assertEqual("USD", verification.currency_iso_code) self.assertEqual(TestHelper.default_merchant_account_id, verification.merchant_account_id) def test_create_with_card_verification_and_non_default_merchant_account(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": { "verification_merchant_account_id": TestHelper.non_default_merchant_account_id, "verify_card": True } }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, verification.status) self.assertEqual(None, verification.gateway_rejection_reason) self.assertEqual(TestHelper.non_default_merchant_account_id, verification.merchant_account_id) def test_verify_gateway_rejected_responds_to_processor_response_code(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "postal_code": "20000" }, "options": { "verify_card": True } }) self.assertFalse(result.is_success) self.assertEqual('1000', result.credit_card_verification.processor_response_code) self.assertEqual('Approved', result.credit_card_verification.processor_response_text) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_expose_gateway_rejection_reason_on_verification(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "200", "options": { "verify_card": True } }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual(Transaction.GatewayRejectionReason.Cvv, verification.gateway_rejection_reason) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_create_with_card_verification_set_to_false(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": {"verify_card": False} }) self.assertTrue(result.is_success) def test_create_with_fail_on_duplicate_payment_method_set_to_true(self): customer = Customer.create().customer CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014" }) result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": {"fail_on_duplicate_payment_method": True} }) self.assertFalse(result.is_success) self.assertEqual("Duplicate card exists in the vault.", result.message) credit_card_number_errors = result.errors.for_object("credit_card").on("number") self.assertEqual(1, len(credit_card_number_errors)) self.assertEqual(ErrorCodes.CreditCard.DuplicateCardExists, credit_card_number_errors[0].code) def test_create_with_invalid_invalid_options(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "invalid_date", }) self.assertFalse(result.is_success) self.assertEqual("Expiration date is invalid.", result.message) expiration_date_errors = result.errors.for_object("credit_card").on("expiration_date") self.assertEqual(1, len(expiration_date_errors)) self.assertEqual(ErrorCodes.CreditCard.ExpirationDateIsInvalid, expiration_date_errors[0].code) def test_create_with_invalid_country_codes(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2012", "billing_address": { "country_code_alpha2": "ZZ", "country_code_alpha3": "ZZZ", "country_code_numeric": "000", "country_name": "zzzzzzz" } }) self.assertFalse(result.is_success) country_code_alpha2_errors = result.errors.for_object("credit_card").for_object("billing_address").on("country_code_alpha2") self.assertEqual(1, len(country_code_alpha2_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, country_code_alpha2_errors[0].code) country_code_alpha3_errors = result.errors.for_object("credit_card").for_object("billing_address").on("country_code_alpha3") self.assertEqual(1, len(country_code_alpha3_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha3IsNotAccepted, country_code_alpha3_errors[0].code) country_code_numeric_errors = result.errors.for_object("credit_card").for_object("billing_address").on("country_code_numeric") self.assertEqual(1, len(country_code_numeric_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeNumericIsNotAccepted, country_code_numeric_errors[0].code) country_name_errors = result.errors.for_object("credit_card").for_object("billing_address").on("country_name") self.assertEqual(1, len(country_name_errors)) self.assertEqual(ErrorCodes.Address.CountryNameIsNotAccepted, country_name_errors[0].code) def test_create_with_venmo_sdk_payment_method_code(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "venmo_sdk_payment_method_code": venmo_sdk.VisaPaymentMethodCode }) self.assertTrue(result.is_success) self.assertEqual("411111", result.credit_card.bin) self.assertFalse(result.credit_card.venmo_sdk) def test_create_with_invalid_venmo_sdk_payment_method_code(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "venmo_sdk_payment_method_code": venmo_sdk.InvalidPaymentMethodCode }) self.assertFalse(result.is_success) self.assertEqual("Invalid VenmoSDK payment method code", result.message) venmo_sdk_payment_method_code_errors = result.errors.for_object("credit_card").on("venmo_sdk_payment_method_code") self.assertEqual(1, len(venmo_sdk_payment_method_code_errors)) self.assertEqual(ErrorCodes.CreditCard.InvalidVenmoSDKPaymentMethodCode, venmo_sdk_payment_method_code_errors[0].code) def test_create_with_payment_method_nonce(self): config = Configuration.instantiate() authorization_fingerprint = json.loads(TestHelper.generate_decoded_client_token())["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) _, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) nonce = json.loads(response)["creditCards"][0]["nonce"] customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "payment_method_nonce": nonce }) self.assertTrue(result.is_success) self.assertEqual("411111", result.credit_card.bin) def test_create_with_venmo_sdk_session(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe", "options": { "venmo_sdk_session": venmo_sdk.Session } }) self.assertTrue(result.is_success) self.assertFalse(result.credit_card.venmo_sdk) def test_create_with_invalid_venmo_sdk_session(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe", "options": { "venmo_sdk_session": venmo_sdk.InvalidSession } }) self.assertTrue(result.is_success) self.assertFalse(result.credit_card.venmo_sdk) def test_update_with_valid_options(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card result = CreditCard.update(credit_card.token, { "number": "5105105105105100", "expiration_date": "06/2010", "cvv": "123", "cardholder_name": "Jane Jones" }) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertTrue(re.search(r"\A\w{4,}\Z", credit_card.token) is not None) self.assertEqual("510510", credit_card.bin) self.assertEqual("5100", credit_card.last_4) self.assertEqual("06", credit_card.expiration_month) self.assertEqual("2010", credit_card.expiration_year) self.assertEqual("06/2010", credit_card.expiration_date) self.assertEqual("Jane Jones", credit_card.cardholder_name) def test_update_billing_address_creates_new_by_default(self): customer = Customer.create().customer initial_credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "123 Nigeria Ave", } }).credit_card updated_credit_card = CreditCard.update(initial_credit_card.token, { "billing_address": { "region": "IL", "country_code_alpha2": "NG", "country_code_alpha3": "NGA", "country_code_numeric": "566", "country_name": "Nigeria" } }).credit_card self.assertEqual("IL", updated_credit_card.billing_address.region) self.assertEqual("NG", updated_credit_card.billing_address.country_code_alpha2) self.assertEqual("NGA", updated_credit_card.billing_address.country_code_alpha3) self.assertEqual("566", updated_credit_card.billing_address.country_code_numeric) self.assertEqual("Nigeria", updated_credit_card.billing_address.country_name) self.assertEqual(None, updated_credit_card.billing_address.street_address) self.assertNotEqual(initial_credit_card.billing_address.id, updated_credit_card.billing_address.id) def test_update_billing_address_when_update_existing_is_True(self): customer = Customer.create().customer initial_credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "123 Nigeria Ave", } }).credit_card updated_credit_card = CreditCard.update(initial_credit_card.token, { "billing_address": { "region": "IL", "options": { "update_existing": True } } }).credit_card self.assertEqual("IL", updated_credit_card.billing_address.region) self.assertEqual("123 Nigeria Ave", updated_credit_card.billing_address.street_address) self.assertEqual(initial_credit_card.billing_address.id, updated_credit_card.billing_address.id) def test_update_and_make_default(self): customer = Customer.create().customer card1 = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card card2 = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card self.assertTrue(card1.default) self.assertFalse(card2.default) CreditCard.update(card2.token, { "options": { "make_default": True } }) self.assertFalse(CreditCard.find(card1.token).default) self.assertTrue(CreditCard.find(card2.token).default) def test_update_verifies_card_if_option_is_provided(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card result = CreditCard.update(credit_card.token, { "number": "4000111111111115", "expiration_date": "06/2010", "cvv": "123", "cardholder_name": "Jane Jones", "options": {"verify_card": True} }) self.assertFalse(result.is_success) self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, result.credit_card_verification.status) def test_update_verifies_card_with_non_default_merchant_account(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card result = CreditCard.update(credit_card.token, { "number": "4000111111111115", "expiration_date": "06/2010", "cvv": "123", "cardholder_name": "Jane Jones", "options": { "verification_merchant_account_id": TestHelper.non_default_merchant_account_id, "verify_card": True } }) self.assertFalse(result.is_success) self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, result.credit_card_verification.status) def test_update_billing_address(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "321 Xyz Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60621" } }).credit_card result = CreditCard.update(credit_card.token, { "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622" } }) self.assertTrue(result.is_success) address = result.credit_card.billing_address self.assertEqual("123 Abc Way", address.street_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60622", address.postal_code) def test_update_returns_error_if_invalid(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014" }).credit_card result = CreditCard.update(credit_card.token, { "expiration_date": "invalid_date" }) self.assertFalse(result.is_success) expiration_date_errors = result.errors.for_object("credit_card").on("expiration_date") self.assertEqual(1, len(expiration_date_errors)) self.assertEqual(ErrorCodes.CreditCard.ExpirationDateIsInvalid, expiration_date_errors[0].code) def test_update_returns_error_with_duplicate_payment_method_if_fail_on_duplicate_payment_method_is_set(self): create_result = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2021", } }) self.assertTrue(create_result.is_success) update_result = Customer.update(create_result.customer.id, { "credit_card": { "number": "4111111111111111", "expiration_date": "05/2021", "options": { "fail_on_duplicate_payment_method": True, }, } }) self.assertFalse(update_result.is_success) number_errors = update_result.errors.for_object("customer").for_object("credit_card").on("number") self.assertEqual(1, len(number_errors)) self.assertEqual(ErrorCodes.CreditCard.DuplicateCardExists, number_errors[0].code) def test_delete_with_valid_token(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014" }).credit_card result = CreditCard.delete(credit_card.token) self.assertTrue(result.is_success) @raises(NotFoundError) def test_delete_raises_error_when_deleting_twice(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014" }).credit_card CreditCard.delete(credit_card.token) CreditCard.delete(credit_card.token) @raises(NotFoundError) def test_delete_with_invalid_token(self): CreditCard.delete("notreal") def test_find_with_valid_token(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014" }).credit_card found_credit_card = CreditCard.find(credit_card.token) self.assertTrue(re.search(r"\A\w{4,}\Z", found_credit_card.token) is not None) self.assertEqual("411111", found_credit_card.bin) self.assertEqual("1111", found_credit_card.last_4) self.assertEqual("05", found_credit_card.expiration_month) self.assertEqual("2014", found_credit_card.expiration_year) self.assertEqual("05/2014", found_credit_card.expiration_date) def test_find_returns_associated_subsriptions(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014" }).credit_card subscription_id = "id_" + str(random.randint(1, 1000000)) subscription = Subscription.create({ "id": subscription_id, "plan_id": "integration_trialless_plan", "payment_method_token": credit_card.token, "price": Decimal("1.00") }).subscription found_credit_card = CreditCard.find(credit_card.token) subscriptions = found_credit_card.subscriptions self.assertEqual(1, len(subscriptions)) subscription = subscriptions[0] self.assertEqual(subscription_id, subscription.id) self.assertEqual(Decimal("1.00"), subscription.price) self.assertEqual(credit_card.token, subscription.payment_method_token) @raises_with_regexp(NotFoundError, "payment method with token 'bad_token' not found") def test_find_with_invalid_token(self): CreditCard.find("bad_token") def test_from_nonce_with_unlocked_nonce(self): config = Configuration.instantiate() customer = Customer.create().customer client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer.id, }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) nonce = json.loads(response)["creditCards"][0]["nonce"] card = CreditCard.from_nonce(nonce) customer = Customer.find(customer.id) self.assertEqual(1, len(customer.credit_cards)) self.assertEqual(customer.credit_cards[0].token, card.token) @raises_with_regexp(NotFoundError, "payment method with nonce .* or not found") def test_from_nonce_with_unlocked_nonce_pointing_to_shared_card(self): config = Configuration.instantiate() client_token = TestHelper.generate_decoded_client_token() authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) self.assertEqual(201, status_code) nonce = json.loads(response)["creditCards"][0]["nonce"] CreditCard.from_nonce(nonce) @raises_with_regexp(NotFoundError, ".* consumed .*") def test_from_nonce_with_consumed_nonce(self): config = Configuration.instantiate() customer = Customer.create().customer client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer.id, }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) nonce = json.loads(response)["creditCards"][0]["nonce"] CreditCard.from_nonce(nonce) CreditCard.from_nonce(nonce) def test_create_from_transparent_redirect(self): customer = Customer.create().customer tr_data = { "credit_card": { "customer_id": customer.id } } post_params = { "tr_data": CreditCard.tr_data_for_create(tr_data, "http://example.com/path?foo=bar"), "credit_card[cardholder_name]": "Card Holder", "credit_card[number]": "4111111111111111", "credit_card[expiration_date]": "05/2012", "credit_card[billing_address][country_code_alpha2]": "MX", "credit_card[billing_address][country_code_alpha3]": "MEX", "credit_card[billing_address][country_code_numeric]": "484", "credit_card[billing_address][country_name]": "Mexico", } query_string = TestHelper.simulate_tr_form_post(post_params, CreditCard.transparent_redirect_create_url()) result = CreditCard.confirm_transparent_redirect(query_string) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertEqual("411111", credit_card.bin) self.assertEqual("1111", credit_card.last_4) self.assertEqual("05", credit_card.expiration_month) self.assertEqual("2012", credit_card.expiration_year) self.assertEqual(customer.id, credit_card.customer_id) self.assertEqual("MX", credit_card.billing_address.country_code_alpha2) self.assertEqual("MEX", credit_card.billing_address.country_code_alpha3) self.assertEqual("484", credit_card.billing_address.country_code_numeric) self.assertEqual("Mexico", credit_card.billing_address.country_name) def test_create_from_transparent_redirect_and_make_default(self): customer = Customer.create().customer card1 = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card self.assertTrue(card1.default) tr_data = { "credit_card": { "customer_id": customer.id, "options": { "make_default": True } } } post_params = { "tr_data": CreditCard.tr_data_for_create(tr_data, "http://example.com/path?foo=bar"), "credit_card[cardholder_name]": "Card Holder", "credit_card[number]": "4111111111111111", "credit_card[expiration_date]": "05/2012", } query_string = TestHelper.simulate_tr_form_post(post_params, CreditCard.transparent_redirect_create_url()) card2 = CreditCard.confirm_transparent_redirect(query_string).credit_card self.assertFalse(CreditCard.find(card1.token).default) self.assertTrue(card2.default) def test_create_from_transparent_redirect_with_error_result(self): customer = Customer.create().customer tr_data = { "credit_card": { "customer_id": customer.id } } post_params = { "tr_data": CreditCard.tr_data_for_create(tr_data, "http://example.com/path"), "credit_card[cardholder_name]": "Card Holder", "credit_card[number]": "eleventy", "credit_card[expiration_date]": "y2k" } query_string = TestHelper.simulate_tr_form_post(post_params, CreditCard.transparent_redirect_create_url()) result = CreditCard.confirm_transparent_redirect(query_string) self.assertFalse(result.is_success) credit_card_number_errors = result.errors.for_object("credit_card").on("number") self.assertEqual(1, len(credit_card_number_errors)) self.assertEqual(ErrorCodes.CreditCard.NumberHasInvalidLength, credit_card_number_errors[0].code) expiration_date_errors = result.errors.for_object("credit_card").on("expiration_date") self.assertEqual(1, len(expiration_date_errors)) self.assertEqual(ErrorCodes.CreditCard.ExpirationDateIsInvalid, expiration_date_errors[0].code) def test_update_from_transparent_redirect_with_successful_result(self): old_token = str(random.randint(1, 1000000)) new_token = str(random.randint(1, 1000000)) credit_card = Customer.create({ "credit_card": { "cardholder_name": "Old Cardholder Name", "number": "4111111111111111", "expiration_date": "05/2012", "token": old_token } }).customer.credit_cards[0] tr_data = { "payment_method_token": old_token, "credit_card": { "token": new_token } } post_params = { "tr_data": CreditCard.tr_data_for_update(tr_data, "http://example.com/path"), "credit_card[cardholder_name]": "New Cardholder Name", "credit_card[expiration_date]": "05/2014" } query_string = TestHelper.simulate_tr_form_post(post_params, CreditCard.transparent_redirect_update_url()) result = CreditCard.confirm_transparent_redirect(query_string) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertEqual(new_token, credit_card.token) self.assertEqual("411111", credit_card.bin) self.assertEqual("1111", credit_card.last_4) self.assertEqual("05", credit_card.expiration_month) self.assertEqual("2014", credit_card.expiration_year) def test_update_from_transparent_redirect_and_make_default(self): customer = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).customer card1 = customer.credit_cards[0] card2 = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", }).credit_card self.assertTrue(card1.default) self.assertFalse(card2.default) tr_data = { "payment_method_token": card2.token, "credit_card": { "options": { "make_default": True } } } post_params = { "tr_data": CreditCard.tr_data_for_update(tr_data, "http://example.com/path"), "credit_card[cardholder_name]": "New Cardholder Name", "credit_card[expiration_date]": "05/2014" } query_string = TestHelper.simulate_tr_form_post(post_params, CreditCard.transparent_redirect_update_url()) CreditCard.confirm_transparent_redirect(query_string) self.assertFalse(CreditCard.find(card1.token).default) self.assertTrue(CreditCard.find(card2.token).default) def test_update_from_transparent_redirect_and_update_existing_billing_address(self): customer = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "billing_address": { "street_address": "123 Old St", "locality": "Chicago", "region": "Illinois", "postal_code": "60621" } } }).customer card = customer.credit_cards[0] tr_data = { "payment_method_token": card.token, "credit_card": { "billing_address": { "street_address": "123 New St", "locality": "Columbus", "region": "Ohio", "postal_code": "43215", "options": { "update_existing": True } } } } post_params = { "tr_data": CreditCard.tr_data_for_update(tr_data, "http://example.com/path") } query_string = TestHelper.simulate_tr_form_post(post_params, CreditCard.transparent_redirect_update_url()) CreditCard.confirm_transparent_redirect(query_string) self.assertEqual(1, len(Customer.find(customer.id).addresses)) updated_card = CreditCard.find(card.token) self.assertEqual("123 New St", updated_card.billing_address.street_address) self.assertEqual("Columbus", updated_card.billing_address.locality) self.assertEqual("Ohio", updated_card.billing_address.region) self.assertEqual("43215", updated_card.billing_address.postal_code) def test_update_from_transparent_redirect_with_error_result(self): old_token = str(random.randint(1, 1000000)) Customer.create({ "credit_card": { "cardholder_name": "Old Cardholder Name", "number": "4111111111111111", "expiration_date": "05/2012", "token": old_token } }) tr_data = { "payment_method_token": old_token, "credit_card": { "token": "bad token" } } post_params = { "tr_data": CreditCard.tr_data_for_update(tr_data, "http://example.com/path"), "credit_card[cardholder_name]": "New Cardholder Name", "credit_card[expiration_date]": "05/2014" } query_string = TestHelper.simulate_tr_form_post(post_params, CreditCard.transparent_redirect_update_url()) result = CreditCard.confirm_transparent_redirect(query_string) self.assertFalse(result.is_success) credit_card_token_errors = result.errors.for_object("credit_card").on("token") self.assertEqual(1, len(credit_card_token_errors)) self.assertEqual(ErrorCodes.CreditCard.TokenInvalid, credit_card_token_errors[0].code) def test_expired_can_iterate_over_all_items(self): customer_id = Customer.all().first.id for _ in range(110 - CreditCard.expired().maximum_size): CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "01/2015" }) collection = CreditCard.expired() self.assertTrue(collection.maximum_size > 100) credit_card_tokens = [credit_card.token for credit_card in collection.items] self.assertEqual(collection.maximum_size, len(TestHelper.unique(credit_card_tokens))) self.assertEqual(set([True]), TestHelper.unique([credit_card.is_expired for credit_card in collection.items])) def test_expiring_between(self): customer_id = Customer.all().first.id for _ in range(110 - CreditCard.expiring_between(date(2010, 1, 1), date(2010, 12, 31)).maximum_size): CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100", "cardholder_name": "John Doe" }) collection = CreditCard.expiring_between(date(2010, 1, 1), date(2010, 12, 31)) self.assertTrue(collection.maximum_size > 100) credit_card_tokens = [credit_card.token for credit_card in collection.items] self.assertEqual(collection.maximum_size, len(TestHelper.unique(credit_card_tokens))) self.assertEqual(set(['2010']), TestHelper.unique([credit_card.expiration_year for credit_card in collection.items])) def test_commercial_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Commercial, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Commercial.Yes, credit_card.commercial) def test_issuing_bank(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.IssuingBank, "expiration_date": "05/2014" }) credit_card = result.credit_card self.assertEqual(CreditCardDefaults.IssuingBank, credit_card.issuing_bank) def test_country_of_issuance(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.CountryOfIssuance, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCardDefaults.CountryOfIssuance, credit_card.country_of_issuance) def test_durbin_regulated_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.DurbinRegulated, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.DurbinRegulated.Yes, credit_card.durbin_regulated) def test_debit_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Debit, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Debit.Yes, credit_card.debit) def test_healthcare_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Healthcare, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Healthcare.Yes, credit_card.healthcare) self.assertEqual("J3", credit_card.product_id) def test_payroll_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Payroll, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Payroll.Yes, credit_card.payroll) self.assertEqual("MSA", credit_card.product_id) def test_prepaid_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Prepaid, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Prepaid.Yes, credit_card.prepaid) def test_all_negative_card_type_indicators(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.No, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Debit.No, credit_card.debit) self.assertEqual(CreditCard.DurbinRegulated.No, credit_card.durbin_regulated) self.assertEqual(CreditCard.Prepaid.No, credit_card.prepaid) self.assertEqual(CreditCard.Payroll.No, credit_card.payroll) self.assertEqual(CreditCard.Commercial.No, credit_card.commercial) self.assertEqual(CreditCard.Healthcare.No, credit_card.healthcare) self.assertEqual("MSB", credit_card.product_id) def test_card_without_card_type_indicators(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Unknown, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Debit.Unknown, credit_card.debit) self.assertEqual(CreditCard.DurbinRegulated.Unknown, credit_card.durbin_regulated) self.assertEqual(CreditCard.Prepaid.Unknown, credit_card.prepaid) self.assertEqual(CreditCard.Payroll.Unknown, credit_card.payroll) self.assertEqual(CreditCard.Commercial.Unknown, credit_card.commercial) self.assertEqual(CreditCard.Healthcare.Unknown, credit_card.healthcare) self.assertEqual(CreditCard.IssuingBank.Unknown, credit_card.issuing_bank) self.assertEqual(CreditCard.CountryOfIssuance.Unknown, credit_card.country_of_issuance) self.assertEquals(CreditCard.ProductId.Unknown, credit_card.product_id) def test_card_with_account_type_debit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2014", "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "debit" } }) self.assertEqual(result.is_success, True) self.assertEqual("debit", result.credit_card.verifications[0]["credit_card"]["account_type"]) updated_result = CreditCard.update(result.credit_card.token, { "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "debit" } }) self.assertEqual(updated_result.is_success, True) self.assertEqual("debit", updated_result.credit_card.verifications[1]["credit_card"]["account_type"]) def test_card_with_account_type_credit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2014", "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "credit" } }) self.assertEqual(result.is_success, True) self.assertEqual("credit", result.credit_card.verifications[0]["credit_card"]["account_type"]) updated_result = CreditCard.update(result.credit_card.token, { "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "credit" } }) self.assertEqual(updated_result.is_success, True) self.assertEqual("credit", updated_result.credit_card.verifications[0]["credit_card"]["account_type"]) def test_card_with_account_type_credit_debit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2014", "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "credit" } }) self.assertEqual(result.is_success, True) self.assertEqual("credit", result.credit_card.verifications[0]["credit_card"]["account_type"]) updated_result = CreditCard.update(result.credit_card.token, { "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "debit" } }) self.assertEqual(updated_result.is_success, True) self.assertEqual("debit", updated_result.credit_card.verifications[0]["credit_card"]["account_type"]) self.assertEqual("credit", updated_result.credit_card.verifications[1]["credit_card"]["account_type"]) braintree_python-3.57.1/tests/integration/test_settlement_batch_summary.py0000644000175000017500000000521713545202423025472 0ustar hlehlefrom tests.test_helper import * class TestSettlementBatchSummary(unittest.TestCase): possible_gateway_time_zone_offsets = (5, 4) def test_generate_returns_empty_collection_if_there_is_no_data(self): result = SettlementBatchSummary.generate('2011-01-01') self.assertTrue(result.is_success) self.assertEqual([], result.settlement_batch_summary.records) def test_generate_returns_error_if_date_can_not_be_parsed(self): result = SettlementBatchSummary.generate('THIS AINT NO DATE') self.assertFalse(result.is_success) settlement_date_errors = result.errors.for_object('settlement_batch_summary').on('settlement_date') self.assertEqual(1, len(settlement_date_errors)) self.assertEqual(ErrorCodes.SettlementBatchSummary.SettlementDateIsInvalid, settlement_date_errors[0].code) def test_generate_returns_transactions_settled_on_a_given_day(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Sergio Ramos" }, "merchant_account_id": "sandbox_credit_card", "options": {"submit_for_settlement": True} }) result = TestHelper.settle_transaction(result.transaction.id) settlement_date = result.transaction.settlement_batch_id.split('_')[0] result = SettlementBatchSummary.generate(settlement_date) self.assertTrue(result.is_success) visa_records = [row for row in result.settlement_batch_summary.records if row['card_type'] == 'Visa' and row['merchant_account_id'] == 'sandbox_credit_card'][0] count = int(visa_records['count']) self.assertGreaterEqual(count, 1) def test_generate_can_be_grouped_by_a_custom_field(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Sergio Ramos" }, "options": {"submit_for_settlement": True}, "custom_fields": { "store_me": 1 } }) result = TestHelper.settle_transaction(result.transaction.id) settlement_date = result.transaction.settlement_batch_id.split('_')[0] result = SettlementBatchSummary.generate(settlement_date, 'store_me') self.assertTrue(result.is_success) self.assertTrue('store_me' in result.settlement_batch_summary.records[0]) braintree_python-3.57.1/tests/integration/test_merchant.py0000644000175000017500000002540213545202423022167 0ustar hlehlefrom tests.test_helper import * from braintree.test.nonces import Nonces class TestMerchantGateway(unittest.TestCase): def setUp(self): self.gateway = BraintreeGateway( client_id="client_id$development$signup_client_id", client_secret="client_secret$development$signup_client_secret" ) def test_create_merchant(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["credit_card", "paypal"] }) merchant = result.merchant self.assertIsNotNone(merchant.id) self.assertEqual(merchant.email, "name@email.com") self.assertEqual(merchant.country_code_alpha3, "USA") self.assertEqual(merchant.country_code_alpha2, "US") self.assertEqual(merchant.country_code_numeric, "840") self.assertEqual(merchant.country_name, "United States of America") self.assertEqual(merchant.company_name, "name@email.com") self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) def test_returns_error_with_invalid_payment_methods(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["fake_money"] }) self.assertFalse(result.is_success) self.assertIn("One or more payment methods passed are not accepted.", result.message) payment_method_errors = result.errors.for_object("merchant").on("payment_methods") self.assertEqual(1, len(payment_method_errors)) self.assertEqual(payment_method_errors[0].code, ErrorCodes.Merchant.PaymentMethodsAreInvalid) def test_create_paypal_only_merchant_that_accepts_multiple_currencies(self): result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["paypal"], "currencies": ["GBP", "USD"], "paypal_account": { "client_id": "paypal_client_id", "client_secret": "paypal_client_secret" } }) merchant = result.merchant self.assertIsNotNone(merchant.id) self.assertEqual(merchant.email, "name@email.com") self.assertEqual(merchant.country_code_alpha3, "USA") self.assertEqual(merchant.country_code_alpha2, "US") self.assertEqual(merchant.country_code_numeric, "840") self.assertEqual(merchant.country_name, "United States of America") self.assertEqual(merchant.company_name, "name@email.com") self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) merchant_accounts = merchant.merchant_accounts self.assertEqual(2, len(merchant_accounts)) usd_merchant_account = [ma for ma in merchant_accounts if ma.id == "USD"][0] self.assertTrue(usd_merchant_account.default) self.assertEqual(usd_merchant_account.currency_iso_code, "USD") gbp_merchant_account = [ma for ma in merchant_accounts if ma.id == "GBP"][0] self.assertFalse(gbp_merchant_account.default) self.assertEqual(gbp_merchant_account.currency_iso_code, "GBP") def test_create_us_merchant_that_accepts_multiple_currencies(self): result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["credit_card", "paypal"], "currencies": ["GBP", "USD"], "paypal_account": { "client_id": "paypal_client_id", "client_secret": "paypal_client_secret" } }) merchant = result.merchant self.assertIsNotNone(merchant.id) self.assertEqual(merchant.email, "name@email.com") self.assertEqual(merchant.country_code_alpha3, "USA") self.assertEqual(merchant.country_code_alpha2, "US") self.assertEqual(merchant.country_code_numeric, "840") self.assertEqual(merchant.country_name, "United States of America") self.assertEqual(merchant.company_name, "name@email.com") self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) merchant_accounts = merchant.merchant_accounts self.assertEqual(2, len(merchant_accounts)) usd_merchant_account = [ma for ma in merchant_accounts if ma.id == "USD"][0] self.assertTrue(usd_merchant_account.default) self.assertEqual(usd_merchant_account.currency_iso_code, "USD") gbp_merchant_account = [ma for ma in merchant_accounts if ma.id == "GBP"][0] self.assertFalse(gbp_merchant_account.default) self.assertEqual(gbp_merchant_account.currency_iso_code, "GBP") def test_create_eu_merchant_that_accepts_multiple_currencies(self): result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["credit_card", "paypal"], "currencies": ["GBP", "USD"], "paypal_account": { "client_id": "paypal_client_id", "client_secret": "paypal_client_secret" } }) merchant = result.merchant self.assertIsNotNone(merchant.id) self.assertEqual(merchant.email, "name@email.com") self.assertEqual(merchant.country_code_alpha3, "GBR") self.assertEqual(merchant.country_code_alpha2, "GB") self.assertEqual(merchant.country_code_numeric, "826") self.assertEqual(merchant.country_name, "United Kingdom") self.assertEqual(merchant.company_name, "name@email.com") self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) merchant_accounts = merchant.merchant_accounts self.assertEqual(2, len(merchant_accounts)) usd_merchant_account = [ma for ma in merchant_accounts if ma.id == "USD"][0] self.assertFalse(usd_merchant_account.default) self.assertEqual(usd_merchant_account.currency_iso_code, "USD") gbp_merchant_account = [ma for ma in merchant_accounts if ma.id == "GBP"][0] self.assertTrue(gbp_merchant_account.default) self.assertEqual(gbp_merchant_account.currency_iso_code, "GBP") def test_allows_creation_of_non_US_merchant_if_onboarding_application_is_internal(self): result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "JPN", "payment_methods": ["paypal"], "paypal_account": { "client_id": "paypal_client_id", "client_secret": "paypal_client_secret" } }) merchant = result.merchant self.assertIsNotNone(merchant.id) self.assertEqual(merchant.email, "name@email.com") self.assertEqual(merchant.country_code_alpha3, "JPN") self.assertEqual(merchant.country_code_alpha2, "JP") self.assertEqual(merchant.country_code_numeric, "392") self.assertEqual(merchant.country_name, "Japan") self.assertEqual(merchant.company_name, "name@email.com") self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) merchant_accounts = merchant.merchant_accounts self.assertEqual(1, len(merchant_accounts)) usd_merchant_account = merchant_accounts[0] self.assertTrue(usd_merchant_account.default) self.assertEqual(usd_merchant_account.currency_iso_code, "JPY") def test_defaults_to_USD_for_non_US_merchant_if_onboarding_application_is_internal_and_country_currency_not_supported(self): result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "YEM", "payment_methods": ["paypal"], "paypal_account": { "client_id": "paypal_client_id", "client_secret": "paypal_client_secret" } }) merchant = result.merchant self.assertIsNotNone(merchant.id) self.assertEqual(merchant.email, "name@email.com") self.assertEqual(merchant.country_code_alpha3, "YEM") self.assertEqual(merchant.country_code_alpha2, "YE") self.assertEqual(merchant.country_code_numeric, "887") self.assertEqual(merchant.country_name, "Yemen") self.assertEqual(merchant.company_name, "name@email.com") self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) merchant_accounts = merchant.merchant_accounts self.assertEqual(1, len(merchant_accounts)) usd_merchant_account = merchant_accounts[0] self.assertTrue(usd_merchant_account.default) self.assertEqual(usd_merchant_account.currency_iso_code, "USD") def test_returns_error_if_invalid_currency_is_passed(self): result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["credit_card"], "currencies": ["GBP", "FAKE"], "paypal_account": { "client_id": "paypal_client_id", "client_secret": "paypal_client_secret" } }) self.assertFalse(result.is_success) currencies_errors = result.errors.for_object("merchant").on("currencies") self.assertEqual(1, len(currencies_errors)) self.assertEqual(ErrorCodes.Merchant.CurrenciesAreInvalid, currencies_errors[0].code) braintree_python-3.57.1/tests/integration/test_merchant_account.py0000644000175000017500000006753313545202423023716 0ustar hlehlefrom tests.test_helper import * class TestMerchantAccount(unittest.TestCase): DEPRECATED_APPLICATION_PARAMS = { "applicant_details": { "company_name": "Garbage Garage", "first_name": "Joe", "last_name": "Bloggs", "email": "joe@bloggs.com", "phone": "555-555-5555", "address": { "street_address": "123 Credibility St.", "postal_code": "60606", "locality": "Chicago", "region": "IL", }, "date_of_birth": "10/9/1980", "ssn": "123-00-1234", "tax_id": "123456789", "routing_number": "122100024", "account_number": "43759348798" }, "tos_accepted": True, "master_merchant_account_id": "sandbox_master_merchant_account" } VALID_APPLICATION_PARAMS = { "individual": { "first_name": "Joe", "last_name": "Bloggs", "email": "joe@bloggs.com", "phone": "555-555-5555", "address": { "street_address": "123 Credibility St.", "postal_code": "60606", "locality": "Chicago", "region": "IL", }, "date_of_birth": "10/9/1980", "ssn": "123-00-1234", }, "business": { "dba_name": "Garbage Garage", "legal_name": "Junk Jymnasium", "tax_id": "123456789", "address": { "street_address": "123 Reputation St.", "postal_code": "40222", "locality": "Louisville", "region": "KY", }, }, "funding": { "routing_number": "122100024", "account_number": "43759348798", "destination": MerchantAccount.FundingDestination.Bank, "descriptor": "Joes Bloggs KY", }, "tos_accepted": True, "master_merchant_account_id": "sandbox_master_merchant_account" } def test_create_accepts_deprecated_parameters(self): result = MerchantAccount.create(self.DEPRECATED_APPLICATION_PARAMS) self.assertTrue(result.is_success) self.assertEqual(MerchantAccount.Status.Pending, result.merchant_account.status) self.assertEqual("sandbox_master_merchant_account", result.merchant_account.master_merchant_account.id) def test_create_application_with_valid_params_and_no_id(self): result = MerchantAccount.create(self.VALID_APPLICATION_PARAMS) self.assertTrue(result.is_success) self.assertEqual(MerchantAccount.Status.Pending, result.merchant_account.status) self.assertEqual("sandbox_master_merchant_account", result.merchant_account.master_merchant_account.id) def test_create_allows_an_id_to_pass(self): params_with_id = self.VALID_APPLICATION_PARAMS.copy() rand = str(random.randint(1, 1000000)) params_with_id['id'] = 'sub_merchant_account_id' + rand result = MerchantAccount.create(params_with_id) self.assertTrue(result.is_success) self.assertEqual(MerchantAccount.Status.Pending, result.merchant_account.status) self.assertEqual(params_with_id['id'], result.merchant_account.id) self.assertEqual("sandbox_master_merchant_account", result.merchant_account.master_merchant_account.id) def test_create_handles_unsuccessful_results(self): result = MerchantAccount.create({}) self.assertFalse(result.is_success) merchant_account_id_errors = result.errors.for_object("merchant_account").on("master_merchant_account_id") self.assertEqual(1, len(merchant_account_id_errors)) self.assertEqual(ErrorCodes.MerchantAccount.MasterMerchantAccountIdIsRequired, merchant_account_id_errors[0].code) def test_create_requires_all_fields(self): result = MerchantAccount.create( {"master_merchant_account_id": "sandbox_master_merchant_account", "applicant_details": {}, "tos_accepted": True} ) self.assertFalse(result.is_success) first_name_errors = result.errors.for_object("merchant_account").for_object("applicant_details").on("first_name") self.assertEqual(1, len(first_name_errors)) self.assertEqual(ErrorCodes.MerchantAccount.ApplicantDetails.FirstNameIsRequired, first_name_errors[0].code) def test_create_funding_destination_accepts_a_bank(self): params = self.VALID_APPLICATION_PARAMS.copy() params['funding']['destination'] = MerchantAccount.FundingDestination.Bank result = MerchantAccount.create(params) self.assertTrue(result.is_success) def test_create_funding_destination_accepts_an_email(self): params = self.VALID_APPLICATION_PARAMS.copy() params['funding']['destination'] = MerchantAccount.FundingDestination.Email params['funding']['email'] = "junkman@hotmail.com" result = MerchantAccount.create(params) self.assertTrue(result.is_success) def test_create_funding_destination_accepts_a_mobile_phone(self): params = self.VALID_APPLICATION_PARAMS.copy() params['funding']['destination'] = MerchantAccount.FundingDestination.MobilePhone params['funding']['mobile_phone'] = "1112223333" result = MerchantAccount.create(params) self.assertTrue(result.is_success) def test_update_all_merchant_account_fields(self): UPDATE_PARAMS = { "individual": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone": "312-555-1234", "address": { "street_address": "123 Fake St", "postal_code": "60622", "locality": "Chicago", "region": "IL", }, "date_of_birth": "1970-01-01", "ssn": "987-65-4321", }, "business": { "dba_name": "James's Bloggs", "legal_name": "James's Junkyard", "tax_id": "987654321", "address": { "street_address": "456 Fake St", "postal_code": "48104", "locality": "Ann Arbor", "region": "MI", }, }, "funding": { "routing_number": "071000013", "account_number": "666666789", "destination": MerchantAccount.FundingDestination.Email, "email": "check@this.com", "mobile_phone": "9998887777", "descriptor": "Joes Bloggs MI", } } result = MerchantAccount.update("sandbox_sub_merchant_account", UPDATE_PARAMS) self.assertTrue(result.is_success) self.assertEqual(result.merchant_account.status, "active") self.assertEqual(result.merchant_account.id, "sandbox_sub_merchant_account") self.assertEqual(result.merchant_account.master_merchant_account.id, "sandbox_master_merchant_account") self.assertEqual(result.merchant_account.individual_details.first_name, "John") self.assertEqual(result.merchant_account.individual_details.last_name, "Doe") self.assertEqual(result.merchant_account.individual_details.email, "john.doe@example.com") self.assertEqual(result.merchant_account.individual_details.date_of_birth, "1970-01-01") self.assertEqual(result.merchant_account.individual_details.phone, "3125551234") self.assertEqual(result.merchant_account.individual_details.address_details.street_address, "123 Fake St") self.assertEqual(result.merchant_account.individual_details.address_details.locality, "Chicago") self.assertEqual(result.merchant_account.individual_details.address_details.region, "IL") self.assertEqual(result.merchant_account.individual_details.address_details.postal_code, "60622") self.assertEqual(result.merchant_account.business_details.dba_name, "James's Bloggs") self.assertEqual(result.merchant_account.business_details.legal_name, "James's Junkyard") self.assertEqual(result.merchant_account.business_details.tax_id, "987654321") self.assertEqual(result.merchant_account.business_details.address_details.street_address, "456 Fake St") self.assertEqual(result.merchant_account.business_details.address_details.postal_code, "48104") self.assertEqual(result.merchant_account.business_details.address_details.locality, "Ann Arbor") self.assertEqual(result.merchant_account.business_details.address_details.region, "MI") self.assertEqual(result.merchant_account.funding_details.routing_number, "071000013") self.assertEqual(result.merchant_account.funding_details.account_number_last_4, "6789") self.assertEqual(result.merchant_account.funding_details.destination, MerchantAccount.FundingDestination.Email) self.assertEqual(result.merchant_account.funding_details.email, "check@this.com") self.assertEqual(result.merchant_account.funding_details.mobile_phone, "9998887777") self.assertEqual(result.merchant_account.funding_details.descriptor, "Joes Bloggs MI") def test_update_does_not_require_all_fields(self): result = MerchantAccount.update("sandbox_sub_merchant_account", { "individual": { "first_name": "Jose" } }) self.assertTrue(result.is_success) def test_update_handles_validation_errors_for_blank_fields(self): params = { "individual": { "first_name": "", "last_name": "", "email": "", "phone": "", "date_of_birth": "", "ssn": "", "address": { "street_address": "", "postal_code": "", "locality": "", "region": "", }, }, "business": { "legal_name": "", "dba_name": "", "tax_id": "" }, "funding": { "destination": "", "routing_number": "", "account_number": "" } } result = MerchantAccount.update("sandbox_sub_merchant_account", params) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("first_name")[0].code, ErrorCodes.MerchantAccount.Individual.FirstNameIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("last_name")[0].code, ErrorCodes.MerchantAccount.Individual.LastNameIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("date_of_birth")[0].code, ErrorCodes.MerchantAccount.Individual.DateOfBirthIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("email")[0].code, ErrorCodes.MerchantAccount.Individual.EmailAddressIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Individual.Address.StreetAddressIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Individual.Address.PostalCodeIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("locality")[0].code, ErrorCodes.MerchantAccount.Individual.Address.LocalityIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Individual.Address.RegionIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("destination")[0].code, ErrorCodes.MerchantAccount.Funding.DestinationIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("first_name")[0].code, ErrorCodes.MerchantAccount.Individual.FirstNameIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("last_name")[0].code, ErrorCodes.MerchantAccount.Individual.LastNameIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("date_of_birth")[0].code, ErrorCodes.MerchantAccount.Individual.DateOfBirthIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("email")[0].code, ErrorCodes.MerchantAccount.Individual.EmailAddressIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Individual.Address.StreetAddressIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Individual.Address.PostalCodeIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("locality")[0].code, ErrorCodes.MerchantAccount.Individual.Address.LocalityIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Individual.Address.RegionIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("destination")[0].code, ErrorCodes.MerchantAccount.Funding.DestinationIsRequired) self.assertEqual(0, len(result.errors.for_object("merchant_account").on("base"))) def test_update_handles_validation_errors_for_invalid_fields(self): params = { "individual": { "first_name": "<>", "last_name": "<>", "email": "bad", "phone": "999", "address": { "street_address": "nope", "postal_code": "1", "region": "QQ", }, "date_of_birth": "hah", "ssn": "12345", }, "business": { "legal_name": "``{}", "dba_name": "{}``", "tax_id": "bad", "address": { "street_address": "nope", "postal_code": "1", "region": "QQ", }, }, "funding": { "destination": "MY WALLET", "routing_number": "LEATHER", "account_number": "BACK POCKET", "email": "BILLFOLD", "mobile_phone": "TRIFOLD" }, } result = MerchantAccount.update("sandbox_sub_merchant_account", params) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("first_name")[0].code, ErrorCodes.MerchantAccount.Individual.FirstNameIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("last_name")[0].code, ErrorCodes.MerchantAccount.Individual.LastNameIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("email")[0].code, ErrorCodes.MerchantAccount.Individual.EmailAddressIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("phone")[0].code, ErrorCodes.MerchantAccount.Individual.PhoneIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Individual.Address.StreetAddressIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Individual.Address.PostalCodeIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Individual.Address.RegionIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("ssn")[0].code, ErrorCodes.MerchantAccount.Individual.SsnIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("legal_name")[0].code, ErrorCodes.MerchantAccount.Business.LegalNameIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("dba_name")[0].code, ErrorCodes.MerchantAccount.Business.DbaNameIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("tax_id")[0].code, ErrorCodes.MerchantAccount.Business.TaxIdIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Business.Address.StreetAddressIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Business.Address.PostalCodeIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Business.Address.RegionIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("destination")[0].code, ErrorCodes.MerchantAccount.Funding.DestinationIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("routing_number")[0].code, ErrorCodes.MerchantAccount.Funding.RoutingNumberIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("account_number")[0].code, ErrorCodes.MerchantAccount.Funding.AccountNumberIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("email")[0].code, ErrorCodes.MerchantAccount.Funding.EmailAddressIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("mobile_phone")[0].code, ErrorCodes.MerchantAccount.Funding.MobilePhoneIsInvalid) self.assertEqual(0, len(result.errors.for_object("merchant_account").on("base"))) def test_update_handles_validation_errors_for_business_fields(self): result = MerchantAccount.update("sandbox_sub_merchant_account", { "business": { "legal_name": "", "tax_id": "111223333" } } ) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("legal_name")[0].code, ErrorCodes.MerchantAccount.Business.LegalNameIsRequiredWithTaxId) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("tax_id")[0].code, ErrorCodes.MerchantAccount.Business.TaxIdMustBeBlank) result = MerchantAccount.update("sandbox_sub_merchant_account", { "business": { "legal_name": "legal name", "tax_id": "" } } ) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("tax_id")[0].code, ErrorCodes.MerchantAccount.Business.TaxIdIsRequiredWithLegalName) def test_update_handles_validation_errors_for_funding_fields(self): result = MerchantAccount.update("sandbox_sub_merchant_account", { "funding": { "destination": MerchantAccount.FundingDestination.Bank, "routing_number": "", "account_number": "" } } ) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("routing_number")[0].code, ErrorCodes.MerchantAccount.Funding.RoutingNumberIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("account_number")[0].code, ErrorCodes.MerchantAccount.Funding.AccountNumberIsRequired) result = MerchantAccount.update("sandbox_sub_merchant_account", { "funding": { "destination": MerchantAccount.FundingDestination.Email, "email": "" } } ) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("email")[0].code, ErrorCodes.MerchantAccount.Funding.EmailAddressIsRequired) result = MerchantAccount.update("sandbox_sub_merchant_account", { "funding": { "destination": MerchantAccount.FundingDestination.MobilePhone, "mobile_phone": "" } } ) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("mobile_phone")[0].code, ErrorCodes.MerchantAccount.Funding.MobilePhoneIsRequired) def test_find(self): result = MerchantAccount.create(self.VALID_APPLICATION_PARAMS) self.assertTrue(result.is_success) merchant_account_id = result.merchant_account.id MerchantAccount.find(merchant_account_id) def test_retrieves_master_merchant_account_currency_iso_code(self): merchant_account = MerchantAccount.find("sandbox_master_merchant_account") self.assertEqual(merchant_account.currency_iso_code, "USD") def test_return_all_merchant_accounts(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) code = TestHelper.create_grant(gateway, { "merchant_public_id": "integration_merchant_id", "scope": "read_write" }) result = gateway.oauth.create_token_from_code({ "code": code }) gateway = BraintreeGateway( access_token=result.credentials.access_token, environment=Environment.Development ) result = gateway.merchant_account.all() merchant_accounts = [ma for ma in result.merchant_accounts.items] self.assertTrue(len(merchant_accounts) > 20) def test_returns_merchant_account_with_correct_attributes(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token ) result = gateway.merchant_account.all() merchant_accounts = [ma for ma in result.merchant_accounts.items] self.assertEqual(len(merchant_accounts), 1) merchant_account = merchant_accounts[0] self.assertEqual(merchant_account.currency_iso_code, "USD") self.assertEqual(merchant_account.status, MerchantAccount.Status.Active) self.assertTrue(merchant_account.default) @raises(NotFoundError) def test_find_404(self): MerchantAccount.find("not_a_real_id") def test_merchant_account_create_for_currency(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, ) result = gateway.merchant_account.create_for_currency({ "currency": "GBP", "id": "custom_id" }) self.assertTrue(result.is_success) self.assertEqual(result.merchant_account.currency_iso_code, "GBP") self.assertEqual(result.merchant_account.id, "custom_id") def test_merchant_account_create_for_currency_handles_invalid_currency(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, ) result = gateway.merchant_account.create_for_currency({ "currency": "DOES_NOT_COMPUTE" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant").on("currency")[0].code, ErrorCodes.Merchant.CurrencyIsInvalid) def test_merchant_account_create_for_currency_handles_currency_requirement(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, ) result = gateway.merchant_account.create_for_currency({}) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant").on("currency")[0].code, ErrorCodes.Merchant.CurrencyIsRequired) def test_merchant_account_create_for_currency_merchant_account_already_existing_for_currency(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, ) result = gateway.merchant_account.create_for_currency({ "currency": "USD", }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant").on("currency")[0].code, ErrorCodes.Merchant.MerchantAccountExistsForCurrency) def test_merchant_account_create_for_currency_merchant_account_already_existing_for_id(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, ) result = gateway.merchant_account.create_for_currency({ "currency": "GBP", "id": result.merchant.merchant_accounts[0].id }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant").on("id")[0].code, ErrorCodes.Merchant.MerchantAccountExistsForId) braintree_python-3.57.1/tests/integration/test_disbursement.py0000644000175000017500000000171313545202423023071 0ustar hlehlefrom tests.test_helper import * from datetime import date class TestDisbursement(unittest.TestCase): def test_disbursement_finds_transactions(self): disbursement = Disbursement(Configuration.gateway(), { "merchant_account": { "id": "sub_merchant_account", "status": "active", "master_merchant_account": { "id": "master_merchant_account", "status": "active" }, }, "id": "123456", "exception_message": "invalid_account_number", "amount": "100.00", "disbursement_date": date(2013, 4, 10), "follow_up_action": "update", "transaction_ids": ["sub_merchant_transaction"] }) transactions = disbursement.transactions() self.assertEqual(1, transactions.maximum_size) self.assertEqual("sub_merchant_transaction", transactions.first.id) braintree_python-3.57.1/tests/integration/test_payment_method.py0000644000175000017500000016672413545202423023420 0ustar hlehleimport time from datetime import datetime from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers from braintree.test.nonces import Nonces class TestPaymentMethod(unittest.TestCase): def test_create_with_three_d_secure_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.ThreeDSecureVisaFullAuthentication, "options": { "verify_card": "true", } }) self.assertTrue(result.is_success) three_d_secure_info = result.payment_method.verification.three_d_secure_info self.assertEqual("Y", three_d_secure_info.enrolled) self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertEqual("cavv_value", three_d_secure_info.cavv) self.assertEqual("xid_value", three_d_secure_info.xid) self.assertEqual(None, three_d_secure_info.ds_transaction_id) self.assertEqual("05", three_d_secure_info.eci_flag) self.assertEqual("1.0.2", three_d_secure_info.three_d_secure_version) def test_create_with_paypal_future_payments_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) created_account = result.payment_method self.assertEqual(PayPalAccount, created_account.__class__) self.assertEqual("jane.doe@example.com", created_account.email) self.assertNotEqual(created_account.image_url, None) found_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(created_account.token, found_account.token) self.assertEqual(created_account.customer_id, found_account.customer_id) def test_create_with_paypal_order_payment_nonce_and_paypal_options(self): customer_id = Customer.create().customer.id http = ClientApiHttp.create() status_code, payment_method_nonce = http.get_paypal_nonce({ "intent": "order", "payment-token": "fake-paypal-payment-token", "payer-id": "fake-paypal-payer-id" }) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": payment_method_nonce, "options": { "paypal": { "payee_email": "payee@example.com", "order_id": "merchant-order-id", "custom_field": "custom merchant field", "description": "merchant description", "amount": "1.23", "shipping": { "first_name": "Andrew", "last_name": "Mason", "company": "Braintree", "street_address": "456 W Main St", "extended_address": "Apt 2F", "locality": "Bartlett", "region": "IL", "postal_code": "60103", "country_name": "Mexico", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484" }, }, }, }) self.assertTrue(result.is_success) created_account = result.payment_method self.assertEqual(PayPalAccount, created_account.__class__) self.assertEqual("bt_buyer_us@paypal.com", created_account.email) self.assertNotEqual(created_account.image_url, None) self.assertNotEqual(created_account.payer_id, None) found_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(created_account.token, found_account.token) self.assertEqual(created_account.customer_id, found_account.customer_id) self.assertEqual(created_account.payer_id, found_account.payer_id) def test_create_with_paypal_refresh_token(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "paypal_refresh_token": "PAYPAL_REFRESH_TOKEN", }) self.assertTrue(result.is_success) created_account = result.payment_method self.assertEqual(PayPalAccount, created_account.__class__) self.assertEqual("B_FAKE_ID", created_account.billing_agreement_id) self.assertNotEqual(created_account.payer_id, None) found_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(created_account.token, found_account.token) self.assertEqual(created_account.customer_id, found_account.customer_id) self.assertEqual(created_account.billing_agreement_id, found_account.billing_agreement_id) self.assertEqual(created_account.payer_id, found_account.payer_id) def test_create_with_paypal_refresh_token_without_upgrade(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "paypal_refresh_token": "PAYPAL_REFRESH_TOKEN", "paypal_vault_without_upgrade": True, }) self.assertTrue(result.is_success) created_account = result.payment_method self.assertEqual(PayPalAccount, created_account.__class__) self.assertEqual(created_account.billing_agreement_id, None) found_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(created_account.token, found_account.token) self.assertEqual(created_account.customer_id, found_account.customer_id) self.assertEqual(created_account.billing_agreement_id, found_account.billing_agreement_id) def test_create_returns_validation_failures(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "options": {"validate": False} }) self.assertEqual(202, status_code) result = PaymentMethod.create({ "payment_method_nonce": nonce }) self.assertFalse(result.is_success) paypal_error_codes = [ error.code for error in result.errors.for_object("paypal_account").on("base") ] self.assertTrue(ErrorCodes.PayPalAccount.ConsentCodeOrAccessTokenIsRequired in paypal_error_codes) customer_error_codes = [ error.code for error in result.errors.for_object("paypal_account").on("customer_id") ] self.assertTrue(ErrorCodes.PayPalAccount.CustomerIdIsRequiredForVaulting in customer_error_codes) def test_create_and_make_default(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2014", }) self.assertTrue(credit_card_result.is_success) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment, "options": {"make_default": True}, }) self.assertTrue(result.is_success) self.assertTrue(result.payment_method.default) def test_create_and_set_token(self): customer_id = Customer.create().customer.id token = str(random.randint(1, 1000000)) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment, "token": token }) self.assertTrue(result.is_success) self.assertEqual(token, result.payment_method.token) def test_create_with_paypal_one_time_nonce_fails(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalOneTimePayment }) self.assertFalse(result.is_success) base_errors = result.errors.for_object("paypal_account").on("base") self.assertEqual(1, len(base_errors)) self.assertEqual(ErrorCodes.PayPalAccount.CannotVaultOneTimeUsePayPalAccount, base_errors[0].code) def test_create_with_credit_card_nonce(self): http = ClientApiHttp.create() status_code, nonce = http.get_credit_card_nonce({ "number": "4111111111111111", "expirationMonth": "12", "expirationYear": "2020", "options": {"validate": False} }) self.assertEqual(202, status_code) customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce }) self.assertTrue(result.is_success) created_credit_card = result.payment_method self.assertEqual(CreditCard, created_credit_card.__class__) self.assertEqual("411111", created_credit_card.bin) found_credit_card = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_credit_card) self.assertEqual(found_credit_card.token, created_credit_card.token) self.assertEqual(found_credit_card.customer_id, created_credit_card.customer_id) def test_create_with_fake_apple_pay_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.ApplePayMasterCard }) self.assertTrue(result.is_success) apple_pay_card = result.payment_method self.assertIsInstance(apple_pay_card, ApplePayCard) self.assertNotEqual(apple_pay_card.bin, None) self.assertNotEqual(apple_pay_card.token, None) self.assertEqual(apple_pay_card.customer_id, customer_id) self.assertEqual(ApplePayCard.CardType.MasterCard, apple_pay_card.card_type) self.assertEqual("MasterCard 0017", apple_pay_card.payment_instrument_name) self.assertEqual("MasterCard 0017", apple_pay_card.source_description) self.assertTrue(apple_pay_card.default) self.assertIn("apple_pay", apple_pay_card.image_url) self.assertTrue(int(apple_pay_card.expiration_month) > 0) self.assertTrue(int(apple_pay_card.expiration_year) > 0) def test_create_with_fake_android_pay_proxy_card_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.AndroidPayCardDiscover }) self.assertTrue(result.is_success) android_pay_card = result.payment_method self.assertIsInstance(android_pay_card, AndroidPayCard) self.assertNotEqual(android_pay_card.token, None) self.assertEqual(customer_id, android_pay_card.customer_id) self.assertEqual(CreditCard.CardType.Discover, android_pay_card.virtual_card_type) self.assertEqual("1117", android_pay_card.virtual_card_last_4) self.assertEqual("Discover 1111", android_pay_card.source_description) self.assertEqual(CreditCard.CardType.Discover, android_pay_card.source_card_type) self.assertEqual("1111", android_pay_card.source_card_last_4) self.assertEqual("1117", android_pay_card.last_4) self.assertEqual(CreditCard.CardType.Discover, android_pay_card.card_type) self.assertTrue(android_pay_card.default) self.assertIn("android_pay", android_pay_card.image_url) self.assertTrue(int(android_pay_card.expiration_month) > 0) self.assertTrue(int(android_pay_card.expiration_year) > 0) self.assertIsInstance(android_pay_card.created_at, datetime) self.assertIsInstance(android_pay_card.updated_at, datetime) self.assertEqual("601111", android_pay_card.bin) self.assertEqual("google_transaction_id", android_pay_card.google_transaction_id) def test_create_with_fake_android_pay_network_token_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.AndroidPayCardMasterCard }) self.assertTrue(result.is_success) android_pay_card = result.payment_method self.assertIsInstance(android_pay_card, AndroidPayCard) self.assertNotEqual(android_pay_card.token, None) self.assertEqual(customer_id, android_pay_card.customer_id) self.assertEqual(CreditCard.CardType.MasterCard, android_pay_card.virtual_card_type) self.assertEqual("4444", android_pay_card.virtual_card_last_4) self.assertEqual("MasterCard 4444", android_pay_card.source_description) self.assertEqual(CreditCard.CardType.MasterCard, android_pay_card.source_card_type) self.assertEqual("4444", android_pay_card.source_card_last_4) self.assertEqual("4444", android_pay_card.last_4) self.assertEqual(CreditCard.CardType.MasterCard, android_pay_card.card_type) self.assertTrue(android_pay_card.default) self.assertIn("android_pay", android_pay_card.image_url) self.assertTrue(int(android_pay_card.expiration_month) > 0) self.assertTrue(int(android_pay_card.expiration_year) > 0) self.assertIsInstance(android_pay_card.created_at, datetime) self.assertIsInstance(android_pay_card.updated_at, datetime) self.assertEqual("555555", android_pay_card.bin) self.assertEqual("google_transaction_id", android_pay_card.google_transaction_id) def test_create_with_fake_amex_express_checkout_card_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.AmexExpressCheckoutCard }) self.assertTrue(result.is_success) amex_express_checkout_card = result.payment_method self.assertIsInstance(amex_express_checkout_card, AmexExpressCheckoutCard) self.assertNotEqual(amex_express_checkout_card.token, None) self.assertTrue(amex_express_checkout_card.default) self.assertEqual("American Express", amex_express_checkout_card.card_type) self.assertRegexpMatches(amex_express_checkout_card.bin, r"\A\d{6}\Z") self.assertRegexpMatches(amex_express_checkout_card.expiration_month, r"\A\d{2}\Z") self.assertRegexpMatches(amex_express_checkout_card.expiration_year, r"\A\d{4}\Z") self.assertRegexpMatches(amex_express_checkout_card.card_member_number, r"\A\d{4}\Z") self.assertRegexpMatches(amex_express_checkout_card.card_member_expiry_date, r"\A\d{2}/\d{2}\Z") self.assertRegexpMatches(amex_express_checkout_card.source_description, r"\AAmEx \d{4}\Z") self.assertRegexpMatches(amex_express_checkout_card.image_url, r"\.png") self.assertEqual(customer_id, amex_express_checkout_card.customer_id) def test_create_with_venmo_account_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.VenmoAccount, }) self.assertTrue(result.is_success) venmo_account = result.payment_method self.assertIsInstance(venmo_account, VenmoAccount) self.assertTrue(venmo_account.default) self.assertIsNotNone(venmo_account.token) self.assertEqual("venmojoe", venmo_account.username) self.assertEqual("Venmo-Joe-1", venmo_account.venmo_user_id) self.assertEqual("Venmo Account: venmojoe", venmo_account.source_description) self.assertRegexpMatches(venmo_account.image_url, r"\.png") self.assertEqual(customer_id, venmo_account.customer_id) def test_create_with_abstract_payment_method_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.AbstractTransactable }) self.assertTrue(result.is_success) payment_method = result.payment_method self.assertNotEqual(None, payment_method) self.assertNotEqual(None, payment_method.token) self.assertEqual(customer_id, payment_method.customer_id) def test_create_with_custom_card_verification_amount(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id client_token = json.loads(TestHelper.generate_decoded_client_token()) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, nonce = http.get_credit_card_nonce({ "number": "4000111111111115", "expirationMonth": "11", "expirationYear": "2099" }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce, "options": { "verify_card": "true", "verification_amount": "1.02" } }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, verification.status) def test_create_respects_verify_card_and_verification_merchant_account_id_when_outside_nonce(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id client_token = json.loads(TestHelper.generate_decoded_client_token()) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, nonce = http.get_credit_card_nonce({ "number": "4000111111111115", "expirationMonth": "11", "expirationYear": "2099" }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "options": { "verify_card": "true", "verification_merchant_account_id": TestHelper.non_default_merchant_account_id } }) self.assertFalse(result.is_success) self.assertTrue(result.credit_card_verification.status == Transaction.Status.ProcessorDeclined) self.assertTrue(result.credit_card_verification.processor_response_code == "2000") self.assertTrue(result.credit_card_verification.processor_response_text == "Do Not Honor") self.assertTrue(result.credit_card_verification.merchant_account_id == TestHelper.non_default_merchant_account_id) def test_create_respects_fail_one_duplicate_payment_method_when_included_outside_of_the_nonce(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" }) self.assertTrue(credit_card_result.is_success) config = Configuration.instantiate() customer_id = Customer.create().customer.id client_token = json.loads(TestHelper.generate_decoded_client_token()) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, nonce = http.get_credit_card_nonce({ "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "options": { "fail_on_duplicate_payment_method": "true" } }) self.assertFalse(result.is_success) self.assertTrue(result.errors.deep_errors[0].code == "81724") def test_create_allows_passing_billing_address_id_outside_the_nonce(self): customer_id = Customer.create().customer.id http = ClientApiHttp.create() status_code, nonce = http.get_credit_card_nonce({ "number": "4111111111111111", "expirationMonth": "12", "expirationYear": "2020", "options": {"validate": "false"} }) self.assertTrue(status_code == 202) address_result = Address.create({ "customer_id": customer_id, "first_name": "Bobby", "last_name": "Tables" }) self.assertTrue(address_result.is_success) payment_method_result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "billing_address_id": address_result.address.id }) self.assertTrue(payment_method_result.is_success) self.assertTrue(isinstance(payment_method_result.payment_method, CreditCard)) token = payment_method_result.payment_method.token found_credit_card = CreditCard.find(token) self.assertFalse(found_credit_card is None) self.assertTrue(found_credit_card.billing_address.first_name == "Bobby") self.assertTrue(found_credit_card.billing_address.last_name == "Tables") def test_create_allows_passing_billing_address_outside_the_nonce(self): customer_id = Customer.create().customer.id http = ClientApiHttp.create() status_code, nonce = http.get_credit_card_nonce({ "number": "4111111111111111", "expirationMonth": "12", "expirationYear": "2020", "options": {"validate": "false"} }) self.assertTrue(status_code == 202) result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "billing_address": { "street_address": "123 Abc Way" } }) self.assertTrue(result.is_success) self.assertTrue(isinstance(result.payment_method, CreditCard)) token = result.payment_method.token found_credit_card = CreditCard.find(token) self.assertFalse(found_credit_card is None) self.assertTrue(found_credit_card.billing_address.street_address == "123 Abc Way") def test_create_overrides_the_billing_address_in_the_nonce(self): customer_id = Customer.create().customer.id http = ClientApiHttp.create() status_code, nonce = http.get_credit_card_nonce({ "number": "4111111111111111", "expirationMonth": "12", "expirationYear": "2020", "options": {"validate": "false"}, "billing_address": { "street_address": "456 Xyz Way" } }) self.assertTrue(status_code == 202) result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "billing_address": { "street_address": "123 Abc Way" } }) self.assertTrue(result.is_success) self.assertTrue(isinstance(result.payment_method, CreditCard)) token = result.payment_method.token found_credit_card = CreditCard.find(token) self.assertFalse(found_credit_card is None) self.assertTrue(found_credit_card.billing_address.street_address == "123 Abc Way") def test_create_does_not_override_the_billing_address_for_a_valuted_credit_card(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id client_token = json.loads(TestHelper.generate_decoded_client_token({"customer_id": customer_id})) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp(config, {"authorization_fingerprint": authorization_fingerprint}) status_code, nonce = http.get_credit_card_nonce({ "number": "4111111111111111", "expirationMonth": "12", "expirationYear": "2020", "billing_address": { "street_address": "456 Xyz Way" } }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "billing_address": { "street_address": "123 Abc Way" } }) self.assertTrue(result.is_success) self.assertTrue(isinstance(result.payment_method, CreditCard)) token = result.payment_method.token found_credit_card = CreditCard.find(token) self.assertFalse(found_credit_card is None) self.assertTrue(found_credit_card.billing_address.street_address == "456 Xyz Way") def test_create_does_not_return_an_error_if_credit_card_options_are_present_for_paypal_nonce(self): customer_id = Customer.create().customer.id original_token = "paypal-account-" + str(int(time.time())) nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code", "token": original_token }) result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "options": { "verify_card": "true", "fail_on_duplicate_payment_method": "true", "verification_merchant_account_id": "not_a_real_merchant_account_id" } }) self.assertTrue(result.is_success) def test_create_for_paypal_ignores_passed_billing_address_id(self): nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code" }) customer_id = Customer.create().customer.id result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "billing_address_id": "address_id" }) self.assertTrue(result.is_success) self.assertTrue(isinstance(result.payment_method, PayPalAccount)) self.assertFalse(result.payment_method.image_url is None) token = result.payment_method.token found_paypal_account = PayPalAccount.find(token) self.assertFalse(found_paypal_account is None) def test_create_for_paypal_ignores_passed_billing_address_params(self): nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "PAYPAL_CONSENT_CODE" }) customer_id = Customer.create().customer.id result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "billing_address": { "street_address": "123 Abc Way" } }) self.assertTrue(result.is_success) self.assertTrue(isinstance(result.payment_method, PayPalAccount)) self.assertFalse(result.payment_method.image_url is None) token = result.payment_method.token found_paypal_account = PayPalAccount.find(token) self.assertFalse(found_paypal_account is None) def test_create_payment_method_with_account_type_debit(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id client_token = json.loads(TestHelper.generate_decoded_client_token()) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing", }) status_code, nonce = http.get_credit_card_nonce({ "number": CreditCardNumbers.Hiper, "expirationMonth": "11", "expirationYear": "2099", }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce, "options": { "verify_card": "true", "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_amount": "1.02", "verification_account_type": "debit", }, }) self.assertTrue(result.is_success) self.assertEqual("debit", result.payment_method.verifications[0]["credit_card"]["account_type"]) def test_create_payment_method_with_account_type_credit(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id client_token = json.loads(TestHelper.generate_decoded_client_token()) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing", }) status_code, nonce = http.get_credit_card_nonce({ "number": CreditCardNumbers.Hiper, "expirationMonth": "11", "expirationYear": "2099", }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce, "options": { "verify_card": "true", "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_amount": "1.02", "verification_account_type": "credit", }, }) self.assertTrue(result.is_success) self.assertEqual("credit", result.payment_method.verifications[0]["credit_card"]["account_type"]) def test_create_credit_card_with_account_type_debit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", "options": { "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_account_type": "debit", "verify_card": True, } }) self.assertTrue(result.is_success) self.assertEqual("debit", result.credit_card.verifications[0]["credit_card"]["account_type"]) def test_create_credit_card_with_account_type_credit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", "options": { "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_account_type": "credit", "verify_card": True, } }) self.assertTrue(result.is_success) self.assertEqual("credit", result.credit_card.verifications[0]["credit_card"]["account_type"]) def test_create_with_usupported_merchant_account(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", "options": { "verification_account_type": "debit", "verify_card": True, } }) self.assertFalse(result.is_success) errors = result.errors.for_object("credit_card").for_object("options").on("verification_account_type") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.CreditCard.VerificationAccountTypeNotSupported, errors[0].code) def test_create_with_invalid_account_type(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", "options": { "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_account_type": "invalid", "verify_card": True, } }) self.assertFalse(result.is_success) errors = result.errors.for_object("credit_card").for_object("options").on("verification_account_type") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.CreditCard.VerificationAccountTypeIsInvald, errors[0].code) def test_find_returns_an_abstract_payment_method(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.AbstractTransactable }) self.assertTrue(result.is_success) found_payment_method = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_payment_method) self.assertEqual(found_payment_method.token, result.payment_method.token) def test_find_returns_a_paypal_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) found_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(PayPalAccount, found_account.__class__) self.assertEqual("jane.doe@example.com", found_account.email) def test_find_returns_a_credit_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe" }) self.assertTrue(result.is_success) found_credit_card = PaymentMethod.find(result.credit_card.token) self.assertNotEqual(None, found_credit_card) self.assertEqual(CreditCard, found_credit_card.__class__) self.assertEqual("411111", found_credit_card.bin) def test_find_returns_an_android_pay_card(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.AndroidPayCard }) self.assertTrue(result.is_success) android_pay_card = result.payment_method found_android_pay_card = PaymentMethod.find(android_pay_card.token) self.assertNotEqual(None, found_android_pay_card) self.assertEqual(AndroidPayCard, found_android_pay_card.__class__) self.assertEqual(found_android_pay_card.token, android_pay_card.token) def test_delete_deletes_a_credit_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe" }) self.assertTrue(result.is_success) delete_result = PaymentMethod.delete(result.credit_card.token) self.assertTrue(delete_result.is_success) self.assertRaises(NotFoundError, PaymentMethod.find, result.credit_card.token) def test_delete_deletes_a_paypal_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) delete_result = PaymentMethod.delete(result.payment_method.token, {"revoke_all_grants": False}) self.assertTrue(delete_result.is_success) self.assertRaises(NotFoundError, PaymentMethod.find, result.payment_method.token) def test_update_credit_cards_updates_the_credit_card(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Original Holder", "customer_id": customer_id, "cvv": "123", "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.MasterCard, "expiration_date": "06/2013" }) self.assertTrue(update_result.is_success) self.assertTrue(update_result.payment_method.token == credit_card_result.credit_card.token) updated_credit_card = update_result.payment_method self.assertTrue(updated_credit_card.bin == CreditCardNumbers.MasterCard[:6]) self.assertTrue(updated_credit_card.last_4 == CreditCardNumbers.MasterCard[-4:]) self.assertTrue(updated_credit_card.expiration_date == "06/2013") def test_update_credit_cards_with_account_type_credit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", }) update_result = PaymentMethod.update(result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.Hiper, "expiration_date": "06/2013", "options": { "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_account_type": "credit", "verify_card": True, } }) self.assertTrue(update_result.is_success) self.assertEqual("credit", update_result.payment_method.verification.credit_card["account_type"]) def test_update_credit_cards_with_account_type_debit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", }) update_result = PaymentMethod.update(result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.Hiper, "expiration_date": "06/2013", "options": { "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_account_type": "debit", "verify_card": True, } }) self.assertTrue(update_result.is_success) self.assertEqual("debit", update_result.payment_method.verification.credit_card["account_type"]) def test_update_credit_cards_with_invalid_account_type(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", }) update_result = PaymentMethod.update(result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.Hiper, "expiration_date": "06/2013", "options": { "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_account_type": "invalid", "verify_card": True, } }) self.assertFalse(update_result.is_success) errors = update_result.errors.for_object("credit_card").for_object("options").on("verification_account_type") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.CreditCard.VerificationAccountTypeIsInvald, errors[0].code) def test_update_credit_cards_with_unsupported_merchant_account(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", }) update_result = PaymentMethod.update(result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.Visa, "expiration_date": "06/2013", "options": { "verification_account_type": "debit", "verify_card": True, } }) self.assertFalse(update_result.is_success) errors = update_result.errors.for_object("credit_card").for_object("options").on("verification_account_type") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.CreditCard.VerificationAccountTypeNotSupported, errors[0].code) def test_update_creates_a_new_billing_address_by_default(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012", "billing_address": { "street_address": "123 Nigeria Ave" } }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "billing_address": { "region": "IL" } }) self.assertTrue(update_result.is_success) updated_credit_card = update_result.payment_method self.assertTrue(updated_credit_card.billing_address.region == "IL") self.assertTrue(updated_credit_card.billing_address.street_address is None) self.assertFalse(updated_credit_card.billing_address.id == credit_card_result.credit_card.billing_address.id) def test_update_updates_the_billing_address_if_option_is_specified(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012", "billing_address": { "street_address": "123 Nigeria Ave" } }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "billing_address": { "region": "IL", "options": { "update_existing": "true" } } }) self.assertTrue(update_result.is_success) updated_credit_card = update_result.payment_method self.assertTrue(updated_credit_card.billing_address.region == "IL") self.assertTrue(updated_credit_card.billing_address.street_address == "123 Nigeria Ave") self.assertTrue(updated_credit_card.billing_address.id == credit_card_result.credit_card.billing_address.id) def test_update_updates_the_country_via_codes(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012", "billing_address": { "street_address": "123 Nigeria Ave" } }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "billing_address": { "country_name": "American Samoa", "country_code_alpha2": "AS", "country_code_alpha3": "ASM", "country_code_numeric": "016", "options": { "update_existing": "true" } } }) self.assertTrue(update_result.is_success) updated_credit_card = update_result.payment_method self.assertTrue(updated_credit_card.billing_address.country_name == "American Samoa") self.assertTrue(updated_credit_card.billing_address.country_code_alpha2 == "AS") self.assertTrue(updated_credit_card.billing_address.country_code_alpha3 == "ASM") self.assertTrue(updated_credit_card.billing_address.country_code_numeric == "016") def test_update_can_pass_expiration_month_and_expiration_year(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "number": CreditCardNumbers.MasterCard, "expiration_month": "07", "expiration_year": "2011" }) self.assertTrue(update_result.is_success) self.assertTrue(update_result.payment_method.token == credit_card_result.credit_card.token) updated_credit_card = update_result.payment_method self.assertTrue(updated_credit_card.expiration_month == "07") self.assertTrue(updated_credit_card.expiration_year == "2011") self.assertTrue(updated_credit_card.expiration_date == "07/2011") def test_update_verifies_the_update_if_options_verify_card_is_true(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Original Holder", "customer_id": customer_id, "cvv": "123", "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.FailsSandboxVerification.MasterCard, "expiration_date": "06/2013", "options": { "verify_card": "true" } }) self.assertFalse(update_result.is_success) self.assertTrue(update_result.credit_card_verification.status == CreditCardVerification.Status.ProcessorDeclined) self.assertTrue(update_result.credit_card_verification.gateway_rejection_reason is None) def test_update_can_pass_custom_verification_amount(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Card Holder", "customer_id": customer_id, "cvv": "123", "number": CreditCardNumbers.Visa, "expiration_date": "05/2020" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "payment_method_nonce": Nonces.ProcessorDeclinedMasterCard, "options": { "verify_card": "true", "verification_amount": "2.34" } }) self.assertFalse(update_result.is_success) self.assertTrue(update_result.credit_card_verification.status == CreditCardVerification.Status.ProcessorDeclined) self.assertTrue(update_result.credit_card_verification.gateway_rejection_reason is None) def test_update_can_update_the_billing_address(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Original Holder", "customer_id": customer_id, "cvv": "123", "number": CreditCardNumbers.Visa, "expiration_date": "05/2012", "billing_address": { "first_name": "Old First Name", "last_name": "Old Last Name", "company": "Old Company", "street_address": "123 Old St", "extended_address": "Apt Old", "locality": "Old City", "region": "Old State", "postal_code": "12345", "country_name": "Canada" } }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "options": {"verify_card": "false"}, "billing_address": { "first_name": "New First Name", "last_name": "New Last Name", "company": "New Company", "street_address": "123 New St", "extended_address": "Apt New", "locality": "New City", "region": "New State", "postal_code": "56789", "country_name": "United States of America" } }) self.assertTrue(update_result.is_success) address = update_result.payment_method.billing_address self.assertTrue(address.first_name == "New First Name") self.assertTrue(address.last_name == "New Last Name") self.assertTrue(address.company == "New Company") self.assertTrue(address.street_address == "123 New St") self.assertTrue(address.extended_address == "Apt New") self.assertTrue(address.locality == "New City") self.assertTrue(address.region == "New State") self.assertTrue(address.postal_code == "56789") self.assertTrue(address.country_name == "United States of America") def test_update_returns_an_error_response_if_invalid(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Original Holder", "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "cardholder_name": "New Holder", "number": "invalid", "expiration_date": "05/2014", }) self.assertFalse(update_result.is_success) number_errors = update_result.errors.for_object("credit_card").on("number") self.assertEqual(1, len(number_errors)) self.assertEqual("Credit card number must be 12-19 digits.", number_errors[0].message) def test_update_can_update_the_default(self): customer_id = Customer.create().customer.id card1 = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }).credit_card card2 = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }).credit_card self.assertTrue(card1.default) self.assertFalse(card2.default) PaymentMethod.update(card2.token, { "options": {"make_default": True} }) self.assertFalse(CreditCard.find(card1.token).default) self.assertTrue(CreditCard.find(card2.token).default) def test_update_updates_a_paypal_accounts_token(self): customer_id = Customer.create().customer.id original_token = "paypal-account-" + str(int(time.time())) nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code", "token": original_token }) original_result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id }) updated_token = "UPDATED_TOKEN-" + str(random.randint(0, 100000000)) PaymentMethod.update( original_token, {"token": updated_token} ) updated_paypal_account = PayPalAccount.find(updated_token) self.assertTrue(updated_paypal_account.email == original_result.payment_method.email) self.assertRaises(NotFoundError, PaymentMethod.find, original_token) def test_update_can_make_a_paypal_account_the_default_payment_method(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "options": {"make_default": "true"} }) self.assertTrue(credit_card_result.is_success) nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code" }) original_token = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id }).payment_method.token PaymentMethod.update( original_token, {"options": {"make_default": "true"}} ) updated_paypal_account = PayPalAccount.find(original_token) self.assertTrue(updated_paypal_account.default) def test_update_fails_to_updates_a_paypal_accounts_token_with(self): customer_id = Customer.create().customer.id first_token = "paypal-account-" + str(random.randint(0, 100000000)) second_token = "paypal-account-" + str(random.randint(0, 100000000)) first_nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code", "token": first_token }) PaymentMethod.create({ "payment_method_nonce": first_nonce, "customer_id": customer_id }) second_nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code", "token": second_token }) PaymentMethod.create({ "payment_method_nonce": second_nonce, "customer_id": customer_id }) updated_result = PaymentMethod.update( first_token, {"token": second_token} ) self.assertFalse(updated_result.is_success) errors = updated_result.errors.deep_errors self.assertEqual(1, len(errors)) self.assertEqual("92906", errors[0].code) def test_payment_method_grant_raises_on_non_existent_tokens(self): granting_gateway, _ = TestHelper.create_payment_method_grant_fixtures() self.assertRaises(NotFoundError, granting_gateway.payment_method.grant, "non-existant-token", False) def test_payment_method_grant_returns_one_time_nonce(self): """ Payment method grant returns a nonce that is transactable by a partner merchant exactly once """ granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, { "allow_vaulting": False }); self.assertTrue(grant_result.is_success) result = Transaction.sale({ "payment_method_nonce": grant_result.payment_method_nonce.nonce, "amount": TransactionAmounts.Authorize }) self.assertTrue(result.is_success) result = Transaction.sale({ "payment_method_nonce": grant_result.payment_method_nonce.nonce, "amount": TransactionAmounts.Authorize }) self.assertFalse(result.is_success) def test_payment_method_grant_returns_a_nonce_that_is_not_vaultable(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, False) customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": grant_result.payment_method_nonce.nonce }) self.assertFalse(result.is_success) def test_payment_method_grant_returns_a_nonce_that_is_vaultable(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, { "allow_vaulting": True }) customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": grant_result.payment_method_nonce.nonce }) self.assertTrue(result.is_success) def test_payment_method_revoke_renders_a_granted_nonce_unusable(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token) revoke_result = granting_gateway.payment_method.revoke(credit_card.token) self.assertTrue(revoke_result.is_success) result = Transaction.sale({ "payment_method_nonce": grant_result.payment_method_nonce.nonce, "amount": TransactionAmounts.Authorize }) self.assertFalse(result.is_success) def test_payment_method_revoke_raises_on_non_existent_tokens(self): granting_gateway, _ = TestHelper.create_payment_method_grant_fixtures() self.assertRaises(NotFoundError, granting_gateway.payment_method.revoke, "non-existant-token") class CreditCardForwardingTest(unittest.TestCase): def setUp(self): braintree.Configuration.configure( braintree.Environment.Development, "forward_payment_method_merchant_id", "forward_payment_method_public_key", "forward_payment_method_private_key" ) def tearDown(self): braintree.Configuration.configure( braintree.Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) def test_forward_raises_exception(self): customer = Customer.create().customer credit_card_result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2025" }) self.assertTrue(credit_card_result.is_success) source_merchant_card = credit_card_result.credit_card self.assertRaises(NotFoundError, CreditCard.forward, source_merchant_card.token, "integration_merchant_id") def test_forward_invalid_token_raises_exception(self): self.assertRaises(NotFoundError, CreditCard.forward, "invalid", "integration_merchant_id") def test_forward_invalid_receiving_merchant_raises_exception(self): customer = Customer.create().customer credit_card_result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2025" }) self.assertTrue(credit_card_result.is_success) source_merchant_card = credit_card_result.credit_card self.assertRaises(NotFoundError, CreditCard.forward, source_merchant_card.token, "invalid_merchant_id") braintree_python-3.57.1/tests/integration/test_subscription.py0000644000175000017500000016712313545202423023121 0ustar hlehlefrom tests.test_helper import * from braintree.test.nonces import Nonces from datetime import date, timedelta class TestSubscription(unittest.TestCase): def setUp(self): self.credit_card = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }).customer.credit_cards[0] self.updateable_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "price": Decimal("54.32"), "plan_id": TestHelper.trialless_plan["id"] }).subscription def test_create_returns_successful_result_if_valid(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }) self.assertTrue(result.is_success) subscription = result.subscription self.assertNotEqual(None, re.search(r"\A\w{6}\Z", subscription.id)) self.assertEqual(Decimal("12.34"), subscription.price) self.assertEqual(Decimal("12.34"), subscription.next_bill_amount) self.assertEqual(Decimal("12.34"), subscription.next_billing_period_amount) self.assertEqual(Subscription.Status.Active, subscription.status) self.assertEqual("integration_trialless_plan", subscription.plan_id) self.assertEqual(TestHelper.default_merchant_account_id, subscription.merchant_account_id) self.assertEqual(Decimal("0.00"), subscription.balance) self.assertEqual(date, type(subscription.first_billing_date)) self.assertEqual(date, type(subscription.next_billing_date)) self.assertEqual(date, type(subscription.billing_period_start_date)) self.assertEqual(date, type(subscription.billing_period_end_date)) self.assertEqual(date, type(subscription.paid_through_date)) self.assertEqual(datetime, type(subscription.created_at)) self.assertEqual(datetime, type(subscription.updated_at)) self.assertEqual(1, subscription.current_billing_cycle) self.assertEqual(0, subscription.failure_count) self.assertEqual(self.credit_card.token, subscription.payment_method_token) self.assertEqual(Subscription.Status.Active, subscription.status_history[0].status) self.assertEqual(Decimal("12.34"), subscription.status_history[0].price) self.assertEqual(Decimal("0.00"), subscription.status_history[0].balance) self.assertEqual(Subscription.Source.Api, subscription.status_history[0].subscription_source) self.assertEqual("USD", subscription.status_history[0].currency_iso_code) self.assertEqual(TestHelper.trialless_plan["id"], subscription.status_history[0].plan_id) def test_create_returns_successful_result_with_payment_method_nonce(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id parsed_client_token = TestHelper.generate_decoded_client_token({"customer_id": customer_id}) authorization_fingerprint = json.loads(parsed_client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) _, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) nonce = json.loads(response)["creditCards"][0]["nonce"] result = Subscription.create({ "payment_method_nonce": nonce, "plan_id": TestHelper.trialless_plan["id"] }) self.assertTrue(result.is_success) transaction = result.subscription.transactions[0] self.assertEqual("411111", transaction.credit_card_details.bin) def test_create_can_set_the_id(self): new_id = str(random.randint(1, 1000000)) result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "id": new_id }) self.assertTrue(result.is_success) self.assertEqual(new_id, result.subscription.id) def test_create_can_set_the_merchant_account_id(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "merchant_account_id": TestHelper.non_default_merchant_account_id }) self.assertTrue(result.is_success) self.assertEqual(TestHelper.non_default_merchant_account_id, result.subscription.merchant_account_id) def test_create_defaults_to_plan_without_trial(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription self.assertEqual(TestHelper.trialless_plan["trial_period"], subscription.trial_period) self.assertEqual(None, subscription.trial_duration) self.assertEqual(None, subscription.trial_duration_unit) def test_create_defaults_to_plan_with_trial(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], }).subscription self.assertEqual(TestHelper.trial_plan["trial_period"], subscription.trial_period) self.assertEqual(TestHelper.trial_plan["trial_duration"], subscription.trial_duration) self.assertEqual(TestHelper.trial_plan["trial_duration_unit"], subscription.trial_duration_unit) def test_create_and_override_plan_with_trial(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "trial_duration": 5, "trial_duration_unit": Subscription.TrialDurationUnit.Month }).subscription self.assertEqual(True, subscription.trial_period) self.assertEqual(5, subscription.trial_duration) self.assertEqual(Subscription.TrialDurationUnit.Month, subscription.trial_duration_unit) def test_create_and_override_trial_period(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "trial_period": False }).subscription self.assertEqual(False, subscription.trial_period) def test_create_and_override_number_of_billing_cycles(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "number_of_billing_cycles": 10 }).subscription self.assertEqual(10, subscription.number_of_billing_cycles) def test_create_and_override_number_of_billing_cycles_to_never_expire(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "never_expires": True }).subscription self.assertEqual(None, subscription.number_of_billing_cycles) def test_create_creates_a_transaction_if_no_trial_period(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription self.assertEqual(1, len(subscription.transactions)) transaction = subscription.transactions[0] self.assertEqual(Transaction, type(transaction)) self.assertEqual(TestHelper.trialless_plan["price"], transaction.amount) self.assertEqual("sale", transaction.type) self.assertEqual(subscription.id, transaction.subscription_id) def test_create_has_transaction_with_billing_period_dates(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription transaction = subscription.transactions[0] self.assertEqual(subscription.billing_period_start_date, transaction.subscription_details.billing_period_start_date) self.assertEqual(subscription.billing_period_end_date, transaction.subscription_details.billing_period_end_date) def test_create_returns_a_transaction_if_transaction_is_declined(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": TransactionAmounts.Decline }) self.assertFalse(result.is_success) self.assertEqual(Transaction.Status.ProcessorDeclined, result.transaction.status) def test_create_doesnt_creates_a_transaction_if_trial_period(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], }).subscription self.assertEqual(0, len(subscription.transactions)) def test_create_with_error_result(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "id": "invalid token" }) self.assertFalse(result.is_success) id_errors = result.errors.for_object("subscription").on("id") self.assertEqual(1, len(id_errors)) self.assertEqual("81906", id_errors[0].code) def test_create_inherits_billing_day_of_month_from_plan(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.billing_day_of_month_plan["id"], }) self.assertTrue(result.is_success) self.assertEqual(5, result.subscription.billing_day_of_month) def test_create_allows_overriding_billing_day_of_month(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.billing_day_of_month_plan["id"], "billing_day_of_month": 19 }) self.assertTrue(result.is_success) self.assertEqual(19, result.subscription.billing_day_of_month) def test_create_allows_overriding_billing_day_of_month_with_start_immediately(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.billing_day_of_month_plan["id"], "options": { "start_immediately": True } }) self.assertTrue(result.is_success) self.assertEqual(1, len(result.subscription.transactions)) def test_create_allows_specifying_first_billing_date(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.billing_day_of_month_plan["id"], "first_billing_date": date.today() + timedelta(days=3) }) self.assertTrue(result.is_success) self.assertEqual(date.today() + timedelta(days=3), result.subscription.first_billing_date) self.assertEqual(Subscription.Status.Pending, result.subscription.status) def test_create_does_not_allow_first_billing_date_in_the_past(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.billing_day_of_month_plan["id"], "first_billing_date": date.today() - timedelta(days=3) }) self.assertFalse(result.is_success) billing_date_errors = result.errors.for_object("subscription").on("first_billing_date") self.assertEqual(1, len(billing_date_errors)) self.assertEqual(ErrorCodes.Subscription.FirstBillingDateCannotBeInThePast, billing_date_errors[0].code) def test_create_does_not_inherit_add_ons_or_discounts_from_the_plan_when_flag_is_set(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "options": { "do_not_inherit_add_ons_or_discounts": True } }).subscription self.assertEqual(0, len(subscription.add_ons)) self.assertEqual(0, len(subscription.discounts)) def test_create_inherits_add_ons_and_discounts_from_the_plan_when_not_specified(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"] }).subscription self.assertEqual(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEqual("increase_10", add_ons[0].id) self.assertEqual(Decimal("10.00"), add_ons[0].amount) self.assertEqual(1, add_ons[0].quantity) self.assertEqual(None, add_ons[0].number_of_billing_cycles) self.assertTrue(add_ons[0].never_expires) self.assertEqual(0, add_ons[0].current_billing_cycle) self.assertEqual("increase_20", add_ons[1].id) self.assertEqual(Decimal("20.00"), add_ons[1].amount) self.assertEqual(1, add_ons[1].quantity) self.assertEqual(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEqual(0, add_ons[1].current_billing_cycle) self.assertEqual(2, len(subscription.discounts)) discounts = sorted(subscription.discounts, key=lambda discount: discount.id) self.assertEqual("discount_11", discounts[0].id) self.assertEqual(Decimal("11.00"), discounts[0].amount) self.assertEqual(1, discounts[0].quantity) self.assertEqual(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) self.assertEqual(0, discounts[0].current_billing_cycle) self.assertEqual("discount_7", discounts[1].id) self.assertEqual(Decimal("7.00"), discounts[1].amount) self.assertEqual(1, discounts[1].quantity) self.assertEqual(None, discounts[1].number_of_billing_cycles) self.assertTrue(discounts[1].never_expires) self.assertEqual(0, discounts[1].current_billing_cycle) def test_create_allows_overriding_of_inherited_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "update": [ { "amount": Decimal("50.00"), "existing_id": "increase_10", "quantity": 2, "number_of_billing_cycles": 5 }, { "amount": Decimal("100.00"), "existing_id": "increase_20", "quantity": 4, "never_expires": True } ] }, "discounts": { "update": [ { "amount": Decimal("15.00"), "existing_id": "discount_7", "quantity": 3, "number_of_billing_cycles": 19 } ] } }).subscription self.assertEqual(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEqual("increase_10", add_ons[0].id) self.assertEqual(Decimal("50.00"), add_ons[0].amount) self.assertEqual(2, add_ons[0].quantity) self.assertEqual(5, add_ons[0].number_of_billing_cycles) self.assertFalse(add_ons[0].never_expires) self.assertEqual(0, add_ons[0].current_billing_cycle) self.assertEqual("increase_20", add_ons[1].id) self.assertEqual(Decimal("100.00"), add_ons[1].amount) self.assertEqual(4, add_ons[1].quantity) self.assertEqual(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEqual(0, add_ons[1].current_billing_cycle) self.assertEqual(2, len(subscription.discounts)) discounts = sorted(subscription.discounts, key=lambda discount: discount.id) self.assertEqual("discount_11", discounts[0].id) self.assertEqual(Decimal("11.00"), discounts[0].amount) self.assertEqual(1, discounts[0].quantity) self.assertEqual(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) self.assertEqual(0, discounts[0].current_billing_cycle) self.assertEqual("discount_7", discounts[1].id) self.assertEqual(Decimal("15.00"), discounts[1].amount) self.assertEqual(3, discounts[1].quantity) self.assertEqual(19, discounts[1].number_of_billing_cycles) self.assertFalse(discounts[1].never_expires) self.assertEqual(0, discounts[1].current_billing_cycle) def test_create_allows_deleting_of_inherited_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "remove": ["increase_10", "increase_20"] }, "discounts": { "remove": ["discount_7"] } }).subscription self.assertEqual(0, len(subscription.add_ons)) self.assertEqual(1, len(subscription.discounts)) self.assertEqual("discount_11", subscription.discounts[0].id) def test_create_allows_adding_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "add": [ { "amount": Decimal("50.00"), "inherited_from_id": "increase_30", "quantity": 2, "number_of_billing_cycles": 5 } ], "remove": ["increase_10", "increase_20"] }, "discounts": { "add": [ { "amount": Decimal("17.00"), "inherited_from_id": "discount_15", "never_expires": True } ], "remove": ["discount_7", "discount_11"] } }).subscription self.assertEqual(1, len(subscription.add_ons)) self.assertEqual("increase_30", subscription.add_ons[0].id) self.assertEqual(Decimal("50.00"), subscription.add_ons[0].amount) self.assertEqual(2, subscription.add_ons[0].quantity) self.assertEqual(5, subscription.add_ons[0].number_of_billing_cycles) self.assertFalse(subscription.add_ons[0].never_expires) self.assertEqual(0, subscription.add_ons[0].current_billing_cycle) self.assertEqual(1, len(subscription.discounts)) self.assertEqual("discount_15", subscription.discounts[0].id) self.assertEqual(Decimal("17.00"), subscription.discounts[0].amount) self.assertEqual(1, subscription.discounts[0].quantity) self.assertEqual(None, subscription.discounts[0].number_of_billing_cycles) self.assertTrue(subscription.discounts[0].never_expires) self.assertEqual(0, subscription.discounts[0].current_billing_cycle) def test_create_properly_parses_validation_errors_for_arrays(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "update": [ { "existing_id": "increase_10", "amount": "invalid" }, { "existing_id": "increase_20", "quantity": -2 } ] } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Subscription.Modification.AmountIsInvalid, result.errors.for_object("subscription").for_object("add_ons").for_object("update").for_index(0).on("amount")[0].code ) self.assertEqual( ErrorCodes.Subscription.Modification.QuantityIsInvalid, result.errors.for_object("subscription").for_object("add_ons").for_object("update").for_index(1).on("quantity")[0].code ) def test_descriptors_accepts_name_phone_and_url(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" } }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual("123*123456789012345678", subscription.descriptor.name) self.assertEqual("3334445555", subscription.descriptor.phone) transaction = subscription.transactions[0] self.assertEqual("123*123456789012345678", transaction.descriptor.name) self.assertEqual("3334445555", transaction.descriptor.phone) self.assertEqual("ebay.com", transaction.descriptor.url) def test_descriptors_has_validation_errors_if_format_is_invalid(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "descriptor": { "name": "badcompanyname12*badproduct12", "phone": "%bad4445555" } }) self.assertFalse(result.is_success) name_errors = result.errors.for_object("transaction").for_object("descriptor").on("name") self.assertEqual(1, len(name_errors)) self.assertEqual(ErrorCodes.Descriptor.NameFormatIsInvalid, name_errors[0].code) phone_errors = result.errors.for_object("transaction").for_object("descriptor").on("phone") self.assertEqual(1, len(phone_errors)) self.assertEqual(ErrorCodes.Descriptor.PhoneFormatIsInvalid, phone_errors[0].code) def test_description(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "options": {"validate": False} }) self.assertEqual(202, status_code) payment_method_token = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": nonce }).payment_method.token result = Subscription.create({ "payment_method_token": payment_method_token, "plan_id": TestHelper.trialless_plan["id"], "options": { "paypal": { "description": "A great product" } } }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual("A great product", subscription.description) transaction = subscription.transactions[0] paypal_details = transaction.paypal_details self.assertEqual("A great product", paypal_details.description) def test_find_with_valid_id(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], }).subscription found_subscription = Subscription.find(subscription.id) self.assertEqual(subscription.id, found_subscription.id) @raises_with_regexp(NotFoundError, "subscription with id 'bad_token' not found") def test_find_with_invalid_token(self): Subscription.find("bad_token") def test_update_creates_a_prorated_transaction_when_merchant_is_set_to_prorate(self): result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("1"), }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(2, len(subscription.transactions)) def test_update_creates_a_prorated_transaction_when_flag_is_passed_as_True(self): result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("1"), "options": { "prorate_charges": True } }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(2, len(subscription.transactions)) def test_update_does_not_create_a_prorated_transaction_when_flag_is_passed_as_False(self): result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("1"), "options": { "prorate_charges": False } }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(1, len(subscription.transactions)) def test_update_does_not_update_subscription_when_revert_subscription_on_proration_failure_is_true(self): result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("2100"), "options": { "prorate_charges": True, "revert_subscription_on_proration_failure": True } }) self.assertFalse(result.is_success) found_subscription = Subscription.find(result.subscription.id) self.assertEqual(len(self.updateable_subscription.transactions) + 1, len(result.subscription.transactions)) self.assertEqual("processor_declined", result.subscription.transactions[0].status) self.assertEqual(Decimal("0.00"), found_subscription.balance) self.assertEqual(self.updateable_subscription.price, found_subscription.price) def test_update_updates_subscription_when_revert_subscription_on_proration_failure_is_false(self): result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("2100"), "options": { "prorate_charges": True, "revert_subscription_on_proration_failure": False } }) self.assertTrue(result.is_success) found_subscription = Subscription.find(result.subscription.id) self.assertEqual(len(self.updateable_subscription.transactions) + 1, len(result.subscription.transactions)) self.assertEqual("processor_declined", result.subscription.transactions[0].status) self.assertEqual(result.subscription.transactions[0].amount, Decimal(found_subscription.balance)) self.assertEqual(self.updateable_subscription.price + Decimal("2100"), found_subscription.price) def test_update_with_successful_result(self): new_id = str(random.randint(1, 1000000)) result = Subscription.update(self.updateable_subscription.id, { "id": new_id, "price": Decimal("9999.88"), "plan_id": TestHelper.trial_plan["id"] }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(new_id, subscription.id) self.assertEqual(TestHelper.trial_plan["id"], subscription.plan_id) self.assertEqual(Decimal("9999.88"), subscription.price) def test_update_with_merchant_account_id(self): result = Subscription.update(self.updateable_subscription.id, { "merchant_account_id": TestHelper.non_default_merchant_account_id, }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(TestHelper.non_default_merchant_account_id, subscription.merchant_account_id) def test_update_with_payment_method_token(self): newCard = CreditCard.create({ "customer_id": self.credit_card.customer_id, "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "100", "cardholder_name": self.credit_card.cardholder_name }).credit_card result = Subscription.update(self.updateable_subscription.id, { "payment_method_token": newCard.token }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(newCard.token, subscription.payment_method_token) def test_update_with_payment_method_nonce(self): config = Configuration.instantiate() customer_id = self.credit_card.customer_id parsed_client_token = TestHelper.generate_decoded_client_token({"customer_id": customer_id}) authorization_fingerprint = json.loads(parsed_client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) _, response = http.add_card({ "credit_card": { "number": "4242424242424242", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) nonce = json.loads(response)["creditCards"][0]["nonce"] result = Subscription.update(self.updateable_subscription.id, { "payment_method_nonce": nonce }) self.assertTrue(result.is_success) subscription = result.subscription newCard = CreditCard.find(subscription.payment_method_token) self.assertEqual("4242", newCard.last_4) self.assertNotEqual(newCard.last_4, self.credit_card.last_4) def test_update_with_number_of_billing_cycles(self): result = Subscription.update(self.updateable_subscription.id, { "number_of_billing_cycles": 10 }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(10, subscription.number_of_billing_cycles) def test_update_with_never_expires(self): result = Subscription.update(self.updateable_subscription.id, { "never_expires": True }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(None, subscription.number_of_billing_cycles) def test_update_with_error_result(self): result = Subscription.update(self.updateable_subscription.id, { "id": "bad id", }) self.assertFalse(result.is_success) id_errors = result.errors.for_object("subscription").on("id") self.assertEqual(1, len(id_errors)) self.assertEqual("81906", id_errors[0].code) @raises(NotFoundError) def test_update_raises_error_when_subscription_not_found(self): Subscription.update("notfound", { "id": "newid", }) def test_update_allows_overriding_of_inherited_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], }).subscription subscription = Subscription.update(subscription.id, { "add_ons": { "update": [ { "amount": Decimal("50.00"), "existing_id": "increase_10", "quantity": 2, "number_of_billing_cycles": 5 }, { "amount": Decimal("100.00"), "existing_id": "increase_20", "quantity": 4, "never_expires": True } ] }, "discounts": { "update": [ { "amount": Decimal("15.00"), "existing_id": "discount_7", "quantity": 3, "number_of_billing_cycles": 19 } ] } }).subscription self.assertEqual(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEqual("increase_10", add_ons[0].id) self.assertEqual(Decimal("50.00"), add_ons[0].amount) self.assertEqual(2, add_ons[0].quantity) self.assertEqual(5, add_ons[0].number_of_billing_cycles) self.assertFalse(add_ons[0].never_expires) self.assertEqual("increase_20", add_ons[1].id) self.assertEqual(Decimal("100.00"), add_ons[1].amount) self.assertEqual(4, add_ons[1].quantity) self.assertEqual(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEqual(2, len(subscription.discounts)) discounts = sorted(subscription.discounts, key=lambda discount: discount.id) self.assertEqual("discount_11", discounts[0].id) self.assertEqual(Decimal("11.00"), discounts[0].amount) self.assertEqual(1, discounts[0].quantity) self.assertEqual(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) self.assertEqual("discount_7", discounts[1].id) self.assertEqual(Decimal("15.00"), discounts[1].amount) self.assertEqual(3, discounts[1].quantity) self.assertEqual(19, discounts[1].number_of_billing_cycles) self.assertFalse(discounts[1].never_expires) def test_update_allows_adding_and_removing_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], }).subscription subscription = Subscription.update(subscription.id, { "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "add": [ { "amount": Decimal("50.00"), "inherited_from_id": "increase_30", "quantity": 2, "number_of_billing_cycles": 5 } ], "remove": ["increase_10", "increase_20"] }, "discounts": { "add": [ { "amount": Decimal("17.00"), "inherited_from_id": "discount_15", "never_expires": True } ], "remove": ["discount_7", "discount_11"] } }).subscription self.assertEqual(1, len(subscription.add_ons)) self.assertEqual("increase_30", subscription.add_ons[0].id) self.assertEqual(Decimal("50.00"), subscription.add_ons[0].amount) self.assertEqual(2, subscription.add_ons[0].quantity) self.assertEqual(5, subscription.add_ons[0].number_of_billing_cycles) self.assertFalse(subscription.add_ons[0].never_expires) self.assertEqual(1, len(subscription.discounts)) self.assertEqual("discount_15", subscription.discounts[0].id) self.assertEqual(Decimal("17.00"), subscription.discounts[0].amount) self.assertEqual(1, subscription.discounts[0].quantity) self.assertEqual(None, subscription.discounts[0].number_of_billing_cycles) self.assertTrue(subscription.discounts[0].never_expires) def test_update_allows_adding_and_removing_unicode_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], }).subscription subscription = Subscription.update(subscription.id, { "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "add": [ { "amount": Decimal("50.00"), "inherited_from_id": u"increase_30", "quantity": 2, "number_of_billing_cycles": 5 } ], "remove": [u"increase_10", u"increase_20"] }, "discounts": { "add": [ { "amount": Decimal("17.00"), "inherited_from_id": u"discount_15", "never_expires": True } ], "remove": [u"discount_7", u"discount_11"] } }).subscription self.assertEqual(1, len(subscription.add_ons)) self.assertEqual(u"increase_30", subscription.add_ons[0].id) self.assertEqual(Decimal("50.00"), subscription.add_ons[0].amount) self.assertEqual(2, subscription.add_ons[0].quantity) self.assertEqual(5, subscription.add_ons[0].number_of_billing_cycles) self.assertFalse(subscription.add_ons[0].never_expires) self.assertEqual(1, len(subscription.discounts)) self.assertEqual(u"discount_15", subscription.discounts[0].id) self.assertEqual(Decimal("17.00"), subscription.discounts[0].amount) self.assertEqual(1, subscription.discounts[0].quantity) self.assertEqual(None, subscription.discounts[0].number_of_billing_cycles) self.assertTrue(subscription.discounts[0].never_expires) def test_update_can_replace_entire_set_of_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], }).subscription subscription = Subscription.update(subscription.id, { "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "add": [ {"inherited_from_id": "increase_30"}, {"inherited_from_id": "increase_20"}, ], }, "discounts": { "add": [ {"inherited_from_id": "discount_15"}, ], }, "options": { "replace_all_add_ons_and_discounts": True, }, }).subscription self.assertEqual(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEqual("increase_20", add_ons[0].id) self.assertEqual(Decimal("20.00"), add_ons[0].amount) self.assertEqual(1, add_ons[0].quantity) self.assertEqual(None, add_ons[0].number_of_billing_cycles) self.assertTrue(add_ons[0].never_expires) self.assertEqual("increase_30", add_ons[1].id) self.assertEqual(Decimal("30.00"), add_ons[1].amount) self.assertEqual(1, add_ons[1].quantity) self.assertEqual(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEqual(1, len(subscription.discounts)) self.assertEqual("discount_15", subscription.discounts[0].id) self.assertEqual(Decimal("15.00"), subscription.discounts[0].amount) self.assertEqual(1, subscription.discounts[0].quantity) self.assertEqual(None, subscription.discounts[0].number_of_billing_cycles) self.assertTrue(subscription.discounts[0].never_expires) def test_update_descriptor_name_and_phone(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "descriptor": { "name": "123*123456789012345678", "phone": "1234567890" } }) self.assertTrue(result.is_success) subscription = result.subscription updated_subscription = Subscription.update(subscription.id, { "descriptor": { "name": "999*99", "phone": "1234567890" } }).subscription self.assertEqual("999*99", updated_subscription.descriptor.name) self.assertEqual("1234567890", updated_subscription.descriptor.phone) def test_update_description(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "options": {"validate": False} }) self.assertEqual(202, status_code) payment_method_token = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": nonce }).payment_method.token result = Subscription.create({ "payment_method_token": payment_method_token, "plan_id": TestHelper.trialless_plan["id"], "options": { "paypal": { "description": "A great product" } } }) self.assertTrue(result.is_success) subscription = result.subscription updated_subscription = Subscription.update(subscription.id, { "options": { "paypal": { "description": "An incredible product" } } }).subscription self.assertEqual("An incredible product", updated_subscription.description) def test_cancel_with_successful_response(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription result = Subscription.cancel(subscription.id) self.assertTrue(result.is_success) self.assertEqual("Canceled", result.subscription.status) def test_unsuccessful_cancel_returns_validation_error(self): Subscription.cancel(self.updateable_subscription.id) result = Subscription.cancel(self.updateable_subscription.id) self.assertFalse(result.is_success) status_errors = result.errors.for_object("subscription").on("status") self.assertTrue(len(status_errors), 1) self.assertEqual("81905", status_errors[0].code) @raises(NotFoundError) def test_cancel_raises_not_found_error_with_bad_subscription(self): Subscription.cancel("notreal") def test_search_with_argument_list_rather_than_literal_list(self): trial_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("1") }).subscription trialless_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": Decimal("1") }).subscription collection = Subscription.search( SubscriptionSearch.plan_id == "integration_trial_plan", SubscriptionSearch.price == Decimal("1") ) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_search_on_billing_cycles_remaining(self): subscription_5 = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "number_of_billing_cycles": 5 }).subscription subscription_10 = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "number_of_billing_cycles": 10 }).subscription collection = Subscription.search([ SubscriptionSearch.billing_cycles_remaining >= 7 ]) self.assertTrue(TestHelper.includes(collection, subscription_10)) self.assertFalse(TestHelper.includes(collection, subscription_5)) def test_search_on_created_at(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription empty_collection = Subscription.search([ SubscriptionSearch.created_at.between(date.today() + timedelta(1), date.today() + timedelta(2)) ]) self.assertTrue(empty_collection.maximum_size == 0) success_collection = Subscription.search([ SubscriptionSearch.created_at.between(date.today() - timedelta(1), date.today() + timedelta(1)) ]) self.assertTrue(success_collection.maximum_size > 0) def test_search_on_days_past_due(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription, 3) collection = Subscription.search([ SubscriptionSearch.days_past_due.between(2, 10) ]) self.assertTrue(collection.maximum_size > 0) for subscription in collection.items: self.assertTrue(2 <= subscription.days_past_due <= 10) def test_search_on_plan_id(self): trial_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("2") }).subscription trialless_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": Decimal("2") }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id == "integration_trial_plan", SubscriptionSearch.price == Decimal("2") ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) collection = Subscription.search([ SubscriptionSearch.plan_id.in_list("integration_trial_plan", "integration_trialless_plan"), SubscriptionSearch.price == Decimal("2") ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertTrue(TestHelper.includes(collection, trialless_subscription)) def test_search_on_plan_id_is_acts_like_text_node_instead_of_multiple_value(self): for plan in [TestHelper.trial_plan, TestHelper.trialless_plan]: Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": plan["id"], "price": Decimal("3") }) collection = Subscription.search([ SubscriptionSearch.plan_id == "no such plan id", SubscriptionSearch.price == Decimal("3") ]) self.assertEqual(0, collection.maximum_size) def test_search_on_status(self): active_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": Decimal("3") }).subscription canceled_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": Decimal("3") }).subscription Subscription.cancel(canceled_subscription.id) collection = Subscription.search([ SubscriptionSearch.status.in_list([Subscription.Status.Active, Subscription.Status.Canceled]), SubscriptionSearch.price == Decimal("3") ]) self.assertTrue(TestHelper.includes(collection, active_subscription)) self.assertTrue(TestHelper.includes(collection, canceled_subscription)) def test_search_on_merchant_account_id(self): subscription_default_ma = Subscription.create({ "merchant_account_id": TestHelper.default_merchant_account_id, "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("4") }).subscription subscription_non_default_ma = Subscription.create({ "merchant_account_id": TestHelper.non_default_merchant_account_id, "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("4") }).subscription collection = Subscription.search([ SubscriptionSearch.merchant_account_id == TestHelper.default_merchant_account_id, SubscriptionSearch.price == Decimal("4") ]) self.assertTrue(TestHelper.includes(collection, subscription_default_ma)) self.assertFalse(TestHelper.includes(collection, subscription_non_default_ma)) def test_search_on_bogus_merchant_account_id(self): subscription = Subscription.create({ "merchant_account_id": TestHelper.default_merchant_account_id, "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("4") }).subscription collection = Subscription.search([ SubscriptionSearch.merchant_account_id == subscription.merchant_account_id, SubscriptionSearch.price == Decimal("4") ]) self.assertTrue(TestHelper.includes(collection, subscription)) collection = Subscription.search([ SubscriptionSearch.merchant_account_id.in_list(["totally_bogus_id", subscription.merchant_account_id]), SubscriptionSearch.price == Decimal("4") ]) self.assertTrue(TestHelper.includes(collection, subscription)) collection = Subscription.search([ SubscriptionSearch.merchant_account_id == "totally_bogus_id", SubscriptionSearch.price == Decimal("4") ]) self.assertFalse(TestHelper.includes(collection, subscription)) def test_search_on_price(self): subscription_900 = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("900") }).subscription subscription_1000 = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("1000") }).subscription collection = Subscription.search([ SubscriptionSearch.price >= Decimal("950") ]) self.assertTrue(TestHelper.includes(collection, subscription_1000)) self.assertFalse(TestHelper.includes(collection, subscription_900)) def test_search_on_transaction_id(self): subscription_found = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription subscription_not_found = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription collection = Subscription.search( SubscriptionSearch.transaction_id == subscription_found.transactions[0].id ) self.assertTrue(TestHelper.includes(collection, subscription_found)) self.assertFalse(TestHelper.includes(collection, subscription_not_found)) def test_search_on_id(self): subscription_found = Subscription.create({ "id": "find_me_%s" % random.randint(1, 1000000), "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], }).subscription subscription_not_found = Subscription.create({ "id": "do_not_find_me_%s" % random.randint(1, 1000000), "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], }).subscription collection = Subscription.search([ SubscriptionSearch.id.starts_with("find_me") ]) self.assertTrue(TestHelper.includes(collection, subscription_found)) self.assertFalse(TestHelper.includes(collection, subscription_not_found)) def test_search_on_next_billing_date(self): subscription_found = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription subscription_not_found = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription next_billing_date_cutoff = datetime.today() + timedelta(days=5) collection = Subscription.search( SubscriptionSearch.next_billing_date >= next_billing_date_cutoff ) self.assertTrue(TestHelper.includes(collection, subscription_found)) self.assertFalse(TestHelper.includes(collection, subscription_not_found)) def test_retryCharge_without_amount__deprecated(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription) result = Subscription.retryCharge(subscription.id) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(subscription.price, transaction.amount) self.assertNotEqual(None, transaction.processor_authorization_code) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) def test_retry_charge_without_amount(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription) result = Subscription.retry_charge(subscription.id) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(subscription.price, transaction.amount) self.assertNotEqual(None, transaction.processor_authorization_code) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) def test_retryCharge_with_amount__deprecated(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription) result = Subscription.retryCharge(subscription.id, Decimal(TransactionAmounts.Authorize)) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertNotEqual(None, transaction.processor_authorization_code) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) def test_retry_charge_with_amount(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription) result = Subscription.retry_charge(subscription.id, Decimal(TransactionAmounts.Authorize)) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertNotEqual(None, transaction.processor_authorization_code) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) def test_retry_charge_with_submit_for_settlement(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription) result = Subscription.retry_charge(subscription.id, None, True) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(subscription.price, transaction.amount) self.assertNotEqual(None, transaction.processor_authorization_code) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) def test_retry_charge_with_submit_for_settlement_and_amount(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription) result = Subscription.retry_charge(subscription.id, Decimal(TransactionAmounts.Authorize), True) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertNotEqual(None, transaction.processor_authorization_code) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) def test_create_with_paypal_future_payment_method_token(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "options": {"validate": False} }) self.assertEqual(202, status_code) payment_method_token = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": nonce }).payment_method.token result = Subscription.create({ "payment_method_token": payment_method_token, "plan_id": TestHelper.trialless_plan["id"] }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(payment_method_token, subscription.payment_method_token) def test_create_fails_with_paypal_one_time_payment_method_nonce(self): result = Subscription.create({ "payment_method_nonce": Nonces.PayPalOneTimePayment, "plan_id": TestHelper.trialless_plan["id"] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Subscription.PaymentMethodNonceIsInvalid, result.errors.for_object("subscription")[0].code ) def test_create_fails_with_paypal_future_payment_method_nonce(self): result = Subscription.create({ "payment_method_nonce": Nonces.PayPalFuturePayment, "plan_id": TestHelper.trialless_plan["id"] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Subscription.PaymentMethodNonceIsInvalid, result.errors.for_object("subscription")[0].code ) braintree_python-3.57.1/tests/integration/test_credentials_parser.py0000644000175000017500000000673413545202423024246 0ustar hlehlefrom tests.test_helper import * from braintree.test.nonces import Nonces from braintree.credentials_parser import CredentialsParser class TestCredentialsParser(unittest.TestCase): def test_parses_client_credentials(self): parser = CredentialsParser( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) parser.parse_client_credentials() self.assertEqual("client_id$development$integration_client_id", parser.client_id) self.assertEqual("client_secret$development$integration_client_secret", parser.client_secret) self.assertEqual(braintree.Environment.Development, parser.environment) def test_error_on_inconsistent_environment(self): with self.assertRaises(ConfigurationError) as error: parser = CredentialsParser( client_id="client_id$qa$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) parser.parse_client_credentials() config_error = error.exception self.assertIn("Mismatched credential environments", str(config_error)) def test_error_on_missing_client_id(self): with self.assertRaises(ConfigurationError) as error: parser = CredentialsParser( client_id=None, client_secret="client_secret$development$integration_client_secret" ) parser.parse_client_credentials() config_error = error.exception self.assertIn("Missing client_id", str(config_error)) def test_error_on_missing_client_secret(self): with self.assertRaises(ConfigurationError) as error: parser = CredentialsParser( client_id="client_id$development$integration_client_id", client_secret=None ) parser.parse_client_credentials() config_error = error.exception self.assertIn("Missing client_secret", str(config_error)) def test_error_on_invalid_client_id(self): with self.assertRaises(ConfigurationError) as error: parser = CredentialsParser( client_id="client_secret$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) parser.parse_client_credentials() config_error = error.exception self.assertIn("Value passed for client_id is not a client_id", str(config_error)) def test_error_on_invalid_client_secret(self): with self.assertRaises(ConfigurationError) as error: parser = CredentialsParser( client_id="client_id$development$integration_client_id", client_secret="client_id$development$integration_client_secret" ) parser.parse_client_credentials() config_error = error.exception self.assertIn("Value passed for client_secret is not a client_secret", str(config_error)) def test_parses_access_token(self): parser = CredentialsParser( access_token="access_token$development$integration_merchant_id$fb27c79dd" ) parser.parse_access_token() self.assertEqual("access_token$development$integration_merchant_id$fb27c79dd", parser.access_token) self.assertEqual("integration_merchant_id", parser.merchant_id) self.assertEqual(braintree.Environment.Development, parser.environment) braintree_python-3.57.1/tests/integration/test_http.py0000644000175000017500000000673413545202423021354 0ustar hlehlefrom tests.test_helper import * from distutils.version import LooseVersion import platform import braintree import requests class TestHttp(unittest.TestCase): if LooseVersion(requests.__version__) >= LooseVersion('1.0.0'): SSLError = requests.exceptions.SSLError else: SSLError = requests.models.SSLError @staticmethod def get_http(environment): config = Configuration(environment, "merchant_id", public_key="public_key", private_key="private_key") return config.http() @raises(AuthenticationError) def test_successful_connection_sandbox(self): http = self.get_http(Environment.Sandbox) http.get("/") @raises(AuthenticationError) def test_successful_connection_production(self): http = self.get_http(Environment.Production) http.get("/") def test_wrapping_http_exceptions(self): config = Configuration( Environment("test", "localhost", "1", False, None, Environment.Production.ssl_certificate), "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key", wrap_http_exceptions=True ) gateway = braintree.braintree_gateway.BraintreeGateway(config) try: gateway.transaction.find("my_id") except braintree.exceptions.unexpected_error.UnexpectedError: correct_exception = True except Exception: correct_exception = False self.assertTrue(correct_exception) def test_unsuccessful_connection_to_good_ssl_server_with_wrong_cert(self): if platform.system() == "Darwin": return #any endpoint that returns valid XML with a status of 3xx or less and serves SSL environment = Environment("test", "aws.amazon.com/ec2", "443", "http://auth.venmo.dev:9292", True, Environment.Production.ssl_certificate) http = self.get_http(environment) try: http.get("/") except self.SSLError as e: self.assertTrue("certificate verify failed" in str(e)) except AuthenticationError: self.fail("Expected to receive an SSL error but received an Authentication Error instead, check your local openssl installation") else: self.fail("Expected to receive an SSL error but no exception was raised") def test_unsuccessful_connection_to_ssl_server_with_wrong_domain(self): #ip address of api.braintreegateway.com environment = Environment("test", "204.109.13.121", "443", "http://auth.venmo.dev:9292", True, Environment.Production.ssl_certificate) http = self.get_http(environment) try: http.get("/") except self.SSLError: pass else: self.fail("Expected to receive an SSL error but no exception was raised") def test_timeouts(self): config = Configuration( Environment.Development, "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key", wrap_http_exceptions=True, timeout=0.001 ) gateway = braintree.braintree_gateway.BraintreeGateway(config) try: gateway.transaction.find("my_id") except braintree.exceptions.http.timeout_error.TimeoutError: correct_exception = True except Exception: correct_exception = False self.assertTrue(correct_exception) braintree_python-3.57.1/tests/integration/test_transparent_redirect.py0000644000175000017500000001715213545202423024613 0ustar hlehlefrom tests.test_helper import * class TestTransparentRedirect(unittest.TestCase): @raises(DownForMaintenanceError) def test_parse_and_validate_query_string_checks_http_status_before_hash(self): customer = Customer.create().customer tr_data = { "credit_card": { "customer_id": customer.id } } post_params = { "tr_data": CreditCard.tr_data_for_create(tr_data, "http://example.com/path?foo=bar"), "credit_card[cardholder_name]": "Card Holder", "credit_card[number]": "4111111111111111", "credit_card[expiration_date]": "05/2012", } query_string = TestHelper.simulate_tr_form_post(post_params, Configuration.instantiate().base_merchant_path() + "/test/maintenance") CreditCard.confirm_transparent_redirect(query_string) @raises(AuthenticationError) def test_parse_and_validate_query_string_raises_authentication_error_with_bad_credentials(self): customer = Customer.create().customer tr_data = { "credit_card": { "customer_id": customer.id } } old_private_key = Configuration.private_key try: Configuration.private_key = "bad" post_params = { "tr_data": CreditCard.tr_data_for_create(tr_data, "http://example.com/path?foo=bar"), "credit_card[cardholder_name]": "Card Holder", "credit_card[number]": "4111111111111111", "credit_card[expiration_date]": "05/2012", } query_string = TestHelper.simulate_tr_form_post(post_params, CreditCard.transparent_redirect_create_url()) CreditCard.confirm_transparent_redirect(query_string) finally: Configuration.private_key = old_private_key def test_transaction_sale_from_transparent_redirect_with_successful_result(self): tr_data = { "transaction": { "amount": TransactionAmounts.Authorize, } } post_params = { "tr_data": Transaction.tr_data_for_sale(tr_data, "http://example.com/path"), "transaction[credit_card][number]": "4111111111111111", "transaction[credit_card][expiration_date]": "05/2010", } query_string = TestHelper.simulate_tr_form_post(post_params) result = TransparentRedirect.confirm(query_string) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual("411111", transaction.credit_card_details.bin) self.assertEqual("1111", transaction.credit_card_details.last_4) self.assertEqual("05/2010", transaction.credit_card_details.expiration_date) def test_transaction_credit_from_transparent_redirect_with_successful_result(self): tr_data = { "transaction": { "amount": TransactionAmounts.Authorize, } } post_params = { "tr_data": Transaction.tr_data_for_credit(tr_data, "http://example.com/path"), "transaction[credit_card][number]": "4111111111111111", "transaction[credit_card][expiration_date]": "05/2010", } query_string = TestHelper.simulate_tr_form_post(post_params) result = TransparentRedirect.confirm(query_string) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEqual(Transaction.Type.Credit, transaction.type) self.assertEqual("411111", transaction.credit_card_details.bin) self.assertEqual("1111", transaction.credit_card_details.last_4) self.assertEqual("05/2010", transaction.credit_card_details.expiration_date) def test_customer_create_from_transparent_redirect(self): tr_data = { "customer": { "first_name": "John", "last_name": "Doe", "company": "Doe Co", } } post_params = { "tr_data": Customer.tr_data_for_create(tr_data, "http://example.com/path"), "customer[email]": "john@doe.com", "customer[phone]": "312.555.2323", "customer[fax]": "614.555.5656", "customer[website]": "www.johndoe.com" } query_string = TestHelper.simulate_tr_form_post(post_params) result = TransparentRedirect.confirm(query_string) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("John", customer.first_name) self.assertEqual("Doe", customer.last_name) self.assertEqual("Doe Co", customer.company) self.assertEqual("john@doe.com", customer.email) self.assertEqual("312.555.2323", customer.phone) self.assertEqual("614.555.5656", customer.fax) self.assertEqual("www.johndoe.com", customer.website) def test_customer_update_from_transparent_redirect(self): customer = Customer.create({"first_name": "Sarah", "last_name": "Humphrey"}).customer tr_data = { "customer_id": customer.id, "customer": { "first_name": "Stan", } } post_params = { "tr_data": Customer.tr_data_for_update(tr_data, "http://example.com/path"), "customer[last_name]": "Humphrey", } query_string = TestHelper.simulate_tr_form_post(post_params) result = TransparentRedirect.confirm(query_string) self.assertTrue(result.is_success) customer = Customer.find(customer.id) self.assertEqual("Stan", customer.first_name) self.assertEqual("Humphrey", customer.last_name) def test_payment_method_create_from_transparent_redirect(self): customer = Customer.create({"first_name": "Sarah", "last_name": "Humphrey"}).customer tr_data = { "credit_card": { "customer_id": customer.id, "number": "4111111111111111", } } post_params = { "tr_data": CreditCard.tr_data_for_create(tr_data, "http://example.com/path"), "credit_card[expiration_month]": "01", "credit_card[expiration_year]": "10" } query_string = TestHelper.simulate_tr_form_post(post_params) result = TransparentRedirect.confirm(query_string) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertEqual("411111", credit_card.bin) self.assertEqual("1111", credit_card.last_4) self.assertEqual("01/2010", credit_card.expiration_date) def test_payment_method_update_from_transparent_redirect(self): customer = Customer.create({"first_name": "Sarah", "last_name": "Humphrey"}).customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "10/10" }).credit_card tr_data = { "payment_method_token": credit_card.token, "credit_card": { "expiration_date": "12/12" } } post_params = { "tr_data": CreditCard.tr_data_for_update(tr_data, "http://example.com/path"), } query_string = TestHelper.simulate_tr_form_post(post_params) TransparentRedirect.confirm(query_string) credit_card = CreditCard.find(credit_card.token) self.assertEqual("12/2012", credit_card.expiration_date) braintree_python-3.57.1/tests/integration/test_discounts.py0000644000175000017500000000235213545202423022400 0ustar hlehlefrom tests.test_helper import * class TestDiscounts(unittest.TestCase): def test_all_returns_all_discounts(self): new_id = str(random.randint(1, 1000000)) attributes = { "amount": "100.00", "description": "some description", "id": new_id, "kind": "discount", "name": "python_discount", "never_expires": False, "number_of_billing_cycles": 1 } Configuration.instantiate().http().post(Configuration.instantiate().base_merchant_path() + "/modifications/create_modification_for_tests", {"modification": attributes}) discounts = Discount.all() for discount in discounts: if discount.id == new_id: break else: discount = None self.assertNotEqual(None, discount) self.assertEqual(Decimal("100.00"), discount.amount) self.assertEqual("some description", discount.description) self.assertEqual(new_id, discount.id) self.assertEqual("discount", discount.kind) self.assertEqual("python_discount", discount.name) self.assertEqual(False, discount.never_expires) self.assertEqual(1, discount.number_of_billing_cycles) braintree_python-3.57.1/tests/integration/test_testing_gateway.py0000644000175000017500000000326013545202423023562 0ustar hlehlefrom tests.test_helper import * from braintree.configuration import Configuration from braintree.exceptions.test_operation_performed_in_production_error import TestOperationPerformedInProductionError class TestTestingGateway(unittest.TestCase): def setUp(self): config = Configuration(braintree.Environment.Production, "merchant_id", "public_key", "private_key") braintree_gateway = BraintreeGateway(config) self.gateway = TestingGateway(braintree_gateway) @raises(TestOperationPerformedInProductionError) def test_error_is_raised_in_production_for_settle_transaction(self): self.gateway.settle_transaction("") @raises(TestOperationPerformedInProductionError) def test_error_is_raised_in_production_for_make_past_due(self): self.gateway.make_past_due("") @raises(TestOperationPerformedInProductionError) def test_error_is_raised_in_production_for_escrow_transaction(self): self.gateway.escrow_transaction("") @raises(TestOperationPerformedInProductionError) def test_error_is_raised_in_production_for_settlement_confirm_transaction(self): self.gateway.settlement_confirm_transaction("") @raises(TestOperationPerformedInProductionError) def test_error_is_raised_in_production_for_settlement_decline_transaction(self): self.gateway.settlement_decline_transaction("") @raises(TestOperationPerformedInProductionError) def test_error_is_raised_in_production_for_create_3ds_verification(self): self.gateway.create_3ds_verification("", "") @raises(TestOperationPerformedInProductionError) def test_error_is_raised_in_production(self): self.gateway.settle_transaction("") braintree_python-3.57.1/tests/integration/test_graphql_client.py0000644000175000017500000000332513545202423023362 0ustar hlehlefrom unittest import TestCase from braintree.configuration import Configuration from braintree.environment import Environment class TestGraphQLClient(TestCase): @staticmethod def get_graphql_client(environment): config = Configuration(environment, "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key") return config.graphql_client() def test_graphql_makes_valid_queries_without_variables(self): definition = ''' query { ping } ''' graphql_client = self.get_graphql_client(Environment.Development) response = graphql_client.query(definition) self.assertTrue("data" in response) self.assertTrue("ping" in response["data"]) self.assertTrue("pong" == response["data"]["ping"]) def test_graphql_makes_valid_queries_with_variables(self): definition = ''' mutation CreateClientToken($input: CreateClientTokenInput!) { createClientToken(input: $input) { clientMutationId clientToken } } ''' variables = { "input": { "clientMutationId": "abc123", "clientToken": { "merchantAccountId": "ABC123" } } } graphql_client = self.get_graphql_client(Environment.Development) response = graphql_client.query(definition, variables) self.assertTrue("data" in response) self.assertTrue("createClientToken" in response["data"]) self.assertTrue("clientToken" in response["data"]["createClientToken"]) braintree_python-3.57.1/tests/integration/test_samsung_pay.py0000644000175000017500000001366413545202423022723 0ustar hlehlefrom tests.test_helper import * class TestSamsungPay(unittest.TestCase): def test_create_from_nonce(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.SamsungPayVisa }) self.assertTrue(result.is_success) samsung_pay_card = result.payment_method self.assertIsInstance(samsung_pay_card, braintree.SamsungPayCard) self.assertIsNotNone(samsung_pay_card.bin) self.assertIsNotNone(samsung_pay_card.card_type) self.assertIsNotNone(samsung_pay_card.commercial) self.assertIsNotNone(samsung_pay_card.country_of_issuance) self.assertIsNotNone(samsung_pay_card.created_at) self.assertIsNotNone(samsung_pay_card.customer_id) self.assertIsNotNone(samsung_pay_card.customer_location) self.assertIsNotNone(samsung_pay_card.debit) self.assertIsNotNone(samsung_pay_card.default) self.assertIsNotNone(samsung_pay_card.durbin_regulated) self.assertIsNotNone(samsung_pay_card.expiration_date) self.assertIsNotNone(samsung_pay_card.expiration_month) self.assertIsNotNone(samsung_pay_card.expiration_year) self.assertIsNotNone(samsung_pay_card.expired) self.assertIsNotNone(samsung_pay_card.healthcare) self.assertIsNotNone(samsung_pay_card.image_url) self.assertIsNotNone(samsung_pay_card.issuing_bank) self.assertIsNotNone(samsung_pay_card.last_4) self.assertIsNotNone(samsung_pay_card.masked_number) self.assertIsNotNone(samsung_pay_card.payroll) self.assertIsNotNone(samsung_pay_card.prepaid) self.assertIsNotNone(samsung_pay_card.product_id) self.assertIsNotNone(samsung_pay_card.subscriptions) self.assertIsNotNone(samsung_pay_card.token) self.assertIsNotNone(samsung_pay_card.unique_number_identifier) self.assertIsNotNone(samsung_pay_card.updated_at) def test_create_from_nonce_customer_attr(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.SamsungPayVisa }) samsung_pay_cards = Customer.find(customer.id).samsung_pay_cards self.assertEqual(len(samsung_pay_cards), 1) self.assertEqual(result.payment_method.token, samsung_pay_cards[0].token) def test_create_from_nonce_with_name_and_address(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.SamsungPayVisa, "cardholder_name": "Gronk", "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484", "country_name": "Mexico" } }) self.assertTrue(result.is_success) self.assertEqual("Gronk", result.payment_method.cardholder_name) address = result.payment_method.billing_address self.assertEqual("123 Abc Way", address.street_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60622", address.postal_code) self.assertEqual("MX", address.country_code_alpha2) self.assertEqual("MEX", address.country_code_alpha3) self.assertEqual("484", address.country_code_numeric) self.assertEqual("Mexico", address.country_name) def test_search_for_transaction(self): result = Transaction.sale({ "payment_method_nonce": Nonces.SamsungPayVisa, "amount": "1.69" }) self.assertTrue(result.is_success) transaction = result.transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == PaymentInstrumentType.SamsungPayCard ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_create_transaction_from_nonce_and_vault(self): customer = Customer.create().customer result = Transaction.sale({ "payment_method_nonce": Nonces.SamsungPayVisa, "customer_id": customer.id, "amount": "69.69", "options": { "store_in_vault": True } }) self.assertTrue(result.is_success) samsung_pay_card_details = result.transaction.samsung_pay_card_details self.assertIsInstance(samsung_pay_card_details, braintree.SamsungPayCard) self.assertIsNotNone(samsung_pay_card_details.bin) self.assertIsNotNone(samsung_pay_card_details.card_type) self.assertIsNotNone(samsung_pay_card_details.commercial) self.assertIsNotNone(samsung_pay_card_details.country_of_issuance) self.assertIsNotNone(samsung_pay_card_details.debit) self.assertIsNotNone(samsung_pay_card_details.durbin_regulated) self.assertIsNotNone(samsung_pay_card_details.expiration_date) self.assertIsNotNone(samsung_pay_card_details.expiration_year) self.assertIsNotNone(samsung_pay_card_details.expiration_month) self.assertIsNotNone(samsung_pay_card_details.healthcare) self.assertIsNotNone(samsung_pay_card_details.image_url) self.assertIsNotNone(samsung_pay_card_details.issuing_bank) self.assertIsNotNone(samsung_pay_card_details.last_4) self.assertIsNotNone(samsung_pay_card_details.payroll) self.assertIsNotNone(samsung_pay_card_details.prepaid) self.assertIsNotNone(samsung_pay_card_details.product_id) self.assertIsNotNone(samsung_pay_card_details.token) braintree_python-3.57.1/tests/integration/test_plan.py0000644000175000017500000000571113545202423021321 0ustar hlehlefrom tests.test_helper import * class TestPlan(unittest.TestCase): def test_all_returns_empty_list(self): Configuration.configure( Environment.Development, "test_merchant_id", "test_public_key", "test_private_key" ) plans = Plan.all() self.assertEqual([], plans) Configuration.configure( Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) def test_all_returns_all_the_plans(self): plan_token = str(random.randint(1, 1000000)) attributes = { "id": plan_token, "billing_day_of_month": 1, "billing_frequency": 1, "currency_iso_code": "USD", "description": "some description", "name": "python test plan", "number_of_billing_cycles": 1, "price": "1.00", } Configuration.instantiate().http().post(Configuration.instantiate().base_merchant_path() + "/plans/create_plan_for_tests", {"plan": attributes}) add_on_attributes = { "amount": "100.00", "description": "some description", "plan_id": plan_token, "kind": "add_on", "name": "python_add_on", "never_expires": False, "number_of_billing_cycles": 1 } Configuration.instantiate().http().post(Configuration.instantiate().base_merchant_path() + "/modifications/create_modification_for_tests", {"modification": add_on_attributes}) discount_attributes = { "amount": "100.00", "description": "some description", "plan_id": plan_token, "kind": "discount", "name": "python_discount", "never_expires": False, "number_of_billing_cycles": 1 } Configuration.instantiate().http().post(Configuration.instantiate().base_merchant_path() + "/modifications/create_modification_for_tests", {"modification": discount_attributes}) plans = Plan.all() for plan in plans: if plan.id == plan_token: actual_plan = plan self.assertNotEqual(None, actual_plan) self.assertEqual(1, attributes["billing_day_of_month"]) self.assertEqual(1, attributes["billing_frequency"]) self.assertEqual("USD", attributes["currency_iso_code"]) self.assertEqual("some description", attributes["description"]) self.assertEqual("python test plan", attributes["name"]) self.assertEqual(1, attributes["number_of_billing_cycles"]) self.assertEqual("1.00", attributes["price"]) self.assertEqual(1, len(actual_plan.add_ons)) self.assertEqual(add_on_attributes["name"], actual_plan.add_ons[0].name) self.assertEqual(1, len(actual_plan.discounts)) self.assertEqual(discount_attributes["name"], actual_plan.discounts[0].name) braintree_python-3.57.1/tests/__init__.py0000644000175000017500000000000013545202423016526 0ustar hlehlebraintree_python-3.57.1/tests/test_helper.py0000644000175000017500000004664413545202423017335 0ustar hlehleimport json import os import re import random import sys import unittest import warnings import subprocess import time if sys.version_info[0] == 2: from urllib import urlencode, quote_plus from httplib import HTTPConnection from base64 import encodestring as encodebytes else: from urllib.parse import urlencode, quote_plus from http.client import HTTPConnection from base64 import encodebytes import requests from base64 import b64decode from contextlib import contextmanager from datetime import date, datetime, timedelta from decimal import Decimal from subprocess import Popen, PIPE from nose.tools import make_decorator from nose.tools import raises from braintree import * from braintree.exceptions import * from braintree.test.credit_card_numbers import CreditCardNumbers from braintree.test.nonces import Nonces from braintree.testing_gateway import * from braintree.util import * def raises_with_regexp(expected_exception_class, regexp_to_match): def decorate(func): name = func.__name__ def generated_function(*args, **kwargs): exception_string = None try: func(*args, **kwargs) except expected_exception_class as e: exception_string = str(e) except: raise if exception_string is None: message = "%s() did not raise %s" % (name, expected_exception_class.__name__) raise AssertionError(message) elif re.match(regexp_to_match, exception_string) is None: message = "%s() exception message (%s) did not match (%s)" % \ (name, exception_string, regexp_to_match) raise AssertionError(message) return make_decorator(func)(generated_function) return decorate def reset_braintree_configuration(): Configuration.configure( Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) reset_braintree_configuration() class AdvancedFraudIntegrationMerchant: def __enter__(self): Configuration.configure( Environment.Development, "advanced_fraud_integration_merchant_id", "advanced_fraud_integration_public_key", "advanced_fraud_integration_private_key" ) def __exit__(self, type, value, trace): reset_braintree_configuration() def showwarning(*_): pass warnings.showwarning = showwarning class TestHelper(object): default_merchant_account_id = "sandbox_credit_card" non_default_merchant_account_id = "sandbox_credit_card_non_default" non_default_sub_merchant_account_id = "sandbox_sub_merchant_account" three_d_secure_merchant_account_id = "three_d_secure_merchant_account" fake_amex_direct_merchant_account_id = "fake_amex_direct_usd" fake_venmo_account_merchant_account_id = "fake_first_data_venmo_account" us_bank_merchant_account_id = "us_bank_merchant_account" another_us_bank_merchant_account_id = "another_us_bank_merchant_account" adyen_merchant_account_id = "adyen_ma" hiper_brl_merchant_account_id = "hiper_brl" add_on_discount_plan = { "description": "Plan for integration tests -- with add-ons and discounts", "id": "integration_plan_with_add_ons_and_discounts", "price": Decimal("9.99"), "trial_duration": 2, "trial_duration_unit": Subscription.TrialDurationUnit.Day, "trial_period": True } billing_day_of_month_plan = { "description": "Plan for integration tests -- with billing day of month", "id": "integration_plan_with_billing_day_of_month", "billing_day_of_month": 5, "price": Decimal("8.88"), } trial_plan = { "description": "Plan for integration tests -- with trial", "id": "integration_trial_plan", "price": Decimal("43.21"), "trial_period": True, "trial_duration": 2, "trial_duration_unit": Subscription.TrialDurationUnit.Day } trialless_plan = { "description": "Plan for integration tests -- without a trial", "id": "integration_trialless_plan", "price": Decimal("12.34"), "trial_period": False } valid_token_characters = list("bcdfghjkmnpqrstvwxyz23456789") text_type = unicode if sys.version_info[0] == 2 else str raw_type = str if sys.version_info[0] == 2 else bytes @staticmethod def make_past_due(subscription, number_of_days_past_due=1): Configuration.gateway().testing.make_past_due(subscription.id, number_of_days_past_due) @staticmethod def escrow_transaction(transaction_id): Configuration.gateway().testing.escrow_transaction(transaction_id) @staticmethod def settle_transaction(transaction_id): return Configuration.gateway().testing.settle_transaction(transaction_id) @staticmethod def settlement_confirm_transaction(transaction_id): return Configuration.gateway().testing.settlement_confirm_transaction(transaction_id) @staticmethod def settlement_decline_transaction(transaction_id): return Configuration.gateway().testing.settlement_decline_transaction(transaction_id) @staticmethod def settlement_pending_transaction(transaction_id): return Configuration.gateway().testing.settlement_pending_transaction(transaction_id) @staticmethod def simulate_tr_form_post(post_params, url=TransparentRedirect.url()): form_data = urlencode(post_params) conn = HTTPConnection(Configuration.environment.server_and_port) conn.request("POST", url, form_data, TestHelper.__headers()) response = conn.getresponse() query_string = response.getheader("location").split("?", 1)[1] conn.close() return query_string @staticmethod def create_3ds_verification(merchant_account_id, params): return Configuration.gateway().testing.create_3ds_verification(merchant_account_id, params) @staticmethod @contextmanager def other_merchant(merchant_id, public_key, private_key): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key Configuration.merchant_id = merchant_id Configuration.public_key = public_key Configuration.private_key = private_key try: yield finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key @staticmethod def includes(collection, expected): for item in collection.items: if item.id == expected.id: return True return False @staticmethod def in_list(collection, expected): for item in collection: if item == expected: return True return False @staticmethod def includes_status(collection, status): for item in collection.items: if item.status == status: return True return False @staticmethod def now_minus_offset(offset): now = datetime.utcnow() return (now - timedelta(hours=offset)).strftime("%Y-%m-%d") @staticmethod def unique(some_list): return set(some_list) @staticmethod def __headers(): return { "Accept": "application/xml", "Content-type": "application/x-www-form-urlencoded", } @staticmethod def generate_decoded_client_token(params=None): client_token = None if params: client_token = ClientToken.generate(params) else: client_token = ClientToken.generate() decoded_client_token = b64decode(client_token).decode() return decoded_client_token @staticmethod def nonce_for_paypal_account(paypal_account_details): client_token = json.loads(TestHelper.generate_decoded_client_token()) client = ClientApiHttp(Configuration.instantiate(), { "authorization_fingerprint": client_token["authorizationFingerprint"] }) _, nonce = client.get_paypal_nonce(paypal_account_details) return nonce @staticmethod def random_token_block(x): string = "" for i in range(6): string += random.choice(TestHelper.valid_token_characters) return string @staticmethod def generate_valid_us_bank_account_nonce(routing_number="021000021", account_number="567891234"): client_token = json.loads(TestHelper.generate_decoded_client_token()) headers = { "Content-Type": "application/json", "Braintree-Version": "2016-10-07", "Authorization": "Bearer " + client_token["braintree_api"]["access_token"] } payload = { "type": "us_bank_account", "billing_address": { "street_address": "123 Ave", "region": "CA", "locality": "San Francisco", "postal_code": "94112" }, "account_type": "checking", "ownership_type": "personal", "routing_number": routing_number, "account_number": account_number, "first_name": "Dan", "last_name": "Schulman", "ach_mandate": { "text": "cl mandate text" } } resp = requests.post(client_token["braintree_api"]["url"] + "/tokens", headers=headers, data=json.dumps(payload) ) respJson = json.loads(resp.text) return respJson["data"]["id"] @staticmethod def generate_plaid_us_bank_account_nonce(): client_token = json.loads(TestHelper.generate_decoded_client_token()) headers = { "Content-Type": "application/json", "Braintree-Version": "2016-10-07", "Authorization": "Bearer " + client_token["braintree_api"]["access_token"] } payload = { "type": "plaid_public_token", "public_token": "good", "account_id": "plaid_account_id", "ownership_type": "business", "business_name": "PayPal, Inc.", "billing_address": { "street_address": "123 Ave", "region": "CA", "locality": "San Francisco", "postal_code": "94112" }, "ach_mandate": { "text": "cl mandate text" } } resp = requests.post(client_token["braintree_api"]["url"] + "/tokens", headers=headers, data=json.dumps(payload) ) respJson = json.loads(resp.text) return respJson["data"]["id"] @staticmethod def generate_invalid_us_bank_account_nonce(): token = "tokenusbankacct" for i in range(4): token += "_" + TestHelper.random_token_block('d') token += "_xxx" return token @staticmethod def generate_valid_ideal_payment_id(amount=TransactionAmounts.Authorize): client_token = json.loads(TestHelper.generate_decoded_client_token({ "merchant_account_id": "ideal_merchant_account" })) client = ClientApiHttp(Configuration.instantiate(), { "authorization_fingerprint": client_token["authorizationFingerprint"] }) _, configuration = client.get_configuration() route_id = json.loads(configuration)["ideal"]["routeId"] headers = { "Content-Type": "application/json", "Braintree-Version": "2015-11-01", "Authorization": "Bearer " + client_token["braintree_api"]["access_token"] } payload = { "issuer": "RABONL2U", "order_id": "ABC123", "amount": amount, "currency": "EUR", "route_id": route_id, "redirect_url": "https://braintree-api.com", } resp = requests.post(client_token["braintree_api"]["url"] + "/ideal-payments", headers=headers, data=json.dumps(payload) ) respJson = json.loads(resp.text) return respJson["data"]["id"] @staticmethod def generate_three_d_secure_nonce(gateway, params): url = gateway.config.base_merchant_path() + "/three_d_secure/create_nonce/" + TestHelper.three_d_secure_merchant_account_id response = gateway.config.http().post(url, params) return response["payment_method_nonce"]["nonce"] @staticmethod def create_disputed_transaction(): if hasattr(TestHelper, 'disputed_transaction'): return TestHelper.disputed_transaction disputed_transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": CreditCardNumbers.Disputes.Chargeback, "expiration_date": "04/2018" } }) for _ in range(1, 60): transactions = Transaction.search([ TransactionSearch.id == disputed_transaction.transaction.id, TransactionSearch.dispute_date == datetime.today() ]) if transactions.maximum_size == 1: TestHelper.disputed_transaction = transactions.first return TestHelper.disputed_transaction else: time.sleep(1) raise ValueError('Disputed transaction could not be found') @staticmethod def create_grant(gateway, params): config = gateway.config response = config.http().post("/oauth_testing/grants", { "grant": params }) return response["grant"]["code"] @staticmethod def create_payment_method_grant_fixtures(): config = Configuration( merchant_id="integration_merchant_public_id", public_key="oauth_app_partner_user_public_key", private_key="oauth_app_partner_user_private_key", environment=Environment.Development ) gateway = BraintreeGateway(config) customer = gateway.customer.create().customer credit_card = gateway.credit_card.create( params={ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", "billing_address": { "first_name": "Jon", "last_name": "Doe", "postal_code": "95131" } } ).credit_card oauth_app_gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret", environment=Environment.Development ) code = TestHelper.create_grant(oauth_app_gateway, { "merchant_public_id": "integration_merchant_id", "scope": "grant_payment_method" }) access_token = oauth_app_gateway.oauth.create_token_from_code({ "code": code }).credentials.access_token granting_gateway = BraintreeGateway( access_token=access_token, ) return (granting_gateway, credit_card) @staticmethod def sample_notification_from_xml(xml): gateway = Configuration.gateway() payload = encodebytes(xml) hmac_payload = Crypto.sha1_hmac_hash(gateway.config.private_key, payload) signature = "%s|%s" % (gateway.config.public_key, hmac_payload) return {'bt_signature': signature, 'bt_payload': payload} class ClientApiHttp(Http): def __init__(self, config, options): self.config = config self.options = options self.http = Http(config) @staticmethod def create(): config = Configuration.instantiate() client_token = TestHelper.generate_decoded_client_token() authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] return ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) def get(self, path): return self._make_request("GET", path) def post(self, path, params=None): return self._make_request("POST", path, params) def put(self, path, params=None): return self._make_request("PUT", path, params) def _make_request(self, http_verb, path, params=None): http_strategy = self.config.http_strategy() request_body = json.dumps(params) if params else None return http_strategy.http_do(http_verb, path, self.__headers(), request_body) def set_authorization_fingerprint(self, authorization_fingerprint): self.options['authorization_fingerprint'] = authorization_fingerprint def get_configuration(self): encoded_fingerprint = quote_plus(self.options["authorization_fingerprint"]) url = "/merchants/%s/client_api/v1/configuration" % self.config.merchant_id url += "?authorizationFingerprint=%s" % encoded_fingerprint url += "&configVersion=3" return self.get(url) def get_cards(self): encoded_fingerprint = quote_plus(self.options["authorization_fingerprint"]) url = "/merchants/%s/client_api/v1/payment_methods.json" % self.config.merchant_id url += "?authorizationFingerprint=%s" % encoded_fingerprint url += "&sharedCustomerIdentifier=%s" % self.options["shared_customer_identifier"] url += "&sharedCustomerIdentifierType=%s" % self.options["shared_customer_identifier_type"] return self.get(url) def add_card(self, params): url = "/merchants/%s/client_api/v1/payment_methods/credit_cards.json" % self.config.merchant_id if 'authorization_fingerprint' in self.options: params['authorizationFingerprint'] = self.options['authorization_fingerprint'] if 'shared_customer_identifier' in self.options: params['sharedCustomerIdentifier'] = self.options['shared_customer_identifier'] if 'shared_customer_identifier_type' in self.options: params['sharedCustomerIdentifierType'] = self.options['shared_customer_identifier_type'] return self.post(url, params) def get_paypal_nonce(self, paypal_params): url = "/merchants/%s/client_api/v1/payment_methods/paypal_accounts" % self.config.merchant_id params = {"paypal_account": paypal_params} if 'authorization_fingerprint' in self.options: params['authorizationFingerprint'] = self.options['authorization_fingerprint'] status_code, response = self.post(url, params) nonce = None if status_code == 202: nonce = json.loads(response)["paypalAccounts"][0]["nonce"] return [status_code, nonce] def get_credit_card_nonce(self, credit_card_params): url = "/merchants/%s/client_api/v1/payment_methods/credit_cards" % self.config.merchant_id params = {"credit_card": credit_card_params} if 'authorization_fingerprint' in self.options: params['authorizationFingerprint'] = self.options['authorization_fingerprint'] status_code, response = self.post(url, params) nonce = None if status_code in [201, 202]: nonce = json.loads(response)["creditCards"][0]["nonce"] return [status_code, nonce] def __headers(self): return { "Content-type": "application/json", "User-Agent": "Braintree Python " + version.Version, "X-ApiVersion": Configuration.api_version() } braintree_python-3.57.1/tests/unit/0000755000175000017500000000000013545202423015406 5ustar hlehlebraintree_python-3.57.1/tests/unit/test_payment_method_parser.py0000644000175000017500000000277613545202423023424 0ustar hlehlefrom tests.test_helper import * from braintree.payment_method_parser import parse_payment_method if sys.version_info[0] == 2: from mock import MagicMock else: from unittest.mock import MagicMock class TestPaymentMethodParser(unittest.TestCase): def test_parse_response_returns_a_credit_card(self): credit_card = parse_payment_method(BraintreeGateway(None), { "credit_card": {"bin": "411111", "last_4": "1111"} }) self.assertEqual(CreditCard, credit_card.__class__) self.assertEqual("411111", credit_card.bin) self.assertEqual("1111", credit_card.last_4) def test_parse_response_returns_a_paypal_account(self): paypal_account = parse_payment_method(BraintreeGateway(None), { "paypal_account": {"token": "1234", "default": False} }) self.assertEqual(PayPalAccount, paypal_account.__class__) self.assertEqual("1234", paypal_account.token) self.assertFalse(paypal_account.default) def test_parse_response_returns_an_unknown_payment_method(self): unknown_payment_method = parse_payment_method(BraintreeGateway(None), { "new_fancy_payment_method": { "token": "1234", "default": True, "other_fancy_thing": "is-shiny" } }) self.assertEqual(UnknownPaymentMethod, unknown_payment_method.__class__) self.assertEqual("1234", unknown_payment_method.token) self.assertTrue(unknown_payment_method.default) braintree_python-3.57.1/tests/unit/test_credit_card_verification.py0000644000175000017500000000450313545202423024026 0ustar hlehlefrom tests.test_helper import * class TestCreditCardVerification(unittest.TestCase): @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_create_raises_exception_with_bad_keys(self): CreditCardVerification.create({"bad_key": "value", "credit_card": {"number": "value"}}) def test_constructor_with_amount(self): attributes = { 'amount': '27.00', 'currency_iso_code': 'USD' } verification = CreditCardVerification(None, attributes) self.assertEqual(verification.amount, Decimal('27.00')) self.assertEqual(verification.currency_iso_code, 'USD') def test_constructor_with_bad_amount(self): attributes = { 'amount': None } verification = CreditCardVerification(None, attributes) self.assertEqual(verification.amount, None) def test_constructor_without_amount(self): verification = CreditCardVerification(None, {}) self.assertEqual(verification.amount, None) self.assertEqual(verification.currency_iso_code, None) def test_constructor_when_risk_data_is_not_included(self): verification = CreditCardVerification(None, {"amount": "1.00"}) self.assertEqual(verification.risk_data, None) def test_constructor_when_network_response_is_included(self): attributes = { 'amount': '1.00', 'network_response_code': '00', 'network_response_text': 'Successful approval/completion or V.I.P. PIN verification is successful' } verification = CreditCardVerification(None, attributes) self.assertEqual(verification.network_response_code, '00') self.assertEqual(verification.network_response_text, 'Successful approval/completion or V.I.P. PIN verification is successful') def test_constructor_when_network_response_is_not_included(self): verification = CreditCardVerification(None, {'amount': '1.00'}) self.assertEqual(verification.network_response_code, None) self.assertEqual(verification.network_response_text, None) @raises(NotFoundError) def test_finding_empty_id_raises_not_found_exception(self): CreditCardVerification.find(" ") @raises(NotFoundError) def test_finding_none_raises_not_found_exception(self): CreditCardVerification.find(None) braintree_python-3.57.1/tests/unit/test_europe_bank_account.py0000644000175000017500000000042613545202423023027 0ustar hlehlefrom tests.test_helper import * class TestEuropeBankAccount(unittest.TestCase): def test_mandate_type_constants(self): self.assertEqual("business", EuropeBankAccount.MandateType.Business) self.assertEqual("consumer", EuropeBankAccount.MandateType.Consumer) braintree_python-3.57.1/tests/unit/test_successful_result.py0000644000175000017500000000046613545202423022602 0ustar hlehlefrom tests.test_helper import * class TestSuccessfulResult(unittest.TestCase): def test_is_success(self): self.assertTrue(SuccessfulResult({}).is_success) def test_attributes_are_exposed(self): result = SuccessfulResult({"name": "drew"}) self.assertEqual("drew", result.name) braintree_python-3.57.1/tests/unit/util/0000755000175000017500000000000013545202423016363 5ustar hlehlebraintree_python-3.57.1/tests/unit/util/test_constants.py0000644000175000017500000000042613545202423022012 0ustar hlehlefrom tests.test_helper import * class TestConstants(unittest.TestCase): def test_get_all_constant_values_from_class(self): self.assertEqual(["Active", "Canceled", "Expired", "Past Due", "Pending"], Constants.get_all_constant_values_from_class(Subscription.Status)) braintree_python-3.57.1/tests/unit/util/test_datetime_parser.py0000644000175000017500000000306013545202423023143 0ustar hlehleimport unittest from braintree.util.datetime_parser import parse_datetime as parse from datetime import datetime class TestDateParser(unittest.TestCase): def test_parses_with_zulu_and_symbols(self): self.assertEqual(parse('2017-04-19T18:51:21Z'), datetime(2017, 4, 19, 18, 51, 21)) self.assertEqual(parse('2017-04-19T18:51:21.45Z'), datetime(2017, 4, 19, 18, 51, 21, 450000)) def test_parses_with_zulu_and_no_symbols(self): self.assertEqual(parse('20170419T185121Z'), datetime(2017, 4, 19, 18, 51, 21)) self.assertEqual(parse('20170419T185121.123Z'), datetime(2017, 4, 19, 18, 51, 21, 123000)) def test_parses_with_zero_offset(self): self.assertEqual(parse('2017-04-19T18:51:21+00:00'), datetime(2017, 4, 19, 18, 51, 21)) self.assertEqual(parse('2017-04-19T18:51:21.420+00:00'), datetime(2017, 4, 19, 18, 51, 21, 420000)) def test_parses_with_negative_offset(self): self.assertEqual(parse('2017-04-19T18:51:21-01:30'), datetime(2017, 4, 19, 20, 21, 21)) self.assertEqual(parse('2017-04-19T18:51:21.987-01:30'), datetime(2017, 4, 19, 20, 21, 21, 987000)) def test_parses_with_positive_offset(self): self.assertEqual(parse('2017-04-19T18:51:21+07:00'), datetime(2017, 4, 19, 11, 51, 21)) self.assertEqual(parse('2017-04-19T18:51:21.765+07:00'), datetime(2017, 4, 19, 11, 51, 21, 765000)) def test_raises_with_bad_input(self): with self.assertRaises(ValueError): parse('20170420') with self.assertRaises(ValueError): parse('20170420Z') braintree_python-3.57.1/tests/unit/util/__init__.py0000644000175000017500000000000013545202423020462 0ustar hlehlebraintree_python-3.57.1/tests/unit/test_environment.py0000644000175000017500000000436713545202423021375 0ustar hlehlefrom tests.test_helper import * class TestEnvironment(unittest.TestCase): def test_server_and_port_for_development(self): port = os.getenv("GATEWAY_PORT") or "3000" self.assertEqual("localhost:" + port, Environment.Development.server_and_port) def test_base_url(self): self.assertEqual("https://api.sandbox.braintreegateway.com:443", Environment.Sandbox.base_url) self.assertEqual("https://api.braintreegateway.com:443", Environment.Production.base_url) def test_server_and_port_for_sandbox(self): self.assertEqual("api.sandbox.braintreegateway.com:443", Environment.Sandbox.server_and_port) def test_server_and_port_for_production(self): self.assertEqual("api.braintreegateway.com:443", Environment.Production.server_and_port) def test_server_for_development(self): self.assertEqual("localhost", Environment.Development.server) def test_server_for_sandbox(self): self.assertEqual("api.sandbox.braintreegateway.com", Environment.Sandbox.server) def test_server_for_production(self): self.assertEqual("api.braintreegateway.com", Environment.Production.server) def test_port_for_development(self): port = os.getenv("GATEWAY_PORT") or "3000" port = int(port) self.assertEqual(port, Environment.Development.port) def test_port_for_sandbox(self): self.assertEqual(443, Environment.Sandbox.port) def test_port_for_production(self): self.assertEqual(443, Environment.Production.port) def test_is_ssl_for_development(self): self.assertFalse(Environment.Development.is_ssl) def test_is_ssl_for_sandbox(self): self.assertTrue(Environment.Sandbox.is_ssl) def test_is_ssl_for_production(self): self.assertTrue(Environment.Production.is_ssl) def test_protocol_for_development(self): self.assertEqual("http://", Environment.Development.protocol) def test_protocol_for_sandbox(self): self.assertEqual("https://", Environment.Sandbox.protocol) def test_protocol_for_production(self): self.assertEqual("https://", Environment.Production.protocol) def test_ssl_certificate_for_development(self): self.assertEqual(None, Environment.Development.ssl_certificate) braintree_python-3.57.1/tests/unit/test_authorization_adjustment.py0000644000175000017500000000427613545202423024166 0ustar hlehlefrom tests.test_helper import * from datetime import datetime from braintree.authorization_adjustment import AuthorizationAdjustment class TestAuthorizationAdjustment(unittest.TestCase): def test_constructor(self): attributes = { "amount": "-20.00", "timestamp": datetime(2017, 7, 12, 1, 2, 3), "success": True, "processor_response_code": "1000", "processor_response_text": "Approved", } authorization_adjustment = AuthorizationAdjustment(attributes) self.assertEqual(authorization_adjustment.amount, Decimal("-20.00")) self.assertEqual(authorization_adjustment.timestamp, datetime(2017, 7, 12, 1, 2, 3)) self.assertEqual(authorization_adjustment.success, True) self.assertEqual(authorization_adjustment.processor_response_code, "1000") self.assertEqual(authorization_adjustment.processor_response_text, "Approved") def test_constructor_with_amount_as_None(self): attributes = { "amount": None, "timestamp": datetime(2017, 7, 12, 1, 2, 3), "success": True, "processor_response_code": "1000", } authorization_adjustment = AuthorizationAdjustment(attributes) self.assertEqual(authorization_adjustment.amount, None) self.assertEqual(authorization_adjustment.timestamp, datetime(2017, 7, 12, 1, 2, 3)) self.assertEqual(authorization_adjustment.success, True) self.assertEqual(authorization_adjustment.processor_response_code, "1000") def test_constructor_without_amount(self): attributes = { "timestamp": datetime(2017, 7, 12, 1, 2, 3), "success": True, "processor_response_code": "1000", "processor_response_text": "Approved", } authorization_adjustment = AuthorizationAdjustment(attributes) self.assertEqual(authorization_adjustment.timestamp, datetime(2017, 7, 12, 1, 2, 3)) self.assertEqual(authorization_adjustment.success, True) self.assertEqual(authorization_adjustment.processor_response_code, "1000") self.assertEqual(authorization_adjustment.processor_response_text, "Approved") braintree_python-3.57.1/tests/unit/test_payment_method_gateway.py0000644000175000017500000001513013545202423023555 0ustar hlehlefrom tests.test_helper import * from braintree.payment_method_gateway import PaymentMethodGateway if sys.version_info[0] == 2: from mock import MagicMock else: from unittest.mock import MagicMock class TestPaymentMethodGateway(unittest.TestCase): def test_create_signature(self): actual_signature = PaymentMethod.signature("create") expected_signature = [ "billing_address_id", "cardholder_name", "customer_id", "cvv", "device_data", "device_session_id", "expiration_date", "expiration_month", "expiration_year", "number", "payment_method_nonce", "paypal_refresh_token", "paypal_vault_without_upgrade", "token", { "billing_address": Address.create_signature()}, { "options": [ "fail_on_duplicate_payment_method", "make_default", "us_bank_account_verification_method", "verification_merchant_account_id", "verify_card", "verification_amount", "verification_account_type", { "adyen":[ "overwrite_brand", "selected_brand" ] }, { "paypal":[ "payee_email", "order_id", "custom_field", "description", "amount", { "shipping":[ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "customer_id", "extended_address", "first_name", "last_name", "locality", "postal_code", "region", "street_address" ] }, ] }, ] } ] self.assertEqual(expected_signature, actual_signature) def test_update_signature(self): actual_signature = PaymentMethod.update_signature() expected_signature = [ "billing_address_id", "cardholder_name", "cvv", "device_session_id", "expiration_date", "expiration_month", "expiration_year", "number", "token", "venmo_sdk_payment_method_code", "device_data", "fraud_merchant_id", "payment_method_nonce", { "options": [ "make_default", "us_bank_account_verification_method", "verify_card", "verification_amount", "verification_merchant_account_id", "verification_account_type", "venmo_sdk_session", { "adyen":[ "overwrite_brand", "selected_brand" ] } ] }, { "billing_address" : Address.update_signature() + [{"options": ["update_existing"]}] } ] self.assertEqual(expected_signature, actual_signature) def test_nonce_grant_params(self): """ We validate parameters to PaymentMethod.grant properly """ payment_method_gateway = PaymentMethodGateway(BraintreeGateway(None)) options = { "include_billing_postal_code": True } with self.assertRaises(ValueError): payment_method_gateway.grant("", options) with self.assertRaises(ValueError): payment_method_gateway.grant("\t", False) with self.assertRaises(ValueError): payment_method_gateway.grant(None, True) def test_nonce_revoke_params(self): payment_method_gateway = PaymentMethodGateway(BraintreeGateway(None)) with self.assertRaises(ValueError): payment_method_gateway.revoke("") with self.assertRaises(ValueError): payment_method_gateway.revoke("\t") with self.assertRaises(ValueError): payment_method_gateway.revoke(None) def test_delete_with_revoke_all_grants_value_as_true(self): payment_method_gateway, http_mock = self.setup_payment_method_gateway_and_mock_http() payment_method_gateway.delete("some_token", {"revoke_all_grants": True}) self.assertTrue("delete('/merchants/integration_merchant_id/payment_methods/any/some_token?revoke_all_grants=true')" in str(http_mock.mock_calls)) def test_delete_with_revoke_all_grants_value_as_false(self): payment_method_gateway, http_mock = self.setup_payment_method_gateway_and_mock_http() payment_method_gateway.delete("some_token", {"revoke_all_grants": False}) self.assertTrue("delete('/merchants/integration_merchant_id/payment_methods/any/some_token?revoke_all_grants=false')" in str(http_mock.mock_calls)) def test_delete_without_revoke_all_grants(self): payment_method_gateway, http_mock = self.setup_payment_method_gateway_and_mock_http() payment_method_gateway.delete("some_token") self.assertTrue("delete('/merchants/integration_merchant_id/payment_methods/any/some_token')" in str(http_mock.mock_calls)) def test_delete_with_invalid_keys_to_raise_error(self): payment_method_gateway, http_mock = self.setup_payment_method_gateway_and_mock_http() with self.assertRaises(KeyError): payment_method_gateway.delete("some_token", {"invalid_keys": False}) def setup_payment_method_gateway_and_mock_http(self): braintree_gateway = BraintreeGateway(Configuration.instantiate()) payment_method_gateway = PaymentMethodGateway(braintree_gateway) http_mock = MagicMock(name='config.http.delete') braintree_gateway.config.http = http_mock return payment_method_gateway, http_mock braintree_python-3.57.1/tests/unit/test_unknown_payment_method.py0000644000175000017500000000051313545202423023612 0ustar hlehlefrom tests.test_helper import * class TestUnknownPaymentMethod(unittest.TestCase): def test_image_url(self): unknown_payment_method = UnknownPaymentMethod("gateway", {"token": "TOKEN"}) self.assertEqual("https://assets.braintreegateway.com/payment_method_logo/unknown.png", unknown_payment_method.image_url()) braintree_python-3.57.1/tests/unit/test_subscription_search.py0000644000175000017500000000402013545202423023064 0ustar hlehlefrom tests.test_helper import * class TestSubscriptionSearch(unittest.TestCase): def test_billing_cycles_remaining_is_a_range_node(self): self.assertEqual(Search.RangeNodeBuilder, type(SubscriptionSearch.billing_cycles_remaining)) def test_created_at_is_a_range_node(self): self.assertEqual(Search.RangeNodeBuilder, type(SubscriptionSearch.created_at)) def test_days_past_due_is_a_range_node(self): self.assertEqual(Search.RangeNodeBuilder, type(SubscriptionSearch.days_past_due)) def test_id_is_a_text_node(self): self.assertEqual(Search.TextNodeBuilder, type(SubscriptionSearch.id)) def test_merchant_account_id_is_a_multiple_value_node(self): self.assertEqual(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.merchant_account_id)) def test_plan_id_is_a_multiple_value_or_text_node(self): self.assertEqual(Search.MultipleValueOrTextNodeBuilder, type(SubscriptionSearch.plan_id)) def test_price_is_a_range_node(self): self.assertEqual(Search.RangeNodeBuilder, type(SubscriptionSearch.price)) def test_status_is_a_multiple_value_node(self): self.assertEqual(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.status)) def test_in_trial_period_is_multiple_value_node(self): self.assertEqual(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.in_trial_period)) def test_status_whitelist(self): SubscriptionSearch.status.in_list( Subscription.Status.Active, Subscription.Status.Canceled, Subscription.Status.Expired, Subscription.Status.PastDue ) @raises(AttributeError) def test_status_not_in_whitelist(self): SubscriptionSearch.status.in_list( Subscription.Status.Active, Subscription.Status.Canceled, Subscription.Status.Expired, "not a status" ) def test_ids_is_a_multiple_value_node(self): self.assertEqual(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.ids)) braintree_python-3.57.1/tests/unit/test_address.py0000644000175000017500000000244513545202423020451 0ustar hlehlefrom tests.test_helper import * class TestAddress(unittest.TestCase): @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_create_raise_exception_with_bad_keys(self): Address.create({"customer_id": "12345", "bad_key": "value"}) @raises_with_regexp(KeyError, "'customer_id must be provided'") def test_create_raises_error_if_no_customer_id_given(self): Address.create({"country_name": "United States of America"}) @raises_with_regexp(KeyError, "'customer_id contains invalid characters'") def test_create_raises_key_error_if_given_invalid_customer_id(self): Address.create({"customer_id": "!@#$%"}) @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_update_raise_exception_with_bad_keys(self): Address.update("customer_id", "address_id", {"bad_key": "value"}) @raises(NotFoundError) def test_finding_address_with_empty_customer_id_raises_not_found_exception(self): Address.find(" ", "address_id") @raises(NotFoundError) def test_finding_address_with_none_customer_id_raises_not_found_exception(self): Address.find(None, "address_id") @raises(NotFoundError) def test_finding_address_with_empty_address_id_raises_not_found_exception(self): Address.find("customer_id", " ") braintree_python-3.57.1/tests/unit/test_error_result.py0000644000175000017500000000312513545202423021547 0ustar hlehlefrom tests.test_helper import * class TestErrorResult(unittest.TestCase): def test_it_initializes_params_and_errors(self): errors = { "scope": { "errors": [{"code": 123, "message": "something is invalid", "attribute": "something"}] } } result = ErrorResult("gateway", {"errors": errors, "params": "params", "message": "brief description"}) self.assertFalse(result.is_success) self.assertEqual("params", result.params) self.assertEqual(1, result.errors.size) self.assertEqual("something is invalid", result.errors.for_object("scope")[0].message) self.assertEqual("something", result.errors.for_object("scope")[0].attribute) self.assertEqual(123, result.errors.for_object("scope")[0].code) def test_it_ignores_other_params(self): errors = { "scope": { "errors": [{"code": 123, "message": "something is invalid", "attribute": "something"}] } } result = ErrorResult("gateway", {"errors": errors, "params": "params", "message": "brief description", "other": "stuff"}) self.assertFalse(result.is_success) def test_transaction_is_none_if_not_set(self): result = ErrorResult("gateway", {"errors": {}, "params": {}, "message": "brief description"}) self.assertTrue(result.transaction is None) def test_verification_is_none_if_not_set(self): result = ErrorResult("gateway", {"errors": {}, "params": {}, "message": "brief description"}) self.assertTrue(result.credit_card_verification is None) braintree_python-3.57.1/tests/unit/test_document_upload.py0000644000175000017500000000037113545202423022202 0ustar hlehlefrom tests.test_helper import * class TestDocumentUpload(unittest.TestCase): @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_create_raises_exception_with_bad_keys(self): DocumentUpload.create({"bad_key": "value"}) braintree_python-3.57.1/tests/unit/test_payment_method_nonce.py0000644000175000017500000000052313545202423023216 0ustar hlehlefrom tests.test_helper import * class TestPaymentMethodNonce(unittest.TestCase): @raises(NotFoundError) def test_finding_empty_id_raises_not_found_exception(self): PaymentMethodNonce.find(" ") @raises(NotFoundError) def test_finding_None_id_raises_not_found_exception(self): PaymentMethodNonce.find(None) braintree_python-3.57.1/tests/unit/test_risk_data.py0000644000175000017500000000103213545202423020754 0ustar hlehlefrom tests.test_helper import * from braintree import * class TestRiskData(unittest.TestCase): def test_initialization_of_attributes(self): risk_data = RiskData({"id": "123", "decision": "Unknown", "device_data_captured": True, "fraud_service_provider": "some_fraud_provider"}) self.assertEqual("123", risk_data.id) self.assertEqual("Unknown", risk_data.decision) self.assertEqual(True, risk_data.device_data_captured) self.assertEqual("some_fraud_provider", risk_data.fraud_service_provider) braintree_python-3.57.1/tests/unit/test_webhooks.py0000644000175000017500000010270613545202423020646 0ustar hlehlefrom tests.test_helper import * from datetime import date from braintree.dispute import Dispute from braintree.credit_card import CreditCard from braintree.paypal_account import PayPalAccount from braintree.venmo_account import VenmoAccount class TestWebhooks(unittest.TestCase): def test_sample_notification_builds_a_parsable_notification(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubscriptionWentPastDue, notification.kind) self.assertEqual("my_id", notification.subscription.id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) self.assertIsNone(notification.source_merchant_id) def test_sample_notification_with_source_merchant_id(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, 'my_id', 'my_source_merchant_id' ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual('my_source_merchant_id', notification.source_merchant_id) @raises(InvalidSignatureError) def test_completely_invalid_signature(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) WebhookNotification.parse("bad_stuff", sample_notification['bt_payload']) def test_parse_raises_when_public_key_is_wrong(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="wrong_public_key", private_key="wrong_private_key" ) gateway = BraintreeGateway(config) try: gateway.webhook_notification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) except InvalidSignatureError as e: self.assertEqual("no matching public key", str(e)) else: self.assertFalse("raises exception") def test_invalid_signature_when_payload_modified(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) try: WebhookNotification.parse(sample_notification['bt_signature'], b"badstuff" + sample_notification['bt_payload']) except InvalidSignatureError as e: self.assertEqual("signature does not match payload - one has been modified", str(e)) else: self.assertFalse("raises exception") def test_parse_raise_exception_if_signature_is_blank(self): try: WebhookNotification.parse(None, "payload") except InvalidSignatureError as e: self.assertEqual("signature cannot be blank", str(e)) else: self.assertFalse("raises exception") def test_parse_raise_exception_if_payload_is_blank(self): try: WebhookNotification.parse("signature", None) except InvalidSignatureError as e: self.assertEqual("payload cannot be blank", str(e)) else: self.assertFalse("raises exception") def test_invalid_signature_when_bontains_invalid_characters(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) try: WebhookNotification.parse(sample_notification['bt_signature'], "~* invalid! *~") except InvalidSignatureError as e: self.assertEqual("payload contains illegal characters", str(e)) else: self.assertFalse("raises exception") def test_parse_allows_all_valid_characters(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) try: WebhookNotification.parse(sample_notification['bt_signature'], "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+=/\n") except InvalidSignatureError as e: self.assertNotEqual("payload contains illegal characters", str(e)) def test_parse_retries_payload_with_a_newline(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload'].rstrip()) self.assertEqual(WebhookNotification.Kind.SubscriptionWentPastDue, notification.kind) self.assertEqual("my_id", notification.subscription.id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) def test_verify_returns_a_correct_challenge_response(self): response = WebhookNotification.verify("20f9f8ed05f77439fe955c977e4c8a53") self.assertEqual("integration_public_key|d9b899556c966b3f06945ec21311865d35df3ce4", response) def test_verify_raises_when_challenge_is_invalid(self): try: WebhookNotification.verify("bad challenge") except InvalidChallengeError as e: self.assertEqual("challenge contains non-hex characters", str(e)) else: self.assertFalse("raises exception") def test_builds_notification_for_approved_sub_merchant_account(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubMerchantAccountApproved, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubMerchantAccountApproved, notification.kind) self.assertEqual("my_id", notification.merchant_account.id) self.assertEqual(MerchantAccount.Status.Active, notification.merchant_account.status) self.assertEqual("master_ma_for_my_id", notification.merchant_account.master_merchant_account.id) self.assertEqual(MerchantAccount.Status.Active, notification.merchant_account.master_merchant_account.status) def test_builds_notification_for_declined_sub_merchant_account(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubMerchantAccountDeclined, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubMerchantAccountDeclined, notification.kind) self.assertEqual("my_id", notification.merchant_account.id) self.assertEqual(MerchantAccount.Status.Suspended, notification.merchant_account.status) self.assertEqual("master_ma_for_my_id", notification.merchant_account.master_merchant_account.id) self.assertEqual(MerchantAccount.Status.Suspended, notification.merchant_account.master_merchant_account.status) self.assertEqual("Credit score is too low", notification.message) self.assertEqual(ErrorCodes.MerchantAccount.DeclinedOFAC, notification.errors.for_object("merchant_account").on("base")[0].code) def test_builds_notification_for_disbursed_transactions(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.TransactionDisbursed, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.TransactionDisbursed, notification.kind) self.assertEqual("my_id", notification.transaction.id) self.assertEqual(100, notification.transaction.amount) self.assertEqual(datetime(2013, 7, 9, 18, 23, 29), notification.transaction.disbursement_details.disbursement_date) def test_builds_notification_for_settled_transactions(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.TransactionSettled, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.TransactionSettled, notification.kind) self.assertEqual("my_id", notification.transaction.id) self.assertEqual("settled", notification.transaction.status) self.assertEqual(100, notification.transaction.amount) self.assertEqual(notification.transaction.us_bank_account.routing_number, "123456789") self.assertEqual(notification.transaction.us_bank_account.last_4, "1234") self.assertEqual(notification.transaction.us_bank_account.account_type, "checking") self.assertEqual(notification.transaction.us_bank_account.account_holder_name, "Dan Schulman") def test_builds_notification_for_settlement_declined_transactions(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.TransactionSettlementDeclined, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.TransactionSettlementDeclined, notification.kind) self.assertEqual("my_id", notification.transaction.id) self.assertEqual("settlement_declined", notification.transaction.status) self.assertEqual(100, notification.transaction.amount) self.assertEqual(notification.transaction.us_bank_account.routing_number, "123456789") self.assertEqual(notification.transaction.us_bank_account.last_4, "1234") self.assertEqual(notification.transaction.us_bank_account.account_type, "checking") self.assertEqual(notification.transaction.us_bank_account.account_holder_name, "Dan Schulman") def test_builds_notification_for_disbursements(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.Disbursement, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.Disbursement, notification.kind) self.assertEqual("my_id", notification.disbursement.id) self.assertEqual(100, notification.disbursement.amount) self.assertEqual(None, notification.disbursement.exception_message) self.assertEqual(None, notification.disbursement.follow_up_action) self.assertEqual(date(2014, 2, 9), notification.disbursement.disbursement_date) def test_builds_notification_for_disbursement_exceptions(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisbursementException, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisbursementException, notification.kind) self.assertEqual("my_id", notification.disbursement.id) self.assertEqual(100, notification.disbursement.amount) self.assertEqual("bank_rejected", notification.disbursement.exception_message) self.assertEqual("update_funding_information", notification.disbursement.follow_up_action) self.assertEqual(date(2014, 2, 9), notification.disbursement.disbursement_date) def test_builds_notification_for_old_dispute_opened(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeOpened, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeOpened, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.Open, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) def test_builds_notification_for_old_dispute_lost(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeLost, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeLost, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.Lost, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) def test_builds_notification_for_old_dispute_won(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeWon, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeWon, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.Won, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) self.assertEqual(notification.dispute.date_won, date(2014, 9, 1)) def test_builds_notification_for_new_dispute_opened(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeOpened, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeOpened, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.Open, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) def test_builds_notification_for_new_dispute_lost(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeLost, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeLost, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.Lost, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) def test_builds_notification_for_new_dispute_won(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeWon, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeWon, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.Won, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) self.assertEqual(notification.dispute.date_won, date(2014, 9, 1)) def test_builds_notification_for_partner_merchant_connected(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.PartnerMerchantConnected, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.PartnerMerchantConnected, notification.kind) self.assertEqual("abc123", notification.partner_merchant.partner_merchant_id) self.assertEqual("public_key", notification.partner_merchant.public_key) self.assertEqual("private_key", notification.partner_merchant.private_key) self.assertEqual("public_id", notification.partner_merchant.merchant_public_id) self.assertEqual("cse_key", notification.partner_merchant.client_side_encryption_key) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) def test_builds_notification_for_partner_merchant_disconnected(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.PartnerMerchantDisconnected, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.PartnerMerchantDisconnected, notification.kind) self.assertEqual("abc123", notification.partner_merchant.partner_merchant_id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) def test_builds_notification_for_partner_merchant_declined(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.PartnerMerchantDeclined, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.PartnerMerchantDeclined, notification.kind) self.assertEqual("abc123", notification.partner_merchant.partner_merchant_id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) def test_builds_notification_for_oauth_access_revoked(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.OAuthAccessRevoked, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) self.assertEqual(WebhookNotification.Kind.OAuthAccessRevoked, notification.kind) self.assertEqual("my_id", notification.oauth_access_revocation.merchant_id) self.assertEqual("oauth_application_client_id", notification.oauth_access_revocation.oauth_application_client_id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) def test_builds_notification_for_connected_merchant_status_transitioned(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.ConnectedMerchantStatusTransitioned, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.ConnectedMerchantStatusTransitioned, notification.kind) self.assertEqual("new_status", notification.connected_merchant_status_transitioned.status) self.assertEqual("my_id", notification.connected_merchant_status_transitioned.merchant_public_id) self.assertEqual("my_id", notification.connected_merchant_status_transitioned.merchant_id) self.assertEqual("oauth_application_client_id", notification.connected_merchant_status_transitioned.oauth_application_client_id) def test_builds_notification_for_connected_merchant_paypal_status_changed(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.ConnectedMerchantPayPalStatusChanged, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.ConnectedMerchantPayPalStatusChanged, notification.kind) self.assertEqual("link", notification.connected_merchant_paypal_status_changed.action) self.assertEqual("my_id", notification.connected_merchant_paypal_status_changed.merchant_public_id) self.assertEqual("my_id", notification.connected_merchant_paypal_status_changed.merchant_id) self.assertEqual("oauth_application_client_id", notification.connected_merchant_paypal_status_changed.oauth_application_client_id) def test_builds_notification_for_subscription_charged_successfully(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionChargedSuccessfully, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubscriptionChargedSuccessfully, notification.kind) self.assertEqual("my_id", notification.subscription.id) self.assertTrue(len(notification.subscription.transactions) == 1) transaction = notification.subscription.transactions.pop() self.assertEqual("submitted_for_settlement", transaction.status) self.assertEqual(Decimal("49.99"), transaction.amount) def test_builds_notification_for_subscription_charged_unsuccessfully(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionChargedUnsuccessfully, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubscriptionChargedUnsuccessfully, notification.kind) self.assertEqual("my_id", notification.subscription.id) self.assertTrue(len(notification.subscription.transactions) == 1) transaction = notification.subscription.transactions.pop() self.assertEqual("failed", transaction.status) self.assertEqual(Decimal("49.99"), transaction.amount) def test_builds_notification_for_check(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.Check, "" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.Check, notification.kind) def test_builds_notification_for_account_updater_daily_report_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.AccountUpdaterDailyReport, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.AccountUpdaterDailyReport, notification.kind) self.assertEqual("link-to-csv-report", notification.account_updater_daily_report.report_url) self.assertEqual(date(2016, 1, 14), notification.account_updater_daily_report.report_date) def test_grantor_updated_granted_payment_method_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.GrantorUpdatedGrantedPaymentMethod, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) update = notification.granted_payment_instrument_update self.assertEqual(WebhookNotification.Kind.GrantorUpdatedGrantedPaymentMethod, notification.kind) self.assertEqual("vczo7jqrpwrsi2px", update.grant_owner_merchant_id) self.assertEqual("cf0i8wgarszuy6hc", update.grant_recipient_merchant_id) self.assertEqual("ee257d98-de40-47e8-96b3-a6954ea7a9a4", update.payment_method_nonce) self.assertEqual("abc123z", update.token) self.assertEqual(["expiration-month", "expiration-year"], update.updated_fields) def test_recipient_updated_granted_payment_method_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.RecipientUpdatedGrantedPaymentMethod, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) update = notification.granted_payment_instrument_update self.assertEqual(WebhookNotification.Kind.RecipientUpdatedGrantedPaymentMethod, notification.kind) self.assertEqual("vczo7jqrpwrsi2px", update.grant_owner_merchant_id) self.assertEqual("cf0i8wgarszuy6hc", update.grant_recipient_merchant_id) self.assertEqual("ee257d98-de40-47e8-96b3-a6954ea7a9a4", update.payment_method_nonce) self.assertEqual("abc123z", update.token) self.assertEqual(["expiration-month", "expiration-year"], update.updated_fields) def test_granted_payment_method_revoked_credit_card_webhook(self): xml_payload = """ 12345 2018-10-10T22:46:41Z granted_payment_method_revoked 555555 MasterCard Amber Ankunding Unknown Unknown 2018-10-10T22:46:41Z credit_card_customer_id US Unknown true Unknown 06 2020 false cGF5bWVudG1ldGhvZF8zcHQ2d2hz Unknown https://assets.braintreegateway.com/payment_method_logo/mastercard.png?environment=test Unknown 4444 Unknown Unknown Unknown credit_card_token 08199d188e37460163207f714faf074a 2018-10-10T22:46:41Z false """.encode("utf-8") sample_notification = TestHelper.sample_notification_from_xml(xml_payload) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) metadata = notification.revoked_payment_method_metadata self.assertEqual(WebhookNotification.Kind.GrantedPaymentMethodRevoked, notification.kind) self.assertEqual("credit_card_customer_id", metadata.customer_id) self.assertEqual("credit_card_token", metadata.token) self.assertTrue(isinstance(metadata.revoked_payment_method, CreditCard)) def test_granted_payment_method_revoked_paypal_account_webhook(self): xml_payload = """ 12345 2018-10-10T22:46:41Z granted_payment_method_revoked billing_agreement_id 2018-10-11T21:10:33Z paypal_customer_id true johndoe@example.com cGF5bWVudG1ldGhvZF9wYXlwYWxfdG9rZW4 https://assets.braintreegateway.com/payment_method_logo/mastercard.png?environment=test paypal_token 2018-10-11T21:10:33Z a6a8e1a4 """.encode("utf-8") sample_notification = TestHelper.sample_notification_from_xml(xml_payload) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) metadata = notification.revoked_payment_method_metadata self.assertEqual(WebhookNotification.Kind.GrantedPaymentMethodRevoked, notification.kind) self.assertEqual("paypal_customer_id", metadata.customer_id) self.assertEqual("paypal_token", metadata.token) self.assertTrue(isinstance(metadata.revoked_payment_method, PayPalAccount)) def test_granted_payment_method_revoked_venmo_account_webhook(self): xml_payload = """ 12345 2018-10-10T22:46:41Z granted_payment_method_revoked 2018-10-11T21:28:37Z 2018-10-11T21:28:37Z true https://assets.braintreegateway.com/payment_method_logo/mastercard.png?environment=test venmo_token Venmo Account: venmojoe venmojoe 456 venmo_customer_id cGF5bWVudG1ldGhvZF92ZW5tb2FjY291bnQ """.encode("utf-8") sample_notification = TestHelper.sample_notification_from_xml(xml_payload) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) metadata = notification.revoked_payment_method_metadata self.assertEqual(WebhookNotification.Kind.GrantedPaymentMethodRevoked, notification.kind) self.assertEqual("venmo_customer_id", metadata.customer_id) self.assertEqual("venmo_token", metadata.token) self.assertTrue(isinstance(metadata.revoked_payment_method, VenmoAccount)) def test_payment_method_revoked_by_customer_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.PaymentMethodRevokedByCustomer, "my_payment_method_token" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) metadata = notification.revoked_payment_method_metadata self.assertEqual(WebhookNotification.Kind.PaymentMethodRevokedByCustomer, notification.kind) self.assertEqual("my_payment_method_token", metadata.token) self.assertTrue(isinstance(metadata.revoked_payment_method, PayPalAccount)) self.assertNotEqual(None, metadata.revoked_payment_method.revoked_at) def test_local_payment_completed_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.LocalPaymentCompleted, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) local_payment_completed = notification.local_payment_completed self.assertEqual(WebhookNotification.Kind.LocalPaymentCompleted, notification.kind) self.assertEqual("a-payment-id", local_payment_completed.payment_id) self.assertEqual("a-payer-id", local_payment_completed.payer_id) self.assertEqual("ee257d98-de40-47e8-96b3-a6954ea7a9a4", local_payment_completed.payment_method_nonce) self.assertTrue(isinstance(local_payment_completed.transaction, Transaction)) braintree_python-3.57.1/tests/unit/test_exports.py0000644000175000017500000001062613545202423020530 0ustar hlehlefrom tests.test_helper import * import braintree class TestExports(unittest.TestCase): def test_exports_properties(self): self.assertNotEqual(braintree.AchMandate, None) self.assertNotEqual(braintree.AddOn, None) self.assertNotEqual(braintree.AddOnGateway, None) self.assertNotEqual(braintree.Address, None) self.assertNotEqual(braintree.AddressGateway, None) self.assertNotEqual(braintree.AmexExpressCheckoutCard, None) self.assertNotEqual(braintree.AndroidPayCard, None) self.assertNotEqual(braintree.ApplePayCard, None) self.assertNotEqual(braintree.BraintreeGateway, None) self.assertNotEqual(braintree.ClientToken, None) self.assertNotEqual(braintree.Configuration, None) self.assertNotEqual(braintree.CredentialsParser, None) self.assertNotEqual(braintree.CreditCard, None) self.assertNotEqual(braintree.CreditCardGateway, None) self.assertNotEqual(braintree.CreditCardVerification, None) self.assertNotEqual(braintree.CreditCardVerificationSearch, None) self.assertNotEqual(braintree.Customer, None) self.assertNotEqual(braintree.CustomerGateway, None) self.assertNotEqual(braintree.CustomerSearch, None) self.assertNotEqual(braintree.Descriptor, None) self.assertNotEqual(braintree.Disbursement, None) self.assertNotEqual(braintree.Discount, None) self.assertNotEqual(braintree.DiscountGateway, None) self.assertNotEqual(braintree.Environment, None) self.assertNotEqual(braintree.ErrorCodes, None) self.assertNotEqual(braintree.ErrorResult, None) self.assertNotEqual(braintree.Errors, None) self.assertNotEqual(braintree.EuropeBankAccount, None) # NEXT_MAJOR_VERSION Remove this class as legacy Ideal has been removed/disabled in the Braintree Gateway # DEPRECATED If you're looking to accept iDEAL as a payment method contact accounts@braintreepayments.com for a solution. self.assertNotEqual(braintree.IdealPayment, None) self.assertNotEqual(braintree.Merchant, None) self.assertNotEqual(braintree.MerchantAccount, None) self.assertNotEqual(braintree.MerchantAccountGateway, None) self.assertNotEqual(braintree.PartnerMerchant, None) self.assertNotEqual(braintree.PaymentInstrumentType, None) self.assertNotEqual(braintree.PaymentMethod, None) self.assertNotEqual(braintree.PaymentMethodNonce, None) self.assertNotEqual(braintree.PayPalAccount, None) self.assertNotEqual(braintree.Plan, None) self.assertNotEqual(braintree.PlanGateway, None) self.assertNotEqual(braintree.ResourceCollection, None) self.assertNotEqual(braintree.RiskData, None) self.assertNotEqual(braintree.Search, None) self.assertNotEqual(braintree.SettlementBatchSummary, None) self.assertNotEqual(braintree.SignatureService, None) self.assertNotEqual(braintree.StatusEvent, None) self.assertNotEqual(braintree.Subscription, None) self.assertNotEqual(braintree.SubscriptionGateway, None) self.assertNotEqual(braintree.SubscriptionSearch, None) self.assertNotEqual(braintree.SubscriptionStatusEvent, None) self.assertNotEqual(braintree.SuccessfulResult, None) self.assertNotEqual(braintree.TestingGateway, None) self.assertNotEqual(braintree.ThreeDSecureInfo, None) self.assertNotEqual(braintree.Transaction, None) self.assertNotEqual(braintree.TransactionAmounts, None) self.assertNotEqual(braintree.TransactionDetails, None) self.assertNotEqual(braintree.TransactionGateway, None) self.assertNotEqual(braintree.TransactionSearch, None) self.assertNotEqual(braintree.TransparentRedirect, None) self.assertNotEqual(braintree.TransparentRedirectGateway, None) self.assertNotEqual(braintree.UnknownPaymentMethod, None) self.assertNotEqual(braintree.UsBankAccount, None) self.assertNotEqual(braintree.ValidationErrorCollection, None) self.assertNotEqual(braintree.VenmoAccount, None) self.assertNotEqual(braintree.Version, None) self.assertNotEqual(braintree.WebhookNotification, None) self.assertNotEqual(braintree.WebhookNotificationGateway, None) self.assertNotEqual(braintree.WebhookTesting, None) self.assertNotEqual(braintree.WebhookTestingGateway, None) braintree_python-3.57.1/tests/unit/test_customer.py0000644000175000017500000000355113545202423020664 0ustar hlehlefrom tests.test_helper import * class TestCustomer(unittest.TestCase): @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_create_raise_exception_with_bad_keys(self): Customer.create({"bad_key": "value"}) @raises_with_regexp(KeyError, "'Invalid keys: credit_card\[bad_key\]'") def test_create_raise_exception_with_bad_nested_keys(self): Customer.create({"credit_card": {"bad_key": "value"}}) @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_update_raise_exception_with_bad_keys(self): Customer.update("id", {"bad_key": "value"}) @raises_with_regexp(KeyError, "'Invalid keys: credit_card\[bad_key\]'") def test_update_raise_exception_with_bad_nested_keys(self): Customer.update("id", {"credit_card": {"bad_key": "value"}}) @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_tr_data_for_create_raises_error_with_bad_keys(self): Customer.tr_data_for_create({"bad_key": "value"}, "http://example.com") @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_tr_data_for_update_raises_error_with_bad_keys(self): Customer.tr_data_for_update({"bad_key": "value"}, "http://example.com") @raises(NotFoundError) def test_finding_empty_id_raises_not_found_exception(self): Customer.find(" ") @raises(NotFoundError) def test_finding_none_raises_not_found_exception(self): Customer.find(None) def test_initialize_sets_paypal_accounts(self): customer = Customer("gateway", { "paypal_accounts": [ {"token": "token1"}, {"token": "token2"} ] }) self.assertEqual(2, len(customer.paypal_accounts)) self.assertEqual("token1", customer.paypal_accounts[0].token) self.assertEqual("token2", customer.paypal_accounts[1].token) braintree_python-3.57.1/tests/unit/test_client_token.py0000644000175000017500000000135013545202423021474 0ustar hlehlefrom tests.test_helper import * class TestClientToken(unittest.TestCase): def test_credit_card_options_require_customer_id(self): for option in ["verify_card", "make_default", "fail_on_duplicate_payment_method"]: with self.assertRaisesRegexp(InvalidSignatureError, option): ClientToken.generate({ "options": {option: True} }) def test_generate_delegates_client_token_generation_to_gateway(self): class MockGateway: def generate(self, _): return "mock_client_token" mock_gateway = MockGateway() client_token = ClientToken.generate({}, mock_gateway) self.assertEqual("mock_client_token", client_token) braintree_python-3.57.1/tests/unit/test_transaction.py0000644000175000017500000002306013545202423021345 0ustar hlehlefrom tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers from datetime import datetime from datetime import date from braintree.authorization_adjustment import AuthorizationAdjustment if sys.version_info[0] == 2: from mock import MagicMock else: from unittest.mock import MagicMock class TestTransaction(unittest.TestCase): @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_clone_transaction_raises_exception_with_bad_keys(self): Transaction.clone_transaction("an id", {"bad_key": "value"}) @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_sale_raises_exception_with_bad_keys(self): Transaction.sale({"bad_key": "value"}) @raises_with_regexp(KeyError, "'Invalid keys: credit_card\[bad_key\]'") def test_sale_raises_exception_with_nested_bad_keys(self): Transaction.sale({"credit_card": {"bad_key": "value"}}) @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_tr_data_for_sale_raises_error_with_bad_keys(self): Transaction.tr_data_for_sale({"bad_key": "value"}, "http://example.com") @raises(NotFoundError) def test_finding_empty_id_raises_not_found_exception(self): Transaction.find(" ") @raises(NotFoundError) def test_finding_none_raises_not_found_exception(self): Transaction.find(None) def test_constructor_includes_disbursement_information(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'order_id': '106601', 'channel': '101', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', 'disbursement_details': { 'settlement_amount': '27.00', 'settlement_currency_iso_code': 'USD', 'settlement_currency_exchange_rate': '1', 'disbursement_date': date(2013, 4, 10), 'funds_held': False } } transaction = Transaction(None, attributes) self.assertEqual(transaction.disbursement_details.settlement_amount, Decimal('27.00')) self.assertEqual(transaction.disbursement_details.settlement_currency_iso_code, 'USD') self.assertEqual(transaction.disbursement_details.settlement_currency_exchange_rate, Decimal('1')) self.assertEqual(transaction.disbursement_details.disbursement_date, date(2013, 4, 10)) self.assertEqual(transaction.disbursement_details.funds_held, False) self.assertEqual(transaction.is_disbursed, True) def test_transaction_handles_nil_risk_data(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'order_id': '106601', 'channel': '101', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', } transaction = Transaction(None, attributes) self.assertEqual(transaction.risk_data, None) def test_is_disbursed_false(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'order_id': '106601', 'channel': '101', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', 'disbursement_details': { 'settlement_amount': None, 'settlement_currency_iso_code': None, 'settlement_currency_exchange_rate': None, 'disbursement_date': None, 'funds_held': None, } } transaction = Transaction(None, attributes) self.assertEqual(transaction.is_disbursed, False) def test_sale_with_skip_advanced_fraud_checking_value_as_true(self): attributes = { "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "skip_advanced_fraud_checking": True } } transaction_gateway = self.setup_transaction_gateway_and_mock_post() transaction_gateway.sale(attributes) transaction_param = transaction_gateway._post.call_args[0][1] self.assertTrue(transaction_param['transaction']['options']['skip_advanced_fraud_checking']) def test_sale_with_skip_advanced_fraud_checking_value_as_false(self): attributes = { "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "skip_advanced_fraud_checking": False } } transaction_gateway = self.setup_transaction_gateway_and_mock_post() transaction_gateway.sale(attributes) transaction_param = transaction_gateway._post.call_args[0][1] self.assertFalse(transaction_param['transaction']['options']['skip_advanced_fraud_checking']) def test_sale_without_skip_advanced_fraud_checking_value_option(self): attributes = { "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } } transaction_gateway = self.setup_transaction_gateway_and_mock_post() transaction_gateway.sale(attributes) transaction_param = transaction_gateway._post.call_args[0][1] self.assertTrue('skip_advanced_fraud_checking' not in transaction_param['transaction']['options']) def setup_transaction_gateway_and_mock_post(self): transaction_gateway = TransactionGateway(BraintreeGateway(None)) transaction_gateway._post = MagicMock(name='config.http.post') return transaction_gateway def test_ideal_payment_details(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'ideal_payment': { 'ideal_payment_id': 'idealpayment_abc_123', 'masked_iban': '12************7890', 'bic': 'RABONL2U', 'image_url': 'http://www.example.com/ideal.png', }, } transaction = Transaction(None, attributes) self.assertEqual(transaction.ideal_payment_details.ideal_payment_id, 'idealpayment_abc_123') self.assertEqual(transaction.ideal_payment_details.masked_iban, '12************7890') self.assertEqual(transaction.ideal_payment_details.bic, 'RABONL2U') self.assertEqual(transaction.ideal_payment_details.image_url, 'http://www.example.com/ideal.png') def test_constructor_doesnt_includes_auth_adjustments(self): attributes = { 'amount': '27.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', 'tax_amount': '1.00', } transaction = Transaction(None, attributes) self.assertFalse(hasattr(transaction, 'authorization_adjustments')) def test_constructor_includes_auth_adjustments(self): attributes = { 'amount': '27.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', 'tax_amount': '1.00', 'authorization_adjustments': [{ "amount": "20.00", "timestamp": datetime(2017, 7, 12, 1, 2, 3), "success": True, "processor_response_code": "1000", "processor_response_text": "Approved", }], } transaction = Transaction(None, attributes) transaction_adjustment = transaction.authorization_adjustments[0] self.assertEqual(transaction_adjustment.amount, Decimal("20.00")) self.assertEqual(transaction_adjustment.timestamp, datetime(2017, 7, 12, 1, 2, 3)) self.assertEqual(transaction_adjustment.success, True) self.assertEqual(transaction_adjustment.processor_response_code, "1000") self.assertEqual(transaction_adjustment.processor_response_text, "Approved") def test_constructor_includes_network_transaction_id(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'network_transaction_id': '123456789012345' } transaction = Transaction(None, attributes) self.assertEqual(transaction.network_transaction_id, "123456789012345") def test_constructor_includes_network_transaction_id(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'network_response_code': '00', 'network_response_text': 'Successful approval/completion or V.I.P. PIN verification is successful' } transaction = Transaction(None, attributes) self.assertEqual(transaction.network_response_code, "00") self.assertEqual(transaction.network_response_text, "Successful approval/completion or V.I.P. PIN verification is successful") braintree_python-3.57.1/tests/unit/test_search.py0000644000175000017500000001253613545202423020273 0ustar hlehlefrom tests.test_helper import * class TestSearch(unittest.TestCase): def test_text_node_is(self): node = Search.TextNodeBuilder("name") self.assertEqual({"is": "value"}, (node == "value").to_param()) def test_text_node_is_not(self): node = Search.TextNodeBuilder("name") self.assertEqual({"is_not": "value"}, (node != "value").to_param()) def test_text_node_starts_with(self): node = Search.TextNodeBuilder("name") self.assertEqual({"starts_with": "value"}, (node.starts_with("value")).to_param()) def test_text_node_ends_with(self): node = Search.TextNodeBuilder("name") self.assertEqual({"ends_with": "value"}, (node.ends_with("value")).to_param()) def test_text_node_contains(self): node = Search.TextNodeBuilder("name") self.assertEqual({"contains": "value"}, (node.contains("value")).to_param()) def test_multiple_value_node_in_list(self): node = Search.MultipleValueNodeBuilder("name") self.assertEqual(["value1", "value2"], (node.in_list(["value1", "value2"])).to_param()) def test_multiple_value_node_in_list_as_arg_list(self): node = Search.MultipleValueNodeBuilder("name") self.assertEqual(["value1", "value2"], (node.in_list("value1", "value2")).to_param()) def test_multiple_value_node_is(self): node = Search.MultipleValueNodeBuilder("name") self.assertEqual(["value1"], (node == "value1").to_param()) def test_multiple_value_node_with_value_in_whitelist(self): node = Search.MultipleValueNodeBuilder("name", ["okay"]) self.assertEqual(["okay"], (node == "okay").to_param()) @raises(AttributeError) def test_multiple_value_node_with_value_not_in_whitelist(self): node = Search.MultipleValueNodeBuilder("name", ["okay", "also okay"]) node == "not okay" def test_multiple_value_or_text_node_is(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual({"is": "value"}, (node == "value").to_param()) def test_multiple_value_or_text_node_is_not(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual({"is_not": "value"}, (node != "value").to_param()) def test_multiple_value_or_text_node_starts_with(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual({"starts_with": "value"}, (node.starts_with("value")).to_param()) def test_multiple_value_or_text_node_ends_with(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual({"ends_with": "value"}, (node.ends_with("value")).to_param()) def test_multiple_value_or_text_node_contains(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual({"contains": "value"}, (node.contains("value")).to_param()) def test_multiple_value_or_text_node_in_list(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual(["value1", "value2"], (node.in_list(["value1", "value2"])).to_param()) def test_multiple_value_or_text_node_in_list_as_arg_list(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual(["value1", "value2"], (node.in_list("value1", "value2")).to_param()) def test_multiple_value_or_text_node_with_value_in_whitelist(self): node = Search.MultipleValueOrTextNodeBuilder("name", ["okay"]) self.assertEqual(["okay"], node.in_list("okay").to_param()) @raises(AttributeError) def test_multiple_value_or_text_node_with_value_not_in_whitelist(self): node = Search.MultipleValueOrTextNodeBuilder("name", ["okay"]) node.in_list("not okay").to_param() def test_range_node_min_ge(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"min": "value"}, (node >= "value").to_param()) def test_range_node_min_greater_than_or_equal_to(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"min": "value"}, (node.greater_than_or_equal_to("value")).to_param()) def test_range_node_max_le(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"max": "value"}, (node <= "value").to_param()) def test_range_node_max_less_than_or_equal_to(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"max": "value"}, (node.less_than_or_equal_to("value")).to_param()) def test_range_node_between(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"min": "min_value", "max": "max_value"}, (node.between("min_value", "max_value")).to_param()) def test_range_node_is(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"is": "value"}, (node == "value").to_param()) def test_key_value_node_is_eq(self): node = Search.KeyValueNodeBuilder("name") self.assertTrue((node == True).to_param()) def test_key_value_node_is_equal(self): node = Search.KeyValueNodeBuilder("name") self.assertEqual(True, (node.is_equal(True)).to_param()) def test_key_value_node_is_not_equal(self): node = Search.KeyValueNodeBuilder("name") self.assertEqual(False, (node.is_not_equal(True)).to_param()) def test_key_value_node_symbols_is_not_equal(self): node = Search.KeyValueNodeBuilder("name") self.assertEqual(False, (node != True).to_param()) braintree_python-3.57.1/tests/unit/test_us_bank_account_verification.py0000644000175000017500000000266613545202423024731 0ustar hlehlefrom datetime import datetime from tests.test_helper import * from braintree.us_bank_account_verification import UsBankAccountVerification class TestUsBankAccountVerification(unittest.TestCase): @raises(NotFoundError) def test_finding_empty_id_raises_not_found_exception(self): UsBankAccountVerification.find(" ") @raises(NotFoundError) def test_finding_none_raises_not_found_exception(self): UsBankAccountVerification.find(None) def test_attributes(self): attributes = { "id": "my_favorite_id", "status": "verified", "verification_method": "independent_check", "verification_determined_at": datetime(2018, 11, 11, 23, 59, 59), "us_bank_account": { "token": "abc123", "last_4": 9999, } } verification = UsBankAccountVerification({}, attributes) self.assertEqual(verification.id, "my_favorite_id") self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_determined_at, datetime(2018, 11, 11, 23, 59, 59)) self.assertEqual( verification.verification_method, UsBankAccountVerification.VerificationMethod.IndependentCheck ) self.assertEqual(verification.us_bank_account.token, "abc123") self.assertEqual(verification.us_bank_account.last_4, 9999) braintree_python-3.57.1/tests/unit/test_paginated_collection.py0000644000175000017500000000301113545202423023161 0ustar hlehlefrom tests.test_helper import * from braintree.paginated_collection import PaginatedCollection from braintree.paginated_result import PaginatedResult class TestPaginatedCollection(unittest.TestCase): def test_fetches_once_when_page_and_total_sizes_match(self): def paging_function(current_page): if current_page > 1: raise "too many pages fetched" else: return PaginatedResult(1, 1, [1]) collection = PaginatedCollection(paging_function) items = [i for i in collection.items] self.assertEqual(1, len(items)) def test_fetches_collections_less_than_one_page(self): def paging_function(current_page): if current_page > 1: raise "too many pages fetched" else: return PaginatedResult(2, 5, [1, 2]) collection = PaginatedCollection(paging_function) items = [i for i in collection.items] self.assertEqual(2, len(items)) self.assertEqual(1, items[0]) self.assertEqual(2, items[1]) def test_fetches_multiple_pages(self): def paging_function(current_page): if current_page > 2: raise "too many pages fetched" else: return PaginatedResult(2, 1, [current_page]) collection = PaginatedCollection(paging_function) items = [i for i in collection.items] self.assertEqual(2, len(items)) self.assertEqual(1, items[0]) self.assertEqual(2, items[1]) braintree_python-3.57.1/tests/unit/__init__.py0000644000175000017500000000000013545202423017505 0ustar hlehlebraintree_python-3.57.1/tests/unit/test_us_bank_account.py0000644000175000017500000000417113545202423022160 0ustar hlehlefrom tests.test_helper import * from datetime import date from braintree.us_bank_account import UsBankAccount from braintree.us_bank_account_verification import UsBankAccountVerification class TestUsBankAccount(unittest.TestCase): def test_constructor(self): attributes = { "last_four": "1234", "routing_number": "55555", "account_type": "fake-account", "account_holder_name": "John Doe", "token": "7777-7777", "image_url": "some.png", "bank_name": "Chase", "ach_mandate": None, } us_bank_account = UsBankAccount({}, attributes) self.assertEqual(us_bank_account.last_four, "1234") self.assertEqual(us_bank_account.routing_number, "55555") self.assertEqual(us_bank_account.account_type, "fake-account") self.assertEqual(us_bank_account.account_holder_name, "John Doe") self.assertEqual(us_bank_account.token, "7777-7777") self.assertEqual(us_bank_account.image_url, "some.png") self.assertEqual(us_bank_account.bank_name, "Chase") self.assertEqual(us_bank_account.ach_mandate, None) attributes["ach_mandate"] = {"text":"Some mandate", "accepted_at": date(2013, 4, 10)} us_bank_account_mandated = UsBankAccount({}, attributes) self.assertEqual(us_bank_account_mandated.ach_mandate.text, "Some mandate") self.assertEqual(us_bank_account_mandated.ach_mandate.accepted_at, date(2013, 4, 10)) def test_converts_verifications_to_objects(self): attributes = { "verifications": [ { "status": "verified", "verification_method": "network_check", }, ], } us_bank_account = UsBankAccount({}, attributes) self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.NetworkCheck) braintree_python-3.57.1/tests/unit/test_signature_service.py0000644000175000017500000000070513545202423022542 0ustar hlehlefrom tests.test_helper import * class FakeDigest(object): @staticmethod def hmac_hash(key, data): return "%s_signed_with_%s" % (data, key) class TestSignatureService(unittest.TestCase): def test_hashes_with_digest(self): signature_service = SignatureService("fake_key", FakeDigest.hmac_hash) signed = signature_service.sign({"foo": "bar"}) self.assertEqual("foo=bar_signed_with_fake_key|foo=bar", signed) braintree_python-3.57.1/tests/unit/test_credit_card.py0000644000175000017500000001140013545202423021256 0ustar hlehlefrom tests.test_helper import * import datetime class TestCreditCard(unittest.TestCase): @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_create_raises_exception_with_bad_keys(self): CreditCard.create({"bad_key": "value"}) @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_update_raises_exception_with_bad_keys(self): CreditCard.update("token", {"bad_key": "value"}) @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_tr_data_for_create_raises_error_with_bad_keys(self): CreditCard.tr_data_for_create({"bad_key": "value"}, "http://example.com") @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_tr_data_for_update_raises_error_with_bad_keys(self): CreditCard.tr_data_for_update({"bad_key": "value"}, "http://example.com") def test_transparent_redirect_create_url(self): port = os.getenv("GATEWAY_PORT") or "3000" self.assertEqual( "http://localhost:" + port + "/merchants/integration_merchant_id/payment_methods/all/create_via_transparent_redirect_request", CreditCard.transparent_redirect_create_url() ) def test_transparent_redirect_update_url(self): port = os.getenv("GATEWAY_PORT") or "3000" self.assertEqual( "http://localhost:" + port + "/merchants/integration_merchant_id/payment_methods/all/update_via_transparent_redirect_request", CreditCard.transparent_redirect_update_url() ) @raises(DownForMaintenanceError) def test_confirm_transaprant_redirect_raises_error_given_503_status_in_query_string(self): CreditCard.confirm_transparent_redirect( "http_status=503&id=6kdj469tw7yck32j&hash=1b3d29199a282e63074a7823b76bccacdf732da6" ) def test_create_signature(self): expected = ["billing_address_id", "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", "device_session_id", "fraud_merchant_id", "number", "token", "venmo_sdk_payment_method_code", "device_data", "payment_method_nonce", { "billing_address": [ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "first_name", "last_name", "locality", "postal_code", "region", "street_address" ] }, {"options": ["make_default", "verification_merchant_account_id", "verify_card", "verification_amount", "verification_account_type", "venmo_sdk_session", "fail_on_duplicate_payment_method", {"adyen":["overwrite_brand", "selected_brand"]} ]}, "customer_id" ] self.assertEqual(expected, CreditCard.create_signature()) def test_update_signature(self): expected = ["billing_address_id", "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", "device_session_id", "fraud_merchant_id", "number", "token", "venmo_sdk_payment_method_code", "device_data", "payment_method_nonce", { "billing_address": [ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "first_name", "last_name", "locality", "postal_code", "region", "street_address", {"options": ["update_existing"]} ] }, {"options": ["make_default", "verification_merchant_account_id", "verify_card", "verification_amount", "verification_account_type", "venmo_sdk_session", "fail_on_duplicate_payment_method", {"adyen":["overwrite_brand", "selected_brand"]} ]} ] self.assertEqual(expected, CreditCard.update_signature()) @raises(NotFoundError) def test_finding_empty_id_raises_not_found_exception(self): CreditCard.find(" ") @raises(NotFoundError) def test_finding_none_raises_not_found_exception(self): CreditCard.find(None) @raises(NotFoundError) def test_from_nonce_empty_id_raises_not_found_exception(self): CreditCard.from_nonce(" ") @raises(NotFoundError) def test_from_nonce_none_raises_not_found_exception(self): CreditCard.from_nonce(None) def test_multiple_verifications_sort(self): verification1 = {"created_at": datetime.datetime(2014, 11, 18, 23, 20, 20), "id": 123, "amount": "0.00"} verification2 = {"created_at": datetime.datetime(2014, 11, 18, 23, 20, 21), "id": 456, "amount": "1.00"} credit_card = CreditCard(Configuration.gateway(), {"verifications": [verification1, verification2]}) self.assertEqual(456, credit_card.verification.id) self.assertEqual(1.00, credit_card.verification.amount) braintree_python-3.57.1/tests/unit/test_resource.py0000644000175000017500000000634613545202423020657 0ustar hlehlefrom tests.test_helper import * from braintree.resource import Resource class TestResource(unittest.TestCase): def test_verify_keys_allows_wildcard_keys(self): signature = [ {"foo": [{"bar": ["__any_key__"]}]} ] params = { "foo[bar][lower]": "lowercase", "foo[bar][UPPER]": "uppercase", "foo[bar][123]": "numeric", "foo[bar][under_scores]": "underscores", "foo[bar][dash-es]": "dashes", "foo[bar][ABC-abc_123]": "all together" } Resource.verify_keys(params, signature) @raises(KeyError) def test_verify_keys_escapes_brackets_in_signature(self): signature = [ {"customer": [{"custom_fields": ["__any_key__"]}]} ] params = { "customer_id": "value", } Resource.verify_keys(params, signature) def test_verify_keys_works_with_array_param(self): signature = [ {"customer": ["one", "two"]} ] params = { "customer": { "one": "foo" } } Resource.verify_keys(params, signature) @raises(KeyError) def test_verify_keys_raises_on_bad_array_param(self): signature = [ {"customer": ["one", "two"]} ] params = { "customer": { "invalid": "foo" } } Resource.verify_keys(params, signature) def test_verify_keys_works_with_arrays(self): signature = [ {"add_ons": [{"update": ["existing_id", "quantity"]}]} ] params = { "add_ons": { "update": [ { "existing_id": "foo", "quantity": 10 } ] } } Resource.verify_keys(params, signature) @raises(KeyError) def test_verify_keys_raises_with_invalid_param_in_arrays(self): signature = [ {"add_ons": [{"update": ["existing_id", "quantity"]}]} ] params = { "add_ons": { "update": [ { "invalid": "foo", "quantity": 10 } ] } } Resource.verify_keys(params, signature) def test_verify_keys_allows_text(self): text_string = u"text_string" assert isinstance(text_string, TestHelper.text_type) signature = [ {"customer": [{"custom_fields": [text_string]}]} ] params = { "customer": { "custom_fields": { text_string : text_string } } } Resource.verify_keys(params, signature) def test_verify_keys_allows_raw_data(self): raw_string = str.encode("raw_string") assert isinstance(raw_string, TestHelper.raw_type) signature = [ {"customer": [{"custom_fields": [raw_string]}]} ] params = { "customer": { "custom_fields": { raw_string : raw_string } } } Resource.verify_keys(params, signature) braintree_python-3.57.1/tests/unit/test_xml_util.py0000644000175000017500000001405213545202423020656 0ustar hlehlefrom tests.test_helper import * class TestXmlUtil(unittest.TestCase): def test_dict_from_xml_simple(self): xml = """ val """ expected = {"container": "val"} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_typecasts_ints(self): xml = """ 1 """ expected = {"container": 1} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_typecasts_nils(self): xml = """ """ expected = {"root": {"a_nil_value": None, "an_empty_string": ""}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_typecasts_booleans(self): xml = """ true 1 false anything true """ expected = { "root": { "casted_true": True, "casted_one": True, "casted_false": False, "casted_anything": False, "uncasted_true": "true" } } self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_typecasts_datetimes(self): xml = """ 2009-10-28T10:19:49Z """ expected = {"root": {"created_at": datetime(2009, 10, 28, 10, 19, 49)}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_with_dashes(self): xml = """ val """ expected = {"my_item": "val"} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_nested(self): xml = """ val """ expected = {"container": {"elem": "val"}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_array(self): xml = """ val1 val2 val3 """ expected = {"container": {"elements": ["val1", "val2", "val3"]}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_with_empty_array(self): xml = """ """ expected = {"container": {"elements": []}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_array_of_hashes(self): xml = """ val1 val2 val3 """ expected = {"container": {"elements": [{"val": "val1"}, {"val": "val2"}, {"val": "val3"}]}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_xml_from_dict_escapes_keys_and_values(self): test_dict = {"kva&lue", XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_simple(self): test_dict = {"a": "b"} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_with_integer(self): test_dict = {"a": 1} self.assertEqual('1', XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_with_long(self): test_dict = {"a": 12341234123412341234} self.assertEqual('12341234123412341234', XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_with_boolean(self): test_dict = {"a": True} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_simple_xml_and_back_twice(self): test_dict = {"a": "b"} self.assertEqual(test_dict, self.__xml_and_back(self.__xml_and_back(test_dict))) def test_xml_from_dict_nested(self): test_dict = {"container": {"item": "val"}} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_with_array(self): test_dict = {"container": {"elements": ["val1", "val2", "val3"]}} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_with_array_of_hashes(self): test_dict = {"container": {"elements": [{"val": "val1"}, {"val": "val2"}, {"val": "val3"}]}} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_retains_underscores(self): test_dict = {"container": {"my_element": "val"}} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_escapes_special_chars(self): test_dict = {"container": {"element": "<&>'\""}} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_with_datetime(self): test_dict = {"a": datetime(2010, 1, 2, 3, 4, 5)} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_with_unicode_characters(self): test_dict = {"a": u"\u1f61hat?"} self.assertEqual('ὡhat?', XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_with_dates_formats_as_datetime(self): test_dict = {"a": date(2010, 1, 2)} self.assertEqual('2010-01-02T00:00:00Z', XmlUtil.xml_from_dict(test_dict)) @staticmethod def __xml_and_back(test_dict): return XmlUtil.dict_from_xml(XmlUtil.xml_from_dict(test_dict)) braintree_python-3.57.1/tests/unit/test_oauth_access_revocation.py0000644000175000017500000000042513545202423023712 0ustar hlehlefrom tests.test_helper import * import datetime class TestOAuthAccessRevocation(unittest.TestCase): def test_assigns_merchant_id(self): revocation = OAuthAccessRevocation({"merchant_id": "abc123xyz"}) self.assertEqual(revocation.merchant_id, "abc123xyz") braintree_python-3.57.1/tests/unit/test_merchant_account.py0000644000175000017500000000553613545202423022345 0ustar hlehlefrom tests.test_helper import * class TestMerchantAccount(unittest.TestCase): def test_create_new_merchant_account_with_all_params(self): params = { "id": "sub_merchant_account", "status": "active", "master_merchant_account": { "id": "master_merchant_account", "status": "active" }, "individual": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "date_of_birth": "1970-01-01", "phone": "3125551234", "ssn_last_4": "6789", "address": { "street_address": "123 Fake St", "locality": "Chicago", "region": "IL", "postal_code": "60622", } }, "business": { "dba_name": "James's Bloggs", "tax_id": "123456789", }, "funding": { "account_number_last_4": "8798", "routing_number": "071000013", "descriptor": "Joes Bloggs MI", } } merchant_account = MerchantAccount(None, params) self.assertEqual(merchant_account.status, "active") self.assertEqual(merchant_account.id, "sub_merchant_account") self.assertEqual(merchant_account.master_merchant_account.id, "master_merchant_account") self.assertEqual(merchant_account.master_merchant_account.status, "active") self.assertEqual(merchant_account.individual_details.first_name, "John") self.assertEqual(merchant_account.individual_details.last_name, "Doe") self.assertEqual(merchant_account.individual_details.email, "john.doe@example.com") self.assertEqual(merchant_account.individual_details.date_of_birth, "1970-01-01") self.assertEqual(merchant_account.individual_details.phone, "3125551234") self.assertEqual(merchant_account.individual_details.ssn_last_4, "6789") self.assertEqual(merchant_account.individual_details.address_details.street_address, "123 Fake St") self.assertEqual(merchant_account.individual_details.address_details.locality, "Chicago") self.assertEqual(merchant_account.individual_details.address_details.region, "IL") self.assertEqual(merchant_account.individual_details.address_details.postal_code, "60622") self.assertEqual(merchant_account.business_details.dba_name, "James's Bloggs") self.assertEqual(merchant_account.business_details.tax_id, "123456789") self.assertEqual(merchant_account.funding_details.account_number_last_4, "8798") self.assertEqual(merchant_account.funding_details.routing_number, "071000013") self.assertEqual(merchant_account.funding_details.descriptor, "Joes Bloggs MI") braintree_python-3.57.1/tests/unit/test_disbursement.py0000644000175000017500000000265313545202423021531 0ustar hlehlefrom tests.test_helper import * from datetime import date class TestDisbursement(unittest.TestCase): attributes = { "merchant_account": { "id": "sub_merchant_account", "status": "active", "master_merchant_account": { "id": "master_merchant_account", "status": "active" }, }, "id": "123456", "exception_message": "invalid_account_number", "amount": "100.00", "disbursement_date": date(2013, 4, 10), "follow_up_action": "update", "transaction_ids": ["asdf", "qwer"], "disbursement_type": "credit" } def test_constructor(self): disbursement = Disbursement(None, TestDisbursement.attributes) self.assertEqual("123456", disbursement.id) self.assertEqual(Decimal("100.00"), disbursement.amount) self.assertEqual(["asdf", "qwer"], disbursement.transaction_ids) self.assertEqual("master_merchant_account", disbursement.merchant_account.master_merchant_account.id) def test_credit(self): disbursement = Disbursement(None, TestDisbursement.attributes) self.assertTrue(disbursement.is_credit()) def test_debit(self): thing = TestDisbursement.attributes thing["disbursement_type"] = "debit" disbursement = Disbursement(None, TestDisbursement.attributes) self.assertTrue(disbursement.is_debit()) braintree_python-3.57.1/tests/unit/test_subscription.py0000644000175000017500000000123313545202423021542 0ustar hlehlefrom tests.test_helper import * class TestSubscription(unittest.TestCase): @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_create_raises_exception_with_bad_keys(self): Subscription.create({"bad_key": "value"}) @raises_with_regexp(KeyError, "'Invalid keys: bad_key'") def test_update_raises_exception_with_bad_keys(self): Subscription.update("id", {"bad_key": "value"}) @raises(NotFoundError) def test_finding_empty_id_raises_not_found_exception(self): Subscription.find(" ") @raises(NotFoundError) def test_finding_None_id_raises_not_found_exception(self): Subscription.find(None) braintree_python-3.57.1/tests/unit/test_http.py0000644000175000017500000001217413545202423020003 0ustar hlehleimport traceback from tests.test_helper import * from braintree.exceptions.http.timeout_error import * from braintree.attribute_getter import AttributeGetter class TestHttp(unittest.TestCase): @raises(UpgradeRequiredError) def test_raise_exception_from_status_for_upgrade_required(self): Http.raise_exception_from_status(426) @raises(TooManyRequestsError) def test_raise_exception_from_too_many_requests(self): Http.raise_exception_from_status(429) def test_header_includes_gzip_accept_encoding(self): config = AttributeGetter({ "base_url": (lambda: ""), "has_access_token": (lambda: False), "has_client_credentials": (lambda: False), "public_key": "", "private_key": ""}) headers = Http(config, "fake_environment")._Http__headers(Http.ContentType.Xml) self.assertTrue('Accept-Encoding' in headers) self.assertEqual('gzip', headers["Accept-Encoding"]) def test_backtrace_preserved_when_not_wrapping_exceptions(self): class Error(Exception): pass def raise_error(*_): raise Error http_strategy = AttributeGetter({"http_do": raise_error}) config = AttributeGetter({ "base_url": (lambda: ""), "has_access_token": (lambda: False), "has_client_credentials": (lambda: False), "http_strategy": (lambda: http_strategy), "public_key": "", "private_key": "", "wrap_http_exceptions": False}) try: Http(config, "fake_environment").post("/example/path/to/reach") except Error: _, _, tb = sys.exc_info() self.assertEqual('raise_error', traceback.extract_tb(tb)[-1][2]) def test_request_body_returns_string_for_post(self): def test_http_do_strategy(http_verb, path, headers, request_body): self.assertTrue(isinstance(request_body, str)) self.assertEqual("post", request_body) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.post("/some_path", {"method": "post"}) def test_request_body_returns_string_for_delete(self): def test_http_do_strategy(http_verb, path, headers, request_body): self.assertTrue(isinstance(request_body, str)) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.delete("/some_path") def test_request_body_returns_string_for_get(self): def test_http_do_strategy(http_verb, path, headers, request_body): self.assertTrue(isinstance(request_body, str)) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.get("/some_path") def test_request_body_returns_string_for_put(self): def test_http_do_strategy(http_verb, path, headers, request_body): self.assertTrue(isinstance(request_body, str)) self.assertEqual("put", request_body) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.put("/some_path", {"method": "put"}) def test_request_body_returns_string_for_post_multipart_when_no_files(self): params = {"method": "post_multipart"} def test_http_do_strategy(http_verb, path, headers, request_body): self.assertEqual(params, request_body) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.post_multipart("/some_path", None, params) def test_request_body_returns_tuple_for_post_multipart_when_files(self): params = {"method": "post_multipart"} def test_http_do_strategy(http_verb, path, headers, request_body): self.assertEqual(params, request_body[0]) self.assertEqual("files", request_body[1]) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.post_multipart("/some_path", "files", params) def setup_http_strategy(self, http_do): config = AttributeGetter({ "base_url": (lambda: ""), "has_access_token": (lambda: False), "has_client_credentials": (lambda: False), "http_strategy": (lambda: AttributeGetter({"http_do": http_do})), "public_key": "", "private_key": "", "wrap_http_exceptions": False}) return Http(config, "fake_environment") @raises(ReadTimeoutError) def test_raise_read_timeout_error(self): def test_http_do_strategy(http_verb, path, headers, request_body): return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.handle_exception(requests.exceptions.ReadTimeout()) @raises(ConnectTimeoutError) def test_raise_read_timeout_error(self): def test_http_do_strategy(http_verb, path, headers, request_body): return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.handle_exception(requests.exceptions.ConnectTimeout()) braintree_python-3.57.1/tests/unit/test_transparent_redirect.py0000644000175000017500000000527113545202423023246 0ustar hlehlefrom tests.test_helper import * class TestTransparentRedirect(unittest.TestCase): def test_tr_data(self): data = TransparentRedirect.tr_data({"key": "val"}, "http://example.com/path?foo=bar") self.__assert_valid_tr_data(data) def __assert_valid_tr_data(self, data): test_hash, content = data.split("|", 1) self.assertEqual(test_hash, Crypto.sha1_hmac_hash(Configuration.private_key, content)) @raises(ForgedQueryStringError) def test_parse_and_validate_query_string_raises_for_invalid_hash(self): Configuration.gateway().transparent_redirect._parse_and_validate_query_string( "http_status=200&id=7kdj469tw7yck32j&hash=99c9ff20cd7910a1c1e793ff9e3b2d15586dc6b9" ) @raises(AuthenticationError) def test_parse_and_validate_query_string_raises_for_http_status_401(self): Configuration.gateway().transparent_redirect._parse_and_validate_query_string( "http_status=401&id=6kdj469tw7yck32j&hash=5a26e3cde5ebedb0ec1ba8d35724360334fbf419" ) @raises(AuthorizationError) def test_parse_and_validate_query_string_raises_for_http_status_403(self): Configuration.gateway().transparent_redirect._parse_and_validate_query_string( "http_status=403&id=6kdj469tw7yck32j&hash=126d5130b71a4907e460fad23876ed70dd41dcd2" ) @raises(NotFoundError) def test_parse_and_validate_query_string_raises_for_http_status_404(self): Configuration.gateway().transparent_redirect._parse_and_validate_query_string( "http_status=404&id=6kdj469tw7yck32j&hash=0d3724a45cf1cda5524aa68f1f28899d34d2ff3a" ) @raises(ServerError) def test_parse_and_validate_query_string_raises_for_http_status_500(self): Configuration.gateway().transparent_redirect._parse_and_validate_query_string( "http_status=500&id=6kdj469tw7yck32j&hash=a839a44ca69d59a3d6f639c294794989676632dc" ) @raises(DownForMaintenanceError) def test_parse_and_validate_query_string_raises_for_http_status_503(self): Configuration.gateway().transparent_redirect._parse_and_validate_query_string( "http_status=503&id=6kdj469tw7yck32j&hash=1b3d29199a282e63074a7823b76bccacdf732da6" ) @raises(UnexpectedError) def test_parse_and_validate_query_string_raises_for_unexpected_http_status(self): Configuration.gateway().transparent_redirect._parse_and_validate_query_string( "http_status=600&id=6kdj469tw7yck32j&hash=740633356f93384167d887de0c1d9745e3de8fb6" ) def test_api_version(self): data = TransparentRedirect.tr_data({"key": "val"}, "http://example.com/path?foo=bar") self.assertTrue("api_version=5" in data) braintree_python-3.57.1/tests/unit/test_partner_merchant.py0000644000175000017500000000155513545202423022361 0ustar hlehlefrom tests.test_helper import * class TestPartnerMerchant(unittest.TestCase): def test_representation(self): merchant = PartnerMerchant(None, {"partner_merchant_id": "abc123", "private_key": "my_private_key", "public_key": "my_public_key", "merchant_public_id": "foobar", "client_side_encryption_key": "cse_key"}) self.assertTrue("partner_merchant_id: 'abc123'" in repr(merchant)) self.assertTrue("public_key: 'my_public_key'" in repr(merchant)) self.assertTrue("merchant_public_id: 'foobar'" in repr(merchant)) self.assertTrue("client_side_encryption_key: 'cse_key'" in repr(merchant)) self.assertFalse("private_key: 'my_private_key'" in repr(merchant)) braintree_python-3.57.1/tests/unit/test_validation_error_collection.py0000644000175000017500000001205413545202423024577 0ustar hlehlefrom tests.test_helper import * class TestValidationErrorCollection(unittest.TestCase): def test_it_builds_an_array_of_errors_given_an_array_of_hashes(self): test_hash = {"errors": [{"attribute": "some model attribute", "code": 1, "message": "bad juju"}]} errors = ValidationErrorCollection(test_hash) error = errors[0] self.assertEqual("some model attribute", error.attribute) self.assertEqual(1, error.code) self.assertEqual("bad juju", error.message) def test_for_object_provides_access_to_nested_attributes(self): test_hash = { "errors": [{"attribute": "some model attribute", "code": 1, "message": "bad juju"}], "nested": { "errors": [{"attribute": "number", "code": 2, "message": "badder juju"}] } } errors = ValidationErrorCollection(test_hash) error = errors.for_object("nested").on("number")[0] self.assertEqual("number", error.attribute) self.assertEqual(2, error.code) self.assertEqual("badder juju", error.message) def test_deep_size_non_nested(self): test_hash = { "errors": [ {"attribute": "one", "code": 1, "message": "is too long"}, {"attribute": "two", "code": 2, "message": "contains invalid chars"}, {"attribute": "thr", "code": 3, "message": "is invalid"} ] } self.assertEqual(3, ValidationErrorCollection(test_hash).deep_size) def test_deep_size_nested(self): test_hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}] } } self.assertEqual(2, ValidationErrorCollection(test_hash).deep_size) def test_deep_size_multiple_nestings(self): test_hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}], "nested_again": { "errors": [ {"attribute": "three", "code": 3, "message": "super nested"}, {"attribute": "four", "code": 4, "message": "super nested 2"} ] } } } self.assertEqual(4, ValidationErrorCollection(test_hash).deep_size) def test_len_multiple_nestings(self): test_hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}], "nested_again": { "errors": [ {"attribute": "three", "code": 3, "message": "super nested"}, {"attribute": "four", "code": 4, "message": "super nested 2"} ] } } } validation_error_collection = ValidationErrorCollection(test_hash) self.assertEqual(1, len(validation_error_collection)) self.assertEqual(1, len(validation_error_collection.for_object("nested"))) self.assertEqual(2, len(validation_error_collection.for_object("nested").for_object("nested_again"))) def test_deep_errors(self): test_hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}], "nested_again": { "errors": [ {"attribute": "three", "code": 3, "message": "super nested"}, {"attribute": "four", "code": 4, "message": "super nested 2"} ] } } } validation_error_collection = ValidationErrorCollection(test_hash) self.assertEqual([1, 2, 3, 4], [error.code for error in validation_error_collection.deep_errors]) def test_errors(self): test_hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}], "nested_again": { "errors": [ {"attribute": "three", "code": 3, "message": "super nested"}, {"attribute": "four", "code": 4, "message": "super nested 2"} ] } } } validation_error_collection = ValidationErrorCollection(test_hash) self.assertEqual([1], [error.code for error in validation_error_collection.errors]) self.assertEqual([2], [error.code for error in validation_error_collection.for_object("nested").errors]) self.assertEqual([3, 4], [error.code for error in validation_error_collection.for_object("nested").for_object("nested_again").errors]) braintree_python-3.57.1/tests/unit/test_three_d_secure_info.py0000644000175000017500000000226313545202423023015 0ustar hlehlefrom tests.test_helper import * from braintree import * class TestThreeDSecureInfo(unittest.TestCase): def test_initialization_of_attributes(self): three_d_secure_info = ThreeDSecureInfo({ "enrolled": "Y", "status": "authenticate_successful", "liability_shifted": True, "liability_shift_possible": True, "cavv": "some_cavv", "xid": "some_xid", "ds_transaction_id": "some_ds_txn_id", "eci_flag": "07", "three_d_secure_version": "1.0.2", }) self.assertEqual("Y", three_d_secure_info.enrolled) self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertEqual("some_cavv", three_d_secure_info.cavv) self.assertEqual("some_xid", three_d_secure_info.xid) self.assertEqual("some_ds_txn_id", three_d_secure_info.ds_transaction_id) self.assertEqual("07", three_d_secure_info.eci_flag) self.assertEqual("1.0.2", three_d_secure_info.three_d_secure_version) braintree_python-3.57.1/tests/unit/test_crypto.py0000644000175000017500000000157013545202423020342 0ustar hlehlefrom tests.test_helper import * class TestCrypto(unittest.TestCase): def test_sha1_hmac_hash(self): actual = Crypto.sha1_hmac_hash("secretKey", "hello world") self.assertEqual("d503d7a1a6adba1e6474e9ff2c4167f9dfdf4247", actual) def test_sha256_hmac_hash(self): actual = Crypto.sha256_hmac_hash("secret-key", "secret-message") self.assertEqual("68e7f2ecab71db67b1aca2a638f5122810315c3013f27c2196cd53e88709eecc", actual) def test_secure_compare_returns_true_when_same(self): self.assertTrue(Crypto.secure_compare("a_string", "a_string")) def test_secure_compare_returns_false_when_different_lengths(self): self.assertFalse(Crypto.secure_compare("a_string", "a_string_that_is_longer")) def test_secure_compare_returns_false_when_different(self): self.assertFalse(Crypto.secure_compare("a_string", "a_strong")) braintree_python-3.57.1/tests/unit/test_setup.py0000644000175000017500000000223013545202423020154 0ustar hlehlefrom tests.test_helper import * import os class TestSetup(unittest.TestCase): def test_packages_includes_all_packages(self): with open('setup.py', 'r') as f: setup_contents = f.read() packages_line = re.findall('packages=.*', setup_contents) packages_from_setup = re.findall('"(.*?)"', str(packages_line)) packages_from_directories = ['braintree'] directories_that_dont_have_packages = ['braintree.ssl'] for dirname, dirnames, _ in os.walk('braintree'): for subdirname in dirnames: package_from_directory = re.sub('/', '.', os.path.join(dirname, subdirname)) if package_from_directory not in directories_that_dont_have_packages and subdirname != '__pycache__': packages_from_directories.append(package_from_directory) mismatch_message = "List of packages in setup.py doesn't match subdirectories of 'braintree' - " \ + "add your new directory to 'packages, or if none, `git clean -df` to remove a stale directory" self.assertEqual(sorted(packages_from_directories), sorted(packages_from_setup), mismatch_message) braintree_python-3.57.1/tests/unit/test_disbursement_detail.py0000644000175000017500000000205013545202423023042 0ustar hlehlefrom tests.test_helper import * from braintree.disbursement_detail import DisbursementDetail class TestDisbursementDetail(unittest.TestCase): def test_is_valid_true(self): detail_hash = { 'settlement_amount': '27.00', 'settlement_currency_iso_code': 'USD', 'settlement_currency_exchange_rate': '1', 'disbursed_at': datetime(2013, 4, 11, 0, 0, 0), 'disbursement_date': date(2013, 4, 10), 'funds_held': False } disbursement_details = DisbursementDetail(detail_hash) self.assertTrue(disbursement_details.is_valid) def test_is_valid_false(self): detail_hash = { 'settlement_amount': None, 'settlement_currency_iso_code': None, 'settlement_currency_exchange_rate': None, 'disbursed_at': None, 'disbursement_date': None, 'funds_held': None } disbursement_details = DisbursementDetail(detail_hash) self.assertEqual(False, disbursement_details.is_valid) braintree_python-3.57.1/tests/unit/test_resource_collection.py0000644000175000017500000000402013545202423023055 0ustar hlehlefrom tests.test_helper import * class TestResourceCollection(unittest.TestCase): collection_data = { "search_results": { "page_size": 2, "ids": ["0", "1", "2", "3", "4"] } } class TestResource: items = ["a", "b", "c", "d", "e"] @staticmethod def fetch(_, ids): return [TestResourceCollection.TestResource.items[int(resource_id)] for resource_id in ids] def test_iterating_over_contents(self): collection = ResourceCollection("some_query", self.collection_data, TestResourceCollection.TestResource.fetch) new_items = [] index = 0 for item in collection.items: self.assertEqual(TestResourceCollection.TestResource.items[index], item) new_items.append(item) index += 1 self.assertEqual(5, len(new_items)) def test_iterate_using_iterator_protocol(self): collection = ResourceCollection("some_query", self.collection_data, TestResourceCollection.TestResource.fetch) for test_elem, coll_elem in zip(self.TestResource.items, collection): self.assertEqual(test_elem, coll_elem) def test_ids_returns_array_of_ids(self): collection = ResourceCollection("some_query", self.collection_data, TestResourceCollection.TestResource.fetch) self.assertEqual(collection.ids, self.collection_data['search_results']['ids']) def test_ids_returns_array_of_empty_ids(self): empty_collection_data = { "search_results": { "page_size": 2, "ids": [] } } collection = ResourceCollection("some_query", empty_collection_data, TestResourceCollection.TestResource.fetch) self.assertEqual(collection.ids, []) @raises_with_regexp(UnexpectedError, "Unprocessable entity due to an invalid request") def test_no_search_results(self): bad_collection_data = {} ResourceCollection("some_query", bad_collection_data, TestResourceCollection.TestResource.fetch) braintree_python-3.57.1/tests/unit/test_graphql_client.py0000644000175000017500000000365513545202423022024 0ustar hlehlefrom tests.test_helper import * class TestGraphQLClient(unittest.TestCase): @raises(UpgradeRequiredError) def test_raise_exception_from_status_for_upgrade_required(self): response = { "errors": [ { "message": "error message", "extensions": { "errorClass": "UNSUPPORTED_CLIENT" } } ] } GraphQLClient.raise_exception_for_graphql_error(response) @raises(TooManyRequestsError) def test_raise_exception_from_too_many_requests(self): response = { "errors": [ { "message": "error message", "extensions": { "errorClass": "RESOURCE_LIMIT" } } ] } GraphQLClient.raise_exception_for_graphql_error(response) def test_does_not_raise_exception_from_validation_error(self): response = { "errors": [ { "message": "error message", "extensions": { "errorClass": "VALIDATION" } } ] } GraphQLClient.raise_exception_for_graphql_error(response) @raises(ServerError) def test_raise_exception_from_validation_error_and_legitimate_error(self): response = { "errors": [ { "message": "error message", "extensions": { "errorClass": "VALIDATION" } }, { "message": "error message 2", "extensions": { "errorClass": "INTERNAL" } } ] } GraphQLClient.raise_exception_for_graphql_error(response) braintree_python-3.57.1/tests/unit/merchant_account/0000755000175000017500000000000013545202423020723 5ustar hlehlebraintree_python-3.57.1/tests/unit/merchant_account/test_individual_details.py0000644000175000017500000000157713545202423026203 0ustar hlehlefrom tests.test_helper import * from braintree.merchant_account.individual_details import IndividualDetails class TestIndividualDetails(unittest.TestCase): def test_repr_has_all_fields(self): details = IndividualDetails({ "first_name": "Sue", "last_name": "Smith", "email": "sue@hotmail.com", "phone": "1112223333", "date_of_birth": "1980-12-05", "ssn_last_4": "5555", "address": { "street_address": "123 First St", } }) regex = r"} at \w+>" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-3.57.1/tests/unit/merchant_account/test_address_details.py0000644000175000017500000000112713545202423025467 0ustar hlehlefrom tests.test_helper import * from braintree.merchant_account.address_details import AddressDetails class TestAddressDetails(unittest.TestCase): def test_repr_has_all_fields(self): details = AddressDetails({ "street_address": "123 First St", "region": "Las Vegas", "locality": "NV", "postal_code": "89913" }) regex = r"" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-3.57.1/tests/unit/merchant_account/test_funding_details.py0000644000175000017500000000127513545202423025500 0ustar hlehlefrom tests.test_helper import * from braintree.merchant_account.funding_details import FundingDetails class TestFundingDetails(unittest.TestCase): def test_repr_has_all_fields(self): details = FundingDetails({ "destination": "bank", "routing_number": "11112222", "account_number_last_4": "3333", "email": "lucyloo@work.com", "mobile_phone": "9998887777" }) regex = r"" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-3.57.1/tests/unit/merchant_account/__init__.py0000644000175000017500000000000013545202423023022 0ustar hlehlebraintree_python-3.57.1/tests/unit/merchant_account/test_business_details.py0000644000175000017500000000152713545202423025701 0ustar hlehlefrom tests.test_helper import * from braintree.merchant_account.business_details import BusinessDetails class TestBusinessDetails(unittest.TestCase): def test_repr_has_all_fields(self): details = BusinessDetails({ "dba_name": "Bar Suenami", "legal_name": "Suenami Restaurant Group", "tax_id": "123001234", "address": { "street_address": "123 First St", "region": "Las Vegas", "locality": "NV", } }) regex = r"} at \w+>" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-3.57.1/tests/unit/test_errors.py0000644000175000017500000000430013545202423020330 0ustar hlehlefrom tests.test_helper import * class TestErrors(unittest.TestCase): def test_errors_for_the_given_scope(self): errors = Errors({"level1": {"errors": [{"code": "code1", "attribute": "attr", "message": "message"}]}}) self.assertEqual(1, errors.for_object("level1").size) self.assertEqual(1, len(errors.for_object("level1"))) def test_for_object_returns_empty_errors_collection_if_no_errors_at_given_scope(self): errors = Errors({"level1": {"errors": [{"code": "code1", "attribute": "attr", "message": "message"}]}}) self.assertEqual(0, errors.for_object("no_errors_here").size) self.assertEqual(0, len(errors.for_object("no_errors_here"))) def test_size_returns_number_of_errors_at_first_level_if_only_one_level_exists(self): test_hash = { "level1": {"errors": [{"code": "code1", "attribute": "attr", "message": "message"}]} } self.assertEqual(1, Errors(test_hash).size) self.assertEqual(1, len(Errors(test_hash))) def test_size_returns_number_of_errors_at_all_levels(self): test_hash = { "level1": { "errors": [{"code": "code1", "attribute": "attr", "message": "message"}], "level2": { "errors": [ {"code": "code2", "attribute": "attr", "message": "message"}, {"code": "code3", "attribute": "attr", "message": "message"} ] } } } self.assertEqual(3, Errors(test_hash).size) self.assertEqual(3, len(Errors(test_hash))) def test_deep_errors_returns_all_errors(self): test_hash = { "level1": { "errors": [{"code": "code1", "attribute": "attr", "message": "message"}], "level2": { "errors": [ {"code": "code2", "attribute": "attr", "message": "message"}, {"code": "code3", "attribute": "attr", "message": "message"} ] } } } errors = Errors(test_hash).deep_errors self.assertEqual(["code1", "code2", "code3"], [error.code for error in errors]) braintree_python-3.57.1/tests/unit/test_configuration.py0000644000175000017500000001454013545202423021672 0ustar hlehlefrom tests.test_helper import * import braintree import os import imp class TestConfiguration(unittest.TestCase): def test_works_with_unconfigured_configuration(self): try: # reset class level attributes on Configuration set in test helper imp.reload(braintree.configuration) config = Configuration( environment=braintree.Environment.Sandbox, merchant_id='my_merchant_id', public_key='public_key', private_key='private_key' ) config.http_strategy() except AttributeError as e: print(e) self.fail() finally: # repopulate class level attributes on Configuration import tests.test_helper imp.reload(tests.test_helper) def test_base_merchant_path_for_development(self): self.assertEqual("/merchants/integration_merchant_id", Configuration.instantiate().base_merchant_path()) def test_configuration_construction_for_merchant(self): config = Configuration( environment=braintree.Environment.Sandbox, merchant_id='my_merchant_id', public_key='public_key', private_key='private_key' ) self.assertEqual(config.merchant_id, 'my_merchant_id') self.assertEqual(config.public_key, 'public_key') self.assertEqual(config.private_key, 'private_key') def test_configuration_configure_allows_strings_for_environment(self): try: for environment_string, environment_object in braintree.Environment.All.items(): braintree.Configuration.configure( environment_string, 'my_merchant_id', 'public_key', 'private_key' ) self.assertEqual(braintree.Configuration.environment, environment_object) finally: reset_braintree_configuration() def test_configuration_construction_allows_strings_for_environment(self): config = Configuration( environment='sandbox', merchant_id='my_merchant_id', public_key='public_key', private_key='private_key' ) self.assertEqual(config.environment, braintree.Environment.Sandbox) def test_configuration_construction_allows_empty_parameter_list(self): config = Configuration() self.assertIsInstance(config, braintree.Configuration) def test_configuration_raises_configuration_error_for_invalid_environment(self): for environment in [42, 'not_an_env', '']: def setup_bad_configuration(): Configuration( environment=environment, merchant_id='my_merchant_id', public_key='public_key', private_key='private_key' ) self.assertRaises(ConfigurationError, setup_bad_configuration) def test_configuration_raises_configuration_error_for_empty_merchant_id(self): def setup_bad_configuration(): Configuration( environment=braintree.Environment.Sandbox, merchant_id='', public_key='public_key', private_key='private_key' ) self.assertRaises(ConfigurationError, setup_bad_configuration) def test_configuration_raises_configuration_error_for_empty_public_key(self): def setup_bad_configuration(): Configuration( environment=braintree.Environment.Sandbox, merchant_id='my_merchant_id', public_key='', private_key='private_key' ) self.assertRaises(ConfigurationError, setup_bad_configuration) def test_configuration_raises_configuration_error_for_empty_private_key(self): def setup_bad_configuration(): Configuration( environment=braintree.Environment.Sandbox, merchant_id='my_merchant_id', public_key='public_key', private_key='' ) self.assertRaises(ConfigurationError, setup_bad_configuration) def test_configuration_construction_for_partner(self): config = Configuration.for_partner( braintree.Environment.Sandbox, 'my_partner_id', 'public_key', 'private_key' ) self.assertEqual(config.merchant_id, 'my_partner_id') self.assertEqual(config.public_key, 'public_key') self.assertEqual(config.private_key, 'private_key') def test_configuring_with_an_http_strategy(self): class FakeStrategy(object): def __init__(self, config, environment): pass strategy = Configuration(http_strategy=FakeStrategy).http_strategy() self.assertIsInstance(strategy, FakeStrategy) def test_partner_configuration_does_not_use_default_http_strategy(self): old_http_strategy = Configuration.default_http_strategy class FakeStrategy(object): def __init__(self, config, environment): pass try: Configuration.default_http_strategy = FakeStrategy config = Configuration.for_partner( braintree.Environment.Sandbox, 'my_partner_id', 'public_key', 'private_key' ) self.assertNotIsInstance(config.http_strategy(), FakeStrategy) finally: Configuration.default_http_strategy = old_http_strategy def test_instantiate_with_a_default_http_strategy(self): old_http_strategy = Configuration.default_http_strategy class FakeStrategy(object): def __init__(self, config, environment): pass try: Configuration.default_http_strategy = FakeStrategy strategy = Configuration.instantiate().http_strategy() self.assertIsInstance(strategy, FakeStrategy) finally: Configuration.default_http_strategy = old_http_strategy def test_configuring_with_partial_client_credentials(self): with self.assertRaises(ConfigurationError) as error: Configuration(client_id='client_id$development$integration_client_id') self.assertIn("Missing client_secret when constructing BraintreeGateway", str(error.exception)) braintree_python-3.57.1/tests/unit/test_dispute.py0000644000175000017500000002660513545202423020505 0ustar hlehlefrom tests.test_helper import * from datetime import date from braintree.dispute import Dispute class TestDispute(unittest.TestCase): legacy_attributes = { "transaction": { "id": "transaction_id", "amount": "100.00", }, "id": "123456", "currency_iso_code": "USD", "status": "open", "amount": "100.00", "received_date": date(2013, 4, 10), "reply_by_date": date(2013, 4, 10), "reason": "fraud", "transaction_ids": ["asdf", "qwer"], "date_opened": date(2013, 4, 1), "date_won": date(2013, 4, 2), "kind": "chargeback", } attributes = { "amount": "100.00", "amount_disputed": "100.00", "amount_won": "0.00", "case_number": "CB123456", "created_at": datetime(2013, 4, 10, 10, 50, 39), "currency_iso_code": "USD", "date_opened": date(2013, 4, 1), "date_won": date(2013, 4, 2), "processor_comments": "Forwarded comments", "id": "123456", "kind": "chargeback", "merchant_account_id": "abc123", "original_dispute_id": "original_dispute_id", "reason": "fraud", "reason_code": "83", "reason_description": "Reason code 83 description", "received_date": date(2013, 4, 10), "reference_number": "123456", "reply_by_date": date(2013, 4, 17), "status": "open", "updated_at": datetime(2013, 4, 10, 10, 50, 39), "evidence": [{ "comment": None, "created_at": datetime(2013, 4, 11, 10, 50, 39), "id": "evidence1", "sent_to_processor_at": None, "url": "url_of_file_evidence", },{ "comment": "text evidence", "created_at": datetime(2013, 4, 11, 10, 50, 39), "id": "evidence2", "sent_to_processor_at": "2009-04-11", "url": None, }], "status_history": [{ "disbursement_date": "2013-04-11", "effective_date": "2013-04-10", "status": "open", "timestamp": datetime(2013, 4, 10, 10, 50, 39), }], "transaction": { "id": "transaction_id", "amount": "100.00", "created_at": datetime(2013, 3, 19, 10, 50, 39), "order_id": None, "purchase_order_number": "po", "payment_instrument_subtype": "Visa", }, } def test_legacy_constructor(self): dispute = Dispute(dict(self.legacy_attributes)) self.assertEqual(dispute.id, "123456") self.assertEqual(dispute.amount, Decimal("100.00")) self.assertEqual(dispute.currency_iso_code, "USD") self.assertEqual(dispute.reason, Dispute.Reason.Fraud) self.assertEqual(dispute.status, Dispute.Status.Open) self.assertEqual(dispute.transaction_details.id, "transaction_id") self.assertEqual(dispute.transaction_details.amount, Decimal("100.00")) self.assertEqual(dispute.date_opened, date(2013, 4, 1)) self.assertEqual(dispute.date_won, date(2013, 4, 2)) self.assertEqual(dispute.kind, Dispute.Kind.Chargeback) def test_legacy_params_with_new_attributes(self): dispute = Dispute(dict(self.attributes)) self.assertEqual(dispute.id, "123456") self.assertEqual(dispute.amount, Decimal("100.00")) self.assertEqual(dispute.currency_iso_code, "USD") self.assertEqual(dispute.reason, Dispute.Reason.Fraud) self.assertEqual(dispute.status, Dispute.Status.Open) self.assertEqual(dispute.transaction_details.id, "transaction_id") self.assertEqual(dispute.transaction_details.amount, Decimal("100.00")) self.assertEqual(dispute.date_opened, date(2013, 4, 1)) self.assertEqual(dispute.date_won, date(2013, 4, 2)) self.assertEqual(dispute.kind, Dispute.Kind.Chargeback) def test_constructor_populates_new_fields(self): attributes = dict(self.attributes) del attributes["amount"] dispute = Dispute(attributes) self.assertEqual(dispute.amount_disputed, 100.0) self.assertEqual(dispute.amount_won, 0.00) self.assertEqual(dispute.case_number, "CB123456") self.assertEqual(dispute.created_at, datetime(2013, 4, 10, 10, 50, 39)) self.assertEqual(dispute.forwarded_comments, "Forwarded comments") self.assertEqual(dispute.processor_comments, "Forwarded comments") self.assertEqual(dispute.merchant_account_id, "abc123") self.assertEqual(dispute.original_dispute_id, "original_dispute_id") self.assertEqual(dispute.reason_code, "83") self.assertEqual(dispute.reason_description, "Reason code 83 description") self.assertEqual(dispute.reference_number, "123456") self.assertEqual(dispute.updated_at, datetime(2013, 4, 10, 10, 50, 39)) self.assertIsNone(dispute.evidence[0].comment) self.assertEqual(dispute.evidence[0].created_at, datetime(2013, 4, 11, 10, 50, 39)) self.assertEqual(dispute.evidence[0].id, "evidence1") self.assertIsNone(dispute.evidence[0].sent_to_processor_at) self.assertEqual(dispute.evidence[0].url, "url_of_file_evidence") self.assertEqual(dispute.evidence[1].comment, "text evidence") self.assertEqual(dispute.evidence[1].created_at, datetime(2013, 4, 11, 10, 50, 39)) self.assertEqual(dispute.evidence[1].id, "evidence2") self.assertEqual(dispute.evidence[1].sent_to_processor_at, "2009-04-11") self.assertIsNone(dispute.evidence[1].url) self.assertEqual(dispute.status_history[0].disbursement_date, "2013-04-11") self.assertEqual(dispute.status_history[0].effective_date, "2013-04-10") self.assertEqual(dispute.status_history[0].status, "open") self.assertEqual(dispute.status_history[0].timestamp, datetime(2013, 4, 10, 10, 50, 39)) def test_constructor_handles_none_fields(self): attributes = dict(self.attributes) attributes.update({ "amount": None, "date_opened": None, "date_won": None, "evidence": None, "reply_by_date": None, "status_history": None }) dispute = Dispute(attributes) self.assertIsNone(dispute.reply_by_date) self.assertIsNone(dispute.amount) self.assertIsNone(dispute.date_opened) self.assertIsNone(dispute.date_won) self.assertIsNone(dispute.status_history) def test_constructor_populates_transaction(self): dispute = Dispute(dict(self.attributes)) self.assertEqual(dispute.transaction.id, "transaction_id") self.assertEqual(dispute.transaction.amount, Decimal("100.00")) self.assertEqual(dispute.transaction.created_at, datetime(2013, 3, 19, 10, 50, 39)) self.assertIsNone(dispute.transaction.order_id) self.assertEqual(dispute.transaction.purchase_order_number, "po") self.assertEqual(dispute.transaction.payment_instrument_subtype, "Visa") @raises_with_regexp(NotFoundError, "dispute with id None not found") def test_accept_none_raises_not_found_exception(self): Dispute.accept(None) @raises_with_regexp(NotFoundError, "dispute with id ' ' not found") def test_accept_empty_id_raises_not_found_exception(self): Dispute.accept(" ") @raises_with_regexp(NotFoundError, "dispute_id cannot be blank") def test_add_text_evidence_empty_id_raises_not_found_exception(self): Dispute.add_text_evidence(" ", "evidence") @raises_with_regexp(NotFoundError, "dispute_id cannot be blank") def test_add_text_evidence_none_id_raises_not_found_exception(self): Dispute.add_text_evidence(None, "evidence") @raises_with_regexp(ValueError, "content cannot be blank") def test_add_text_evidence_empty_evidence_raises_value_exception(self): Dispute.add_text_evidence("dispute_id", " ") @raises_with_regexp(ValueError, "sequence_number must be an integer") def test_add_text_evidence_sequence_number_not_number_evidence_raises_value_exception(self): Dispute.add_text_evidence("dispute_id", { "content": "content", "sequence_number": "a" }) @raises_with_regexp(ValueError, "sequence_number must be an integer") def test_add_text_evidence_sequence_number_not_number_evidence_raises_value_exception(self): Dispute.add_text_evidence("dispute_id", { "content": "content", "sequence_number": "1abc" }) @raises_with_regexp(ValueError, "category must be a string") def test_add_text_evidence_category_is_number_evidence_raises_value_exception(self): Dispute.add_text_evidence("dispute_id", { "content": "content", "category": 5 }) @raises_with_regexp(NotFoundError, "dispute with id ' ' not found") def test_add_file_evidence_empty_id_raises_not_found_exception(self): Dispute.add_file_evidence(" ", 1) @raises_with_regexp(NotFoundError, "dispute with id None not found") def test_add_file_evidence_none_id_raises_not_found_exception(self): Dispute.add_file_evidence(None, 1) @raises_with_regexp(ValueError, "document_id cannot be blank") def test_add_file_evidence_empty_evidence_raises_value_exception(self): Dispute.add_file_evidence("dispute_id", " ") @raises_with_regexp(ValueError, "document_id cannot be blank") def test_add_file_evidence_none_evidence_raises_value_exception(self): Dispute.add_file_evidence("dispute_id", None) @raises_with_regexp(ValueError, "category must be a string") def test_add_file_evidence_categorized_document_id_must_be_a_string(self): Dispute.add_file_evidence("dispute_id", { "document_id": "213", "category": 5 }) @raises_with_regexp(ValueError, "document_id cannot be blank") def test_add_file_evidence_empty_categorized_evidence_raises_value_exception(self): Dispute.add_file_evidence("dispute_id", { "category": "DEVICE_ID" }) @raises_with_regexp(NotFoundError, "dispute with id None not found") def test_finalize_none_raises_not_found_exception(self): Dispute.finalize(None) @raises_with_regexp(NotFoundError, "dispute with id ' ' not found") def test_finalize_empty_id_raises_not_found_exception(self): Dispute.finalize(" ") @raises_with_regexp(NotFoundError, "dispute with id None not found") def test_finding_none_raises_not_found_exception(self): Dispute.find(None) @raises_with_regexp(NotFoundError, "dispute with id ' ' not found") def test_finding_empty_id_raises_not_found_exception(self): Dispute.find(" ") @raises_with_regexp(NotFoundError, "evidence with id 'evidence' for dispute with id ' ' not found") def test_remove_evidence_empty_dispute_id_raises_not_found_exception(self): Dispute.remove_evidence(" ", "evidence") @raises_with_regexp(NotFoundError, "evidence with id 'evidence' for dispute with id None not found") def test_remove_evidence_none_dispute_id_raises_not_found_exception(self): Dispute.remove_evidence(None, "evidence") @raises_with_regexp(NotFoundError, "evidence with id None for dispute with id 'dispute_id' not found") def test_remove_evidence_evidence_none_id_raises_not_found_exception(self): Dispute.remove_evidence("dispute_id", None) @raises_with_regexp(NotFoundError, "evidence with id ' ' for dispute with id 'dispute_id' not found") def test_remove_evidence_empty_evidence_id_raises_value_exception(self): Dispute.remove_evidence("dispute_id", " ") braintree_python-3.57.1/Dockerfile0000644000175000017500000000031313545202423015254 0ustar hlehleFROM debian:stretch RUN apt-get update RUN apt-get -y install python rake RUN apt-get -y install python-pip RUN pip install --upgrade pip RUN pip install --upgrade distribute WORKDIR /braintree-python braintree_python-3.57.1/LICENSE0000644000175000017500000000212113545202423014266 0ustar hlehle(The MIT License) Copyright (c) 2009-2014 Braintree, a division of PayPal, Inc. 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. braintree_python-3.57.1/Rakefile0000644000175000017500000000245113545202423014734 0ustar hlehletask :default => :test task :test => ["test:unit", "test:integration"] namespace :test do desc "run unit tests" task :unit do sh "nosetests tests/unit" end desc "run integration tests" task :integration do sh "env nosetests tests/integration" end desc "run single test (example: rake test:single[tests/integration/test_paypal_account.py:TestPayPalAccount.test_find_returns_paypal_account])" task :single, [:test_name] do |t, args| sh "nosetests #{args[:test_name]}" end end task :clean do rm_rf "build" rm_rf "dist" rm_f "MANIFEST" end namespace :pypi do desc "Register the package with PyPI" task :register => :clean do sh "python setup.py register" end desc "Upload a new version to PyPI" task :upload => :clean do sh "python setup.py sdist bdist_wheel" sh "twine upload dist/*" end end namespace :lint do desc "Evaluate test code quality using pylintrc file" task :tests do puts `pylint tests --rcfile=.pylintrc --disable=R0801 --disable=W0232` end desc "Evaluate app code quality using pylintrc file" task :code do puts `pylint braintree --rcfile=.pylintrc` end desc "Evaluate library code quality using pylintrc file" task :all do puts `pylint braintree tests --rcfile=.pylintrc` end end task :lint => "lint:all" braintree_python-3.57.1/CHANGELOG.md0000644000175000017500000005073213545202423015105 0ustar hlehle## 3.57.1 * Set correct version for PyPi ## 3.57.0 * Forward `processor_comments` to `forwarded_comments` * Add Venmo 'TokenIssuance' gateway rejection reason * Add `AmountNotSupportedByProcessor` to validation error ## 3.56.0 * Add PayPalHere details * Add `networkResponseCode` and `networkResponseText` to transactions and verifications * Add `cavv`, `xid`, `ds_transaction_id`, `eci_flag`, and `three_d_secure_version`, to `three_d_secure_info` * Add `three_d_secure_info` to credit_card_verification * Add `GraphQLClient` to `BraintreeGateway` class ## 3.55.0 * Add `captureId` field to local_payment_details * Add `refundId` field to local_payment_details * Add `debugId` field to local_payment_details * Add `transactionFeeAmount` field to local_payment_details * Add `transactionFeeCurrencyIsoCode` field to local_payment_details * Add `refundFromTransactionFeeAmount` field to local_payment_details * Add `refundFromTransactionFeeCurrencyIsoCode` field to local_payment_details * Add `ds_transaction_id` and `three_d_secure_version` to 3DS pass thru fields * Add `payer_info` field to payment_method_nonce details * Add more specific timeout errors: (#105 thanks @bhargavrpatel) * Add `braintree.exceptions.http.timeout_error.ConnectTimeoutError` (child class of TimeoutError) * Add `braintree.exceptions.http.timeout_error.ReadTimeoutError` (child class of TimeoutError) * Add `room_tax` support for transaction sale * Add `no_show` support for transaction sale * Add `advanced_deposit` support for transaction sale * Add `fire_safe` support for transaction sale * Add `property_phone` support for transaction sale * Add `additional_charges` support for transaction sale * Add `PostalCodeIsRequiredForCardBrandAndProcessor` to validation errors * Fix issue where not found error could choke on `None` values (#109) ## 3.54.0 * Add `payment_method_nonce` field to `LocalPaymentCompleted` webhook * Add `transaction` field to `LocalPaymentCompleted` webhook * Add `LocalPaymentDetails` to transactions ## 3.53.0 * Add `refund_from_transaction_fee_amount` field to paypal_details * Add `refund_from_transaction_fee_currency_iso_code` field to paypal_details * Add `revoked_at` field to paypal_account * Add support for `PaymentMethodRevokedByCustomer` webhook ## 3.52.0 * Deprecate `GrantedPaymentInstrumentUpdate` and add `GrantorUpdatedGrantedPaymentMethod` and `RecipientUpdatedGrantedPaymentMethod` * Add account_type support for transaction sale, verification, and payment_method create/update ## 3.51.0 * Add Hiper card type support * Add Hipercard card type support * Add `bin` to `PaymentMethodNonceDetails` * Clarify support for Python versions 3.6.x and 3.7.x * Add Error indicating pdf uploads too long for dispute evidence. * Add `GrantedPaymentMethodRevoked` webhook response objects ## 3.50.0 * Add `fraud_service_provider` field to `risk_data` * Add `authorization_expires_at` to `Transaction` * Remove invalid transaction tests * Allow PayPal payment ID and payer ID to be passed during transaction create * Add `travel_flight` support to industry-specific data * Add `processor_response_type` to `Transaction`, `AuthorizationAdjustment`, and `CreditCardVerification`. ## 3.49.0 * Add new field `network_transaction_id` in transaction response. * Add `external_vault` option to transaction sale. * Add `LocalPaymentCompleted` webhook. * Add `processor_response_type` to `Transaction`, `AuthorizationAdjustment`, and `CreditCardVerification`. ## 3.48.0 * Add ID to Transaction in SubscriptionChargedSuccessfully test webhook (#99, thanks @bjackson) * Fix dispute results in transactions not showing the correct status sometimes * Add Elo card type support ## 3.47.0 * Add processor respone code and processor response text to authorization adjustments subfield in transaction response. * Add support for Samsung Pay ## 3.46.0 * Allow payee ID to be passed in options params for transaction create * Add `merchant_id` alias to ConnectedMerchantStatusTransitioned and ConnectedMerchantPayPalStatusChanged Auth webhooks ## 3.45.0 * Add support for US Bank Account verifications API ## 3.44.0 * Add Dispute error ValidEvidenceRequiredToFinalize ## 3.43.0 * Add `oauth_access_revocation` to `WebhookNotification`s * Add support for `customer_id`, `disbursement_date` and `history_event_effective_date` in DisputeSearch * Remove `sepa_mandate_type` and `sepa_mandate_acceptance_location` params from `ClientToken` * Add support for VCR compelling evidence dispute representment ## 3.42.0 * Add support for `association_filter_id` in `Customer#find` ## 3.41.0 * Deprecated `LineItem/DiscountAmountMustBeGreaterThanZero` error in favor of `DiscountAmountCannotBeNegative` * Deprecated `LineItem/UnitTaxAmountMustBeGreaterThanZero` error in favor of `UnitTaxAmountCannotBeNegative` * Add support for `tax_amount` field on transaction `line_items` * Add support for `source_merchant_id` on webhooks * Add `find_all` static method to `TransactionLineItem` class * Add support for `profile_id` in Transaction#create options for VenmoAccounts ## 3.40.0 * Add level 3 fields to Transactions: * discount_amount * shipping_amount * ships_from_postal_code * Add support for transaction line items * Add support for tagged evidence in DisputeGateway#add_text_evidence (Beta release) * Update https certificate bundle ## 3.39.1 * Fix spec to expect PayPal transactions to move to settling rather than settled * Fix AchMandate.acceptedAt attribute parsing * Fix regression for `http_strategy.http_do` ## 3.39.0 * Add support for upgrading a PayPal future payment refresh token to a billing agreement * Fix braintree.Dispute.search to take a list of search criteria * Add logic to remove deprecation warnings for encodestring and decodestring when used with python 3 (#92) * Fix spec to expect PayPal transaction to settle immediately after successful capture * Add GrantedPaymentInstrumentUpdate webhook support * Add ability to create a transaction from a shared nonce * Add `options` -> `paypal` -> `shipping` for creating & updating customers as well as creating payment methods * Do not convert to Decimal if amount is None in AuthorizationAdjustement (#70) * Add `device_data_captured` field to `risk_data` * Add `bin_data` to `payment_method_nonce` ## 3.38.0 * Add iDEAL webhook support * Add AuthorizationAdjustment class and `authorization_adjustments` to Transaction * Coinbase is no longer a supported payment method. `PaymentMethodNoLongerSupported` will be returned for Coinbase operations * Add facilitated details to Transaction if present * Add `submit_for_settlement` option to `Subscription.retry_charge` * Add `options` -> `paypal` -> `description` for creating and updating subscriptions * Add Braintree.Dispute.find * Add braintree.Dispute.accept * Add braintree.Dispute.add_file_evidence * Add braintree.Dispute.add_text_evidence * Add braintree.Dispute.finalize * Add braintree.Dispute.find * Add braintree.Dispute.remove_evidence * Add braintree.Dispute.search * Add braintree.DocumentUpload ## 3.37.2 * Fix a bug where a null value for `amount` in `CreditCardVerification` would result in a `ValueError` * Add docstrings for AttributeGetter and Search. Thanks @sharma7n! * Add support for additional PayPal options when vaulting a PayPal Order ## 3.37.1 * Add gzip support * Fix a bug in CreditCardVerification where `amount` and `currency_iso_code` were always expected ## 3.37.0 * Fix a regression where `util/datetime_parser.py` was missing * Add support for Visa Checkout * Improve setup.py * Verification response includes amount and currency iso code * Add support for payee_email with paypal intent=order * Add support for skip_avs & skip_cvs ## 3.36.0 * Add ConnectedMerchantStatusTransitioned and ConnectedMerchantPayPalStatusChanged Auth webhooks ## 3.35.0 * Add LICENSE metadata. Thanks graingert. * Allow custom verification amount on payment method updates. * Fix a bug where `merchant_account.all` would attempt to fetch too many pages of merchant accounts ## 3.34.0 * Stop sending account_description field from us bank accounts * Add functionality to list all merchant accounts for a merchant with `merchant_account.all` ## 3.33.0 * Add option `skip_advanced_fraud_check` for transaction flows ## 3.32.0 * Update UsBank tests to use legal routing numbers * Allow setting a custom verification amount in `PaymentMethod` options * Allow setting processor specific fields for transactions and verifications ## 3.31.0 * Fix `UsBankAccount` support for `Customer`s * Added handling for unicode parameters. (Thanks @mgalgs) * Raise `ConfigurationError` for empty string credentials * Update `Grant` api to support options dictionary ## 3.30.0 * Add 'UsBankAccount' payment method ## 3.29.2 * Update links in docstrings * Remove Python 3.x-incompatible branch check * Remove references to SubMerchantAccount API ## 3.29.1 * Improve error handling around server timeouts ## 3.29.0 * Allow 'default_payment_method' option in Customer * Allow 'transaction_source' option in Transaction Sale ## 3.28.0 * Expose resource collection ids * Add order id to refund * Enable 3DS pass thru ## 3.27.0 * Add method of revoking OAuth access tokens ## 3.26.1 * Correct issue with setup.py ## 3.26.0 * Add Transaction `update_details` * Support for Too Many Requests response codes * Add SubMerchantAccount object with associate objects * Allow more parameters to be sent on SubMerchantAccount create * Add SubMerchantAccount update * Handle validation errors for SubMerchantAccount create / update ## 3.25.0 * Add AccountUpdaterDailyReport webhook parsing ## 3.24.0 * Add Verification#create * Add options to `submit_for_settlement` transaction flows * Update https certificate bundle * Support environment settings with strings ## 3.23.0 * Add better defaults to client token generation when using an access token by consolidating client token defaults into ClientTokenGateway * Add PaymentMethodGateway#revoke ## 3.22.0 * Add VenmoAccount * Add support for Set Transaction Context supplementary data. ## 3.21.0 * Add transaction to subscription successfully charged webhook * Add new ProcessorDoesNotSupportAuths error * Add support for partial settlement transactions * Add constants for dispute kind * Preserve backtrace when not wrapping HTTP exceptions * Add date_opened and date_won to dispute webhooks * Add support for searching transactions from oauth app * Support AMEX express checkout ## 3.20.0 * add source\_description to android pay and apple pay * add new android pay test nonces * add support for amex rewards transactions * add billing\_agreement\_id to paypalaccount ## 3.19.0 * Add new test payment method nonces * Allow passing description on PayPal transactions ## 3.18.0 * Fix oauth authentication * Fix python 3 syntax ## 3.17.0 * Add oauth support ## 3.16.0 * Add support for Android Pay ## 3.15.0 * Validate webhook challenge payload ## 3.14.0 * Add 3DS server side fields ## 3.13.0 * Add attribute to customer * Add coinbase constant * Add European test nonce ## 3.12.0 * Add support for new SEPA workflow ## 3.11.1 * Fix test failures in Python 3.3+ ## 3.11.0 * Accept additional params in PaymentMethod.create() ## 3.10.0 * Add 3D Secure transaction fields * Add ability to create nonce from vaulted payment methods ## 3.9.0 * Support Coinbase accounts * Surface Apple Pay payment instrument name in responses * Expose subscription status events * Support SEPA bank accounts for customer * Improve documentation ## 3.8.0 * Add error code constants * Allow PayPal parameters to be sent in options.paypal ## 3.7.0 * Add risk_data to Transaction and Verification with Kount decision and id * Add verification_amount an option when creating a credit card * Add TravelCruise industry type to Transaction * Add room_rate to Lodging industry type * Add CreditCard#verification as the latest verification on that credit card * Add ApplePay support to all endpoints that may return ApplePayCard objects * Align WebhookTesting with other client libraries ## 3.6.0 * Allow descriptor to be passed in Funding Details options params for Merchant Account create and update. ## 3.5.0 * Add additional_processor_response to transaction ## 3.4.1 * Allow payee_email to be passed in options params for Transaction create ## 3.4.0 * Added paypal specific fields to transaction calls * Added SettlementPending, SettlementDeclined transaction statuses ## 3.3.0 * Add Descriptor url support * Fix client token version type ## 3.2.0 * Support credit card options and billing address in PaymentMethod.create * Add PaymentMethod.update * Add associated subscriptions to PayPalAccount * Test refactoring and cleanup ## 3.1.1 * Add support for v.zero SDKs ## 3.0.0 * Drop Python 2.5 support * Remove use_unsafe_ssl option * Remove httplib strategy and pycurl strategy * Add Python 3.3+ support ## 2.29.1 * Make webhook parsing more robust with newlines * Add messages to InvalidSignature exceptions ## 2.29.0 * Include Dispute information on Transaction * Search for Transactions disputed on a certain date ## 2.28.0 * Disbursement Webhooks ## 2.27.0 * Fix using instantiated Configuration objects without first calling Configuration.configure * Accept billing_address_id on transaction create * Expose current_billing_cycle on addons and discounts ## 2.26.0 * Merchant account find API ## 2.25.0 * Merchant account update API * Merchant account create API v2 ## 2.24.1 * Update configuration URLs ## 2.24.0 * Add partnership support * Add partner configuration ## 2.23.1 * Add configuration option for custom HTTP strategies ## 2.23.0 * Adds hold_in_escrow method * Add error codes for verification not supported error * Add company_name and tax_id to merchant account create * Adds cancel_release methods * Adds release_from_escrow functionality * Adds owner_phone to merchant account signature. * Adds merchant account phone error code. ## 2.22.0 * Adds device data to transactions, customers, and credit cards. ## 2.21.0 * Adds disbursement details to transactions. * Adds image_url to transactions. ## 2.20.0 * Support requests >= 1.0 * Add new validation errors and rename old ones ## 2.19.0 * Adds channel field to transactions. ## 2.18.0 * Add additional card types for card type indicators ## 2.17.0 * Adds verification search ## 2.16.0 * Additional card information, such as prepaid, debit, commercial, Durbin regulated, healthcare, and payroll, are returned on credit card responses * Allows transactions to be specified as recurring ## 2.15.0 * Adds prepaid attribute to credit cards (possible values of: Yes, No, Unknown) ## 2.14.2 * Add settling transaction status to transaction search ## 2.14.1 * Adds new package braintree.util.http_stategy to setup.py ## 2.14.0 * Removes relative imports for python 3.0 (thanks [MichaelBlume](https://github.com/MichaelBlume)) * Adds webhook gateways for parsing, verifying, and testing incoming notifications * Allow specifying the http strategy to use (PycURL, httplib, requests) ## 2.13.0 * Adds search for duplicate credit cards given a payment method token * Adds flag to fail saving credit card to vault if card is duplicate ## 2.12.3 * Exposes plan_id on transactions ## 2.12.2 * Added error code for invalid purchase order number * Fixed zip_safe=False error when building (GitHub issue #17) ## 2.12.1 * Added error message for merchant accounts that do not support refunds ## 2.12.0 * Added ability to retrieve all Plans, AddOns, and Discounts * Added Transaction cloning ## 2.11.0 * Added SettlementBatchSummary ## 2.10.1 * Enabled gzip encoding for HTTP requests * Fixed handling of long integers when generating xml (thanks [glencoates](https://github.com/glencoates)) * Added new error code ## 2.10.0 * Added subscription_details to Transaction * Added flag to store in vault only when a transaction is successful * Added new error code ## 2.9.1 * Added improvements to unicode handling. ## 2.9.0 * Added a new transaction state, AuthorizationExpired. * Enabled searching by authorization_expired_at. ## 2.8.0 * Added next_billing_date and transaction_id to subscription search * Added address_country_name to customer search * Added new error codes ## 2.7.0 * Added Customer search * Added dynamic descriptors to Subscriptions and Transactions * Added level 2 fields to Transactions: * tax_amount * tax_exempt * purchase_order_number ## 2.6.1 * Added billing_address_id to allowed parameters for credit cards create and update * Allow searching on subscriptions that are currently in a trial period using in_trial_period ## 2.6.0 * Added ability to perform multiple partial refunds on Transactions * Deprecated Transaction refund_id in favor of refund_ids * Added revert_subscription_on_proration_failure flag to Subscription update that specifies how a Subscription should react to a failed proration charge * Deprecated Subscription next_bill_amount in favor of next_billing_period_amount * Added pycurl dependency in place of M2Crypto for better cross-platform compatibility * Added new fields to Subscription: * balance * paid_through_date * next_billing_period_amount ## 2.5.0 * Added AddOns/Discounts * Enhanced Subscription search * Enhanced Transaction search * Added constants for CreditCardVerification statuses * Added Expired and Pending statuses to Subscription * Allowed prorate_charges to be specified on Subscription update * Allowed argument lists and literal lists when searching for Subscriptions and Transactions * Added AddOn/Discount details to Transactions that were created from a Subscription * All Braintree exceptions now inherit from BraintreeError superclass * Removed 13 digit Visa Sandbox Credit Card number and replaced it with a 16 digit Visa * Made gateway operations threadsafe when using multiple configurations * Added new fields to Subscription: * billing_day_of_month * days_past_due * first_billing_date * never_expires * number_of_billing_cycles ## 2.4.1 * Added support for M2Crypto version 0.20.1, which is the default for Ubuntu Lucid (thanks [foresto](https://github.com/foresto)) ## 2.4.0 * Added unified message to ErrorResult * Added ability to specify country using country_name, country_code_alpha2, country_code_alpha3, or country_code_numeric (see [ISO_3166-1](https://en.wikipedia.org/wiki/ISO_3166-1)) * Renamed Subscription retryCharge to retry_charge * Added gateway_rejection_reason to Transaction and Verification * Allow searching with date objects (in addition to datetime) * When creating a Subscription, return failed transaction on the ErrorResult if the initial transaction is not successful ## 2.3.0 * Added unified TransparentRedirect url and confirm methods and deprecated old methods * Added methods to CreditCard to allow searching on expiring and expired credit cards * Allow credit card verification against a specified merchant account * Added all method on Customer to retrieve all customers * Added ability to update a customer, credit card, and billing address in one request * Allow updating the payment method token on a subscription * Added methods to navigate between a Transaction and its refund (in both directions) ## 2.2.1 * Use isinstance instead of type to cater to inheritance (thanks [danielgtaylor](https://github.com/danielgtaylor)) ## 2.2.0 * Prevent race condition when pulling back collection results -- search results represent the state of the data at the time the query was run * Rename ResourceCollection's approximate_size to maximum_size because items that no longer match the query will not be returned in the result set * Correctly handle HTTP error 426 (Upgrade Required) -- the error code is returned when your client library version is no longer compatible with the gateway ## 2.1.0 * Added transaction advanced search * Added ability to partially refund transactions * Added ability to manually retry past-due subscriptions * Added new transaction error codes * Allow merchant account to be specified when creating transactions * Allow creating a transaction with a vault customer and new credit card * Allow existing billing address to be updated when updating credit card ## 2.0.0 * Updated is_success on transaction results to return false on declined transactions * Search results now return a generator and will automatically paginate data * Allow passing cardholder_name when creating transactions ## 1.2.0 * Renamed ValidationErrorCollection#all to deep_errors and made it a property * Added the ability to make a credit card the default card for a customer * Updated Quick Start in README.md to show a workflow with error checking ## 1.1.0 * Added subscription search * Return associated subscriptions when finding credit cards * Raise down for maintenance error instead of forged query string error on 503 responses * Updated SSL CA file ## 1.0.0 * Initial release braintree_python-3.57.1/README.md0000644000175000017500000000725713545202423014557 0ustar hlehle# Braintree Python library The Braintree Python library provides integration access to the Braintree Gateway. ## Please Note > **The Payment Card Industry (PCI) Council has [mandated](https://blog.pcisecuritystandards.org/migrating-from-ssl-and-early-tls) that early versions of TLS be retired from service. All organizations that handle credit card information are required to comply with this standard. As part of this obligation, Braintree is updating its services to require TLS 1.2 for all HTTPS connections. Braintree will also require HTTP/1.1 for all connections. Please see our [technical documentation](https://github.com/paypal/tls-update) for more information.** ## Dependencies * [requests](http://docs.python-requests.org/en/latest/) The Braintree Python SDK is tested against Python versions 2.7.9, 3.3.5 and 3.7.0. ## Upgrading from 2.x.x to 3.x.x On Python 2.6 or 2.7 with default settings / requests: No changes are required to upgrade to version 3. On Python 2.6 or 2.7 with pycurl, httplib, or use_unsafe_ssl = True: Install requests and test that you are able to connect to the Sandbox environment with version 3 and without specifying an HTTP strategy. The use_unsafe_ssl parameter will be ignored. On Python 2.5: Python 2.5 isn't supported by version 3 of the library. Most code that runs on 2.5 will work unmodified on Python 2.6. After making sure your code works on Python 2.6, follow the instructions above for upgrading from pycurl / httplib to requests. ## Documentation * [Official documentation](https://developers.braintreepayments.com/ios+python/start/hello-server) ## Quick Start Example import braintree gateway = braintree.BraintreeGateway( braintree.Configuration( environment=braintree.Environment.Sandbox merchant_id="your_merchant_id", public_key="your_public_key", private_key="your_private_key", ) ) result = gateway.transaction.sale({ "amount": "1000.00", "payment_method_nonce": nonce_from_the_client, "options": { "submit_for_settlement": True } }) if result.is_success: print("success!: " + result.transaction.id) elif result.transaction: print("Error processing transaction:") print(" code: " + result.transaction.processor_response_code) print(" text: " + result.transaction.processor_response_text) else: for error in result.errors.deep_errors: print("attribute: " + error.attribute) print(" code: " + error.code) print(" message: " + error.message) ## Developing 1. Create a [virtualenv](https://virtualenv.pypa.io/) called `venv`: ``` virtualenv venv ``` 2. Start the virtualenv: ``` source venv/bin/activate ``` 3. Install dependencies: ``` pip install -r requirements.txt ``` ## Developing (Docker) The `Makefile` and `Dockerfile` will build an image containing the dependencies and drop you to a terminal where you can run tests. ``` make ``` ## Testing Our friends at [Venmo](https://venmo.com) have [an open source library](https://github.com/venmo/btnamespace) designed to simplify testing of applications using this library. If you wish to run the tests, make sure you are set up for development (see instructions above). The unit specs can be run by anyone on any system, but the integration specs are meant to be run against a local development server of our gateway code. These integration specs are not meant for public consumption and will likely fail if run on your system. To run unit tests use rake (`rake test:unit`) or nose (`nosetests tests/unit`). ## License See the [LICENSE](LICENSE) file for more info. braintree_python-3.57.1/.gitignore0000644000175000017500000000006413545202423015255 0ustar hlehle*.pyc /dist /docs/_build /tags MANIFEST build /venv braintree_python-3.57.1/requirements.txt0000644000175000017500000000010613545202423016546 0ustar hlehlerequests>=0.11.1,<3.0 mock>=2.0,<3.0 nose>=1.3.7,<2.0 twine>=1.9,<2.0 braintree_python-3.57.1/ci.sh0000755000175000017500000000030113545202423014211 0ustar hlehle#!/bin/bash if [[ "$1" == "http" ]]; then python_tests="test:http" fi if [[ "$1" == "python3" ]]; then /usr/local/lib/python3.3/bin/nosetests-3.3 else env rake $python_tests --trace fi braintree_python-3.57.1/docs/0000755000175000017500000000000013545202423014215 5ustar hlehlebraintree_python-3.57.1/docs/successful_result.rst0000644000175000017500000000016213545202423020523 0ustar hlehleSuccessful Result ===================================== .. automodule:: braintree.successful_result :members: braintree_python-3.57.1/docs/transparent_redirect.rst0000644000175000017500000000017013545202423021167 0ustar hlehleTransparent Redirect ===================================== .. automodule:: braintree.transparent_redirect :members: braintree_python-3.57.1/docs/validation_error_collection.rst0000644000175000017500000000020613545202423022523 0ustar hlehleValidation Error Collection ===================================== .. automodule:: braintree.validation_error_collection :members: braintree_python-3.57.1/docs/subscription.rst0000644000175000017500000000015013545202423017467 0ustar hlehleSubscription ===================================== .. automodule:: braintree.subscription :members: braintree_python-3.57.1/docs/address.rst0000644000175000017500000000013613545202423016374 0ustar hlehleAddress ===================================== .. automodule:: braintree.address :members: braintree_python-3.57.1/docs/validation_error.rst0000644000175000017500000000016013545202423020307 0ustar hlehleValidation Error ===================================== .. automodule:: braintree.validation_error :members: braintree_python-3.57.1/docs/exceptions/0000755000175000017500000000000013545202423016376 5ustar hlehlebraintree_python-3.57.1/docs/exceptions/upgrade_required_error.rst0000644000175000017500000000020713545202423023667 0ustar hlehleUpgrade Required Error ===================================== .. automodule:: braintree.exceptions.upgrade_required_error :members: braintree_python-3.57.1/docs/exceptions/unexpected_error.rst0000644000175000017500000000017313545202423022506 0ustar hlehleUnexpected Error ===================================== .. automodule:: braintree.exceptions.unexpected_error :members: braintree_python-3.57.1/docs/exceptions/authorization_error.rst0000644000175000017500000000020113545202423023232 0ustar hlehleAuthorization Error ===================================== .. automodule:: braintree.exceptions.authorization_error :members: braintree_python-3.57.1/docs/exceptions/server_error.rst0000644000175000017500000000016313545202423021647 0ustar hlehleServer Error ===================================== .. automodule:: braintree.exceptions.server_error :members: braintree_python-3.57.1/docs/exceptions/down_for_maintenance_error.rst0000644000175000017500000000021713545202423024520 0ustar hlehleDown For Maintenance Error ===================================== .. automodule:: braintree.exceptions.down_for_maintenance_error :members: braintree_python-3.57.1/docs/exceptions/forged_query_string_error.rst0000644000175000017500000000021513545202423024420 0ustar hlehleForged Query String Error ===================================== .. automodule:: braintree.exceptions.forged_query_string_error :members: braintree_python-3.57.1/docs/exceptions/authentication_error.rst0000644000175000017500000000020313545202423023353 0ustar hlehleAuthentication Error ===================================== .. automodule:: braintree.exceptions.authentication_error :members: braintree_python-3.57.1/docs/exceptions/not_found_error.rst0000644000175000017500000000017113545202423022333 0ustar hlehleNot Found Error ===================================== .. automodule:: braintree.exceptions.not_found_error :members: braintree_python-3.57.1/docs/resource_collection.rst0000644000175000017500000000016613545202423021014 0ustar hlehleResource Collection ===================================== .. automodule:: braintree.resource_collection :members: braintree_python-3.57.1/docs/customer.rst0000644000175000017500000000014013545202423016603 0ustar hlehleCustomer ===================================== .. automodule:: braintree.customer :members: braintree_python-3.57.1/docs/credit_card.rst0000644000175000017500000000014613545202423017213 0ustar hlehleCredit Card ===================================== .. automodule:: braintree.credit_card :members: braintree_python-3.57.1/docs/transaction.rst0000644000175000017500000000014613545202423017275 0ustar hlehleTransaction ===================================== .. automodule:: braintree.transaction :members: braintree_python-3.57.1/docs/environment.rst0000644000175000017500000000014613545202423017314 0ustar hlehleEnvironment ===================================== .. automodule:: braintree.environment :members: braintree_python-3.57.1/docs/index.rst0000644000175000017500000000254513545202423016064 0ustar hlehle.. Braintree documentation master file, created by sphinx-quickstart on Mon Mar 29 14:46:55 2010. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Braintree Python Client Library ===================================== The Braintree library provides integration access to the Braintree Gateway. Quick Start ----------- See: https://developers.braintreepayments.com/start/hello-server/python Braintree Objects ----------------- .. toctree:: :maxdepth: 2 address credit_card credit_card_verification customer subscription transaction Utility Objects --------------- .. toctree:: :maxdepth: 2 resource_collection transparent_redirect successful_result Errors ------ .. toctree:: :maxdepth: 2 error_codes error_result validation_error validation_error_collection Configuration ------------- .. toctree:: :maxdepth: 2 configuration environment Exceptions ---------- .. toctree:: :maxdepth: 2 exceptions/authentication_error exceptions/authorization_error exceptions/down_for_maintenance_error exceptions/forged_query_string_error exceptions/not_found_error exceptions/server_error exceptions/unexpected_error exceptions/upgrade_required_error Indices ------- * :ref:`genindex` * :ref:`modindex` * :ref:`search` braintree_python-3.57.1/docs/_static/0000755000175000017500000000000013545202423015643 5ustar hlehlebraintree_python-3.57.1/docs/_static/.git_empty_dir0000644000175000017500000000000013545202423020471 0ustar hlehlebraintree_python-3.57.1/docs/configuration.rst0000644000175000017500000000015213545202423017614 0ustar hlehleConfiguration ===================================== .. automodule:: braintree.configuration :members: braintree_python-3.57.1/docs/Makefile0000644000175000017500000000607413545202423015664 0ustar hlehle# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Braintree.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Braintree.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." braintree_python-3.57.1/docs/credit_card_verification.rst0000644000175000017500000000020013545202423021744 0ustar hlehleCredit Card Verification ===================================== .. automodule:: braintree.credit_card_verification :members: braintree_python-3.57.1/docs/error_codes.rst0000644000175000017500000000014613545202423017256 0ustar hlehleError Codes ===================================== .. automodule:: braintree.error_codes :members: braintree_python-3.57.1/docs/conf.py0000644000175000017500000001446013545202423015521 0ustar hlehle# -*- coding: utf-8 -*- # # Braintree documentation build configuration file, created by # sphinx-quickstart on Mon Mar 29 14:46:55 2010. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.append(os.path.abspath('.')) sys.path.insert(0, os.path.dirname(__file__) + '/../') import braintree # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. #templates_path = ['_templates'] templates_path = [] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Braintree' copyright = u'2012, Braintree' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = braintree.version.Version # The full version, including alpha/beta/rc tags. release = braintree.version.Version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'Braintreedoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'Braintree.tex', u'Braintree Documentation', u'Braintree', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True braintree_python-3.57.1/docs/error_result.rst0000644000175000017500000000015013545202423017472 0ustar hlehleError Result ===================================== .. automodule:: braintree.error_result :members: braintree_python-3.57.1/MANIFEST.in0000644000175000017500000000003013545202423015014 0ustar hlehleinclude braintree/ssl/* braintree_python-3.57.1/setup.py0000644000175000017500000000243013545202423014776 0ustar hlehletry: from setuptools import setup except ImportError: from distutils.core import setup long_description = """ The Braintree Python SDK provides integration access to the Braintree Gateway. 1. https://github.com/braintree/braintree_python - README and Samples 2. https://developers.braintreepayments.com/python/sdk/server/overview - API Reference """ setup( name="braintree", version="3.57.1", description="Braintree Python Library", long_description=long_description, author="Braintree", author_email="support@braintreepayments.com", url="https://developers.braintreepayments.com/python/sdk/server/overview", packages=["braintree", "braintree.dispute_details", "braintree.exceptions", "braintree.exceptions.http", "braintree.merchant_account", "braintree.util", "braintree.test"], package_data={"braintree": ["ssl/*"]}, install_requires=["requests>=0.11.1,<3.0"], zip_safe=False, license="MIT", classifiers=[ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5" ] ) braintree_python-3.57.1/setup.cfg0000644000175000017500000000003413545202423015103 0ustar hlehle[bdist_wheel] universal = 1 braintree_python-3.57.1/Makefile0000644000175000017500000000032513545202423014725 0ustar hlehle.PHONY: console build console: build docker run -it -v="$(PWD):/braintree-python" --net="host" braintree-python /bin/bash -l -c "pip install -r requirements.txt;bash" build: docker build -t braintree-python . braintree_python-3.57.1/ACKNOWLEDGEMENTS.md0000644000175000017500000000026213545202423016141 0ustar hlehleAcknowledgements ---------------- The Braintree SDK uses code from the following libraries: * [requests](https://github.com/kennethreitz/requests), Apache License, Version 2.0 braintree_python-3.57.1/.github/0000755000175000017500000000000013545202423014625 5ustar hlehlebraintree_python-3.57.1/.github/ISSUE_TEMPLATE.md0000644000175000017500000000101213545202423017324 0ustar hlehle### General information * SDK/Library version: * Environment: * Language, language version, and OS: ### Issue description braintree_python-3.57.1/.github/PULL_REQUEST_TEMPLATE.md0000644000175000017500000000014213545202423020423 0ustar hlehle# Summary # Checklist - [ ] Added changelog entry - [ ] Ran unit tests (`nosetests tests/unit`) braintree_python-3.57.1/.github/CODEOWNERS0000644000175000017500000000002113545202423016211 0ustar hlehle* @braintree/sdk