pax_global_header00006660000000000000000000000064126276131150014516gustar00rootroot0000000000000052 comment=24edd45e117fe64e77df08740b2ec6633a1157f7 braintree_python-3.23.0/000077500000000000000000000000001262761311500151575ustar00rootroot00000000000000braintree_python-3.23.0/.gitignore000066400000000000000000000000641262761311500171470ustar00rootroot00000000000000*.pyc /dist /docs/_build /tags MANIFEST build /venv braintree_python-3.23.0/CHANGELOG.md000066400000000000000000000256201262761311500167750ustar00rootroot00000000000000## 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](http://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](http://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](http://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](http://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.23.0/LICENSE000066400000000000000000000021211262761311500161600ustar00rootroot00000000000000(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.23.0/MANIFEST.in000066400000000000000000000000301262761311500167060ustar00rootroot00000000000000include braintree/ssl/* braintree_python-3.23.0/README.md000066400000000000000000000051161262761311500164410ustar00rootroot00000000000000# Braintree Python Client Library The Braintree library provides integration access to the Braintree Gateway. ## Dependencies * Python 2.6, 2.7, 3.3, or 3.4 * [requests](http://docs.python-requests.org/en/latest/) ## 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 braintree.Configuration.configure( braintree.Environment.Sandbox, "your_merchant_id", "your_public_key", "your_private_key" ) result = braintree.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) ## 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. 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`). ## Open Source Attribution A list of open source projects that help power Braintree can be found [here](https://www.braintreepayments.com/developers/open-source). ## License See the LICENSE file. braintree_python-3.23.0/Rakefile000066400000000000000000000014701262761311500166260ustar00rootroot00000000000000task :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 upload" end end braintree_python-3.23.0/braintree/000077500000000000000000000000001262761311500171325ustar00rootroot00000000000000braintree_python-3.23.0/braintree/__init__.py000066400000000000000000000073131262761311500212470ustar00rootroot00000000000000from 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.android_pay_card import AndroidPayCard from braintree.amex_express_checkout_card import AmexExpressCheckoutCard 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.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_search import CustomerSearch from braintree.customer_gateway import CustomerGateway from braintree.discount import Discount from braintree.discount_gateway import DiscountGateway from braintree.descriptor import Descriptor from braintree.error_codes import ErrorCodes from braintree.error_result import ErrorResult from braintree.errors import Errors from braintree.environment import Environment from braintree.merchant import Merchant from braintree.merchant_account import MerchantAccount from 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_gateway import MerchantAccountGateway from braintree.payment_method import PaymentMethod from braintree.payment_method_nonce import PaymentMethodNonce from braintree.unknown_payment_method import UnknownPaymentMethod from braintree.payment_instrument_type import PaymentInstrumentType from braintree.paypal_account import PayPalAccount from braintree.partner_merchant import PartnerMerchant from braintree.plan import Plan from braintree.plan_gateway import PlanGateway from braintree.resource_collection import ResourceCollection from braintree.risk_data import RiskData from braintree.three_d_secure_info import ThreeDSecureInfo from braintree.search import Search from braintree.settlement_batch_summary import SettlementBatchSummary from braintree.subscription import Subscription from braintree.subscription_gateway import SubscriptionGateway from braintree.subscription_status_event import SubscriptionStatusEvent from braintree.status_event import StatusEvent from braintree.testing_gateway import TestingGateway from braintree.transaction import Transaction from braintree.transaction_gateway import TransactionGateway from braintree.transaction_search import TransactionSearch from braintree.signature_service import SignatureService from braintree.disbursement import Disbursement from braintree.subscription_search import SubscriptionSearch from braintree.successful_result import SuccessfulResult from braintree.transaction_amounts import TransactionAmounts from braintree.transaction_details import TransactionDetails from braintree.transparent_redirect import TransparentRedirect from braintree.transparent_redirect_gateway import TransparentRedirectGateway from braintree.validation_error_collection import ValidationErrorCollection 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 from braintree.europe_bank_account import EuropeBankAccount from braintree.venmo_account import VenmoAccount braintree_python-3.23.0/braintree/add_on.py000066400000000000000000000003231262761311500207260ustar00rootroot00000000000000from braintree.configuration import Configuration from braintree.modification import Modification class AddOn(Modification): @staticmethod def all(): return Configuration.gateway().add_on.all() braintree_python-3.23.0/braintree/add_on_gateway.py000066400000000000000000000010021262761311500224420ustar00rootroot00000000000000import 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.23.0/braintree/address.py000066400000000000000000000061761262761311500211430ustar00rootroot00000000000000from 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", "street_address", "extended_address", "postal_code", "country_code_alpha2"] 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.23.0/braintree/address_gateway.py000066400000000000000000000046771262761311500226700ustar00rootroot00000000000000import 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.23.0/braintree/amex_express_checkout_card.py000066400000000000000000000010751262761311500250700ustar00rootroot00000000000000import 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.23.0/braintree/android_pay_card.py000066400000000000000000000014251262761311500227700ustar00rootroot00000000000000import 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.23.0/braintree/apple_pay_card.py000066400000000000000000000017641262761311500224570ustar00rootroot00000000000000import 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.23.0/braintree/attribute_getter.py000066400000000000000000000011251262761311500230600ustar00rootroot00000000000000class AttributeGetter(object): 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.23.0/braintree/braintree_gateway.py000066400000000000000000000057251262761311500232110ustar00rootroot00000000000000from 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.customer_gateway import CustomerGateway from braintree.discount_gateway import DiscountGateway from braintree.merchant_account_gateway import MerchantAccountGateway from braintree.merchant_gateway import MerchantGateway from braintree.oauth_gateway import OAuthGateway from braintree.paypal_account_gateway import PayPalAccountGateway from braintree.payment_method_gateway import PaymentMethodGateway from braintree.payment_method_nonce_gateway import PaymentMethodNonceGateway 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.transparent_redirect_gateway import TransparentRedirectGateway from braintree.credit_card_verification_gateway import CreditCardVerificationGateway from braintree.webhook_notification_gateway import WebhookNotificationGateway from braintree.webhook_testing_gateway import WebhookTestingGateway 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.add_on = AddOnGateway(self) self.address = AddressGateway(self) self.client_token = ClientTokenGateway(self) self.credit_card = CreditCardGateway(self) self.customer = CustomerGateway(self) self.discount = DiscountGateway(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.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) braintree_python-3.23.0/braintree/client_token.py000066400000000000000000000014511262761311500221630ustar00rootroot00000000000000import 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", "sepa_mandate_type", "sepa_mandate_acceptance_location", "version", "merchant_account_id", {"options": ["make_default", "verify_card", "fail_on_duplicate_payment_method"]} ] braintree_python-3.23.0/braintree/client_token_gateway.py000066400000000000000000000021101262761311500236750ustar00rootroot00000000000000import 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.23.0/braintree/coinbase_account.py000066400000000000000000000005541262761311500230070ustar00rootroot00000000000000import 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.23.0/braintree/configuration.py000066400000000000000000000103041262761311500223510ustar00rootroot00000000000000import os import sys import braintree from braintree.exceptions.configuration_error import ConfigurationError from braintree.credentials_parser import CredentialsParser 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 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 "4" 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 self.merchant_id = merchant_id self.public_key = public_key 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 http(self): return braintree.util.http.Http(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.23.0/braintree/credentials_parser.py000066400000000000000000000043411262761311500233570ustar00rootroot00000000000000import os import sys import braintree from braintree.exceptions.configuration_error import ConfigurationError from braintree.environment import Environment class CredentialsParser(object): ENVIRONMENTS = { "development": Environment.Development, "integration": Environment.Development, "qa": Environment.QA, "sandbox": Environment.Sandbox, "production": Environment.Production } 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 self.ENVIRONMENTS.get(parts[1], None) def get_merchant_id(self, credential): parts = credential.split("$") return parts[2] braintree_python-3.23.0/braintree/credit_card.py000066400000000000000000000246351262761311500217610ustar00rootroot00000000000000import 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 } }) print(result.credit_card.token) print(result.credit_card.masked_number) For more information on CreditCards, see https://developers.braintreepayments.com/ios+python/reference/request/credit-card/create """ 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.JCB * Braintree.CreditCard.Laser * 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" JCB = "JCB" Laser = "Laser" 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 = 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): """ Create a nonce for a credit card in your Braintree vault that can be used by another Braintree merchant. A credit card token and a receiving merchant ID are required: result = braintree.CreditCard.forward( credit_card.token, "another_merchant_public_id" }) """ 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", "venmo_sdk_session"] 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") options.append("fail_on_duplicate_payment_method") 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.23.0/braintree/credit_card_gateway.py000066400000000000000000000141371262761311500234760ustar00rootroot00000000000000import 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): forwardParams = { "payment_method": { "payment_method_token": credit_card_token, "receiving_merchant_id": receiving_merchant_id } } response = self.config.http().post(self.config.base_merchant_path() + "/payment_methods/forward", forwardParams) if "payment_method_nonce" in response: return SuccessfulResult({"nonce": response["payment_method_nonce"]["nonce"]}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) 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 " + 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.23.0/braintree/credit_card_verification.py000066400000000000000000000032621262761311500245140ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter from braintree.configuration import Configuration from braintree.risk_data import RiskData 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 "processor_response_code" not in attributes: self.processor_response_code = None if "processor_response_text" not in attributes: self.processor_response_text = None if "risk_data" in attributes: self.risk_data = RiskData(attributes["risk_data"]) else: self.risk_data = None @staticmethod def find(verification_id): return Configuration.gateway().verification.find(verification_id) @staticmethod def search(*query): return Configuration.gateway().verification.search(*query) def __eq__(self, other): if not isinstance(other, CreditCardVerification): return False return self.id == other.id braintree_python-3.23.0/braintree/credit_card_verification_gateway.py000066400000000000000000000047511262761311500262410ustar00rootroot00000000000000from 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 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")] braintree_python-3.23.0/braintree/credit_card_verification_search.py000066400000000000000000000023611262761311500260400ustar00rootroot00000000000000from 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.23.0/braintree/customer.py000066400000000000000000000212741262761311500213530ustar00rootroot00000000000000import 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.coinbase_account import CoinbaseAccount from braintree.venmo_account import VenmoAccount 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 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 } }, "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/ios+python/reference/request/customer/create """ def __repr__(self): detail_list = ["first_name", "last_name", "id"] 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): """ 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) @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", {"credit_card": CreditCard.create_signature()}, {"custom_fields": ["__any_key__"]} ] @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", {"credit_card": CreditCard.signature("update_via_customer")}, {"custom_fields": ["__any_key__"]} ] 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 braintree_python-3.23.0/braintree/customer_gateway.py000066400000000000000000000111611262761311500230660ustar00rootroot00000000000000import 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): try: if customer_id is None or customer_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/customers/" + customer_id) 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.23.0/braintree/customer_search.py000066400000000000000000000041421262761311500226730ustar00rootroot00000000000000from 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.23.0/braintree/descriptor.py000066400000000000000000000002471262761311500216650ustar00rootroot00000000000000from braintree.resource import Resource class Descriptor(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-3.23.0/braintree/disbursement.py000066400000000000000000000014211262761311500222060ustar00rootroot00000000000000from decimal import Decimal from braintree.resource import Resource from braintree.transaction_search import TransactionSearch from braintree.merchant_account import MerchantAccount class Disbursement(Resource): 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)]) braintree_python-3.23.0/braintree/disbursement_detail.py000066400000000000000000000011101262761311500235230ustar00rootroot00000000000000from 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.23.0/braintree/discount.py000066400000000000000000000003321262761311500213320ustar00rootroot00000000000000from braintree.modification import Modification from braintree.configuration import Configuration class Discount(Modification): @staticmethod def all(): return Configuration.gateway().discount.all() braintree_python-3.23.0/braintree/discount_gateway.py000066400000000000000000000010311262761311500230500ustar00rootroot00000000000000import 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.23.0/braintree/dispute.py000066400000000000000000000046721262761311500211720ustar00rootroot00000000000000from decimal import Decimal from braintree.attribute_getter import AttributeGetter from braintree.transaction_details import TransactionDetails class Dispute(AttributeGetter): class Status(object): """ Constants representing dispute statuses. Available types are: * braintree.Dispute.Status.Open * braintree.Dispute.Status.Won * braintree.Dispute.Status.Lost """ 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" def __init__(self, attributes): AttributeGetter.__init__(self, attributes) if self.amount is not None: self.amount = Decimal(self.amount) if "transaction" in attributes: self.transaction_details = TransactionDetails(attributes.pop("transaction")) braintree_python-3.23.0/braintree/environment.py000066400000000000000000000037701262761311500220570ustar00rootroot00000000000000import os import inspect 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): self.__name__ = name self.__server = server self.__port = port self.is_ssl = is_ssl self.ssl_certificate = ssl_certificate self.__auth_url = auth_url @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 @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) Environment.QA = Environment("qa", "gateway.qa.braintreepayments.com", "443", "http://auth.qa.venmo.com", True, Environment.braintree_root() + "/ssl/api_braintreegateway_com.ca.crt") Environment.Sandbox = Environment("sandbox", "api.sandbox.braintreegateway.com", "443", "https://auth.sandbox.venmo.com", True, Environment.braintree_root() + "/ssl/api_braintreegateway_com.ca.crt") Environment.Production = Environment("production", "api.braintreegateway.com", "443", "https://auth.venmo.com", True, Environment.braintree_root() + "/ssl/api_braintreegateway_com.ca.crt") braintree_python-3.23.0/braintree/error_codes.py000066400000000000000000000533121262761311500220160ustar00rootroot00000000000000class 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" LastNameIsInvalid = "91820" LastNameIsTooLong = "81806" LocalityIsInvalid = "91824" LocalityIsTooLong = "81807" PostalCodeInvalidCharacters = "81813" PostalCodeIsInvalid = "91826" PostalCodeIsRequired = "81808" 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" 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" class Options(object): UpdateExistingTokenIsInvalid = "91723" UpdateExistingTokenNotAllowed = "91729" VerificationAmountCannotBeNegative = "91739" VerificationAmountFormatIsInvalid = "91740" VerificationAmountNotSupportedByProcessor = "91741" VerificationMerchantAccountIdIsInvalid = "91728" VerificationMerchantAccountIsForbidden = "91743" VerificationMerchantAccountIsSuspended = "91742" 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 Merchant(object): CountryCannotBeBlank = "83603" CountryCodeAlpha2IsInvalid = "93607" CountryCodeAlpha2IsNotAccepted = "93606" CountryCodeAlpha3IsInvalid = "93605" CountryCodeAlpha3IsNotAccepted = "93604" CountryCodeNumericIsInvalid = "93609" CountryCodeNumericIsNotAccepted = "93608" CountryNameIsInvalid = "93611" CountryNameIsNotAccepted = "93610" EmailFormatIsInvalid = "93602" EmailIsRequired = "83601" InconsistentCountry = "93612" PaymentMethodsAreInvalid = "93613" 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 PaymentMethod(object): CannotForwardPaymentMethodType = "93106" PaymentMethodParamsAreRequired = "93101" NonceIsInvalid = "93102" NonceIsRequired = "93103" CustomerIdIsRequired = "93104" CustomerIdIsInvalid = "93105" PaymentMethodNonceConsumed = "93107" PaymentMethodNonceUnknown = "93108" PaymentMethodNonceLocked = "93109" AuthExpired = "92911" CannotHaveFundingSourceWithoutAccessToken = "92912" InvalidFundingSourceSelection = "92913" CannotUpdatePayPalAccountUsingPaymentMethodNonce = "92914" 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" AmountIsInvalid = AmountFormatIsInvalid = "81503" AmountIsRequired = "81502" AmountIsTooLarge = "81528" AmountMustBeGreaterThanZero = "81531" BillingAddressConflict = "91530" CannotBeVoided = "91504" CannotCancelRelease = "91562" CannotCloneCredit = "91543" 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" ChannelIsTooLong = "91550" ChannelIsTooLong = "91550" CreditCardIsRequired = "91508" CustomFieldIsInvalid = "91526" CustomFieldIsTooLong = "81527" CustomerDefaultPaymentMethodCardTypeIsNotAccepted = "81509" CustomerDoesNotHaveCreditCard = "91511" CustomerIdIsInvalid = "91510" HasAlreadyBeenRefunded = "91512" MerchantAccountDoesNotMatch3DSecureMerchantAccount = "91584" MerchantAccountDoesNotSupportMOTO = "91558" MerchantAccountDoesNotSupportRefunds = "91547" MerchantAccountIdIsInvalid = "91513" MerchantAccountIsSusped = "91514" # Deprecated MerchantAccountIsSuspended = "91514" MerchantAccountNameIsInvalid = "91513" # Deprecated 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" 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" TypeIsInvalid = "91523" TypeIsRequired = "91524" UnsupportedVoiceAuthorization = "91539" class Options(object): SubmitForSettlementIsRequiredForCloning = "91544" SubmitForSettlementIsRequiredForPayPalUnilateral = "91582" UseBillingForShippingDisabled = "91572" VaultIsDisabled = "91525" class PayPal(object): CustomFieldTooLong = "91580" class Industry(object): IndustryTypeIsInvalid = "93401" class Lodging(object): EmptyData = "93402" FolioNumberIsInvalid = "93403" CheckInDateIsInvalid = "93404" CheckOutDateIsInvalid = "93405" CheckOutDateMustFollowCheckInDate = "93406" UnknownDataField = "93407" class TravelCruise(object): EmptyData = "93408" UnknownDataField = "93409" TravelPackageIsInvalid = "93410" DepartureDateIsInvalid = "93411" LodgingCheckInDateIsInvalid = "93412" LodgingCheckOutDateIsInvalid = "93413" braintree_python-3.23.0/braintree/error_result.py000066400000000000000000000046621262761311500222430ustar00rootroot00000000000000import 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.23.0/braintree/errors.py000066400000000000000000000007121262761311500210200ustar00rootroot00000000000000from 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.23.0/braintree/europe_bank_account.py000066400000000000000000000014141262761311500235120ustar00rootroot00000000000000import 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.23.0/braintree/exceptions/000077500000000000000000000000001262761311500213135ustar00rootroot00000000000000braintree_python-3.23.0/braintree/exceptions/__init__.py000066400000000000000000000016341262761311500234300ustar00rootroot00000000000000from 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.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.23.0/braintree/exceptions/authentication_error.py000066400000000000000000000006301262761311500261140ustar00rootroot00000000000000from 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/ios+python/reference/general/exceptions#authentication-error """ pass braintree_python-3.23.0/braintree/exceptions/authorization_error.py000066400000000000000000000005111262761311500257730ustar00rootroot00000000000000from 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/ios+python/reference/general/exceptions#authorization-error """ pass braintree_python-3.23.0/braintree/exceptions/braintree_error.py000066400000000000000000000000521262761311500250460ustar00rootroot00000000000000class BraintreeError(Exception): pass braintree_python-3.23.0/braintree/exceptions/configuration_error.py000066400000000000000000000001671262761311500257510ustar00rootroot00000000000000from braintree.exceptions.unexpected_error import UnexpectedError class ConfigurationError(UnexpectedError): pass braintree_python-3.23.0/braintree/exceptions/down_for_maintenance_error.py000066400000000000000000000004551262761311500272610ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class DownForMaintenanceError(BraintreeError): """ Raised when the gateway is down for maintenance. See https://developers.braintreepayments.com/ios+python/reference/general/exceptions#down-for-maintenance """ pass braintree_python-3.23.0/braintree/exceptions/forged_query_string_error.py000066400000000000000000000005271262761311500271630ustar00rootroot00000000000000from 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/ios+python/reference/general/exceptions#forged-query-string """ pass braintree_python-3.23.0/braintree/exceptions/http/000077500000000000000000000000001262761311500222725ustar00rootroot00000000000000braintree_python-3.23.0/braintree/exceptions/http/__init__.py000066400000000000000000000003321262761311500244010ustar00rootroot00000000000000from 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.23.0/braintree/exceptions/http/connection_error.py000066400000000000000000000001641262761311500262150ustar00rootroot00000000000000from braintree.exceptions.unexpected_error import UnexpectedError class ConnectionError(UnexpectedError): pass braintree_python-3.23.0/braintree/exceptions/http/invalid_response_error.py000066400000000000000000000001711262761311500274200ustar00rootroot00000000000000from braintree.exceptions.unexpected_error import UnexpectedError class InvalidResponseError(UnexpectedError): pass braintree_python-3.23.0/braintree/exceptions/http/timeout_error.py000066400000000000000000000001611262761311500255410ustar00rootroot00000000000000from braintree.exceptions.unexpected_error import UnexpectedError class TimeoutError(UnexpectedError): pass braintree_python-3.23.0/braintree/exceptions/invalid_challenge_error.py000066400000000000000000000001671262761311500265320ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class InvalidChallengeError(BraintreeError): pass braintree_python-3.23.0/braintree/exceptions/invalid_signature_error.py000066400000000000000000000001671262761311500266110ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class InvalidSignatureError(BraintreeError): pass braintree_python-3.23.0/braintree/exceptions/not_found_error.py000066400000000000000000000005061262761311500250720ustar00rootroot00000000000000from 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/ios+python/reference/general/exceptions#not-found-error """ pass braintree_python-3.23.0/braintree/exceptions/server_error.py000066400000000000000000000005061262761311500244050ustar00rootroot00000000000000from 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/ios+python/reference/general/exceptions#server-error """ pass braintree_python-3.23.0/braintree/exceptions/test_operation_performed_in_production_error.py000066400000000000000000000003721262761311500331360ustar00rootroot00000000000000from 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.23.0/braintree/exceptions/unexpected_error.py000066400000000000000000000002461262761311500252440ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class UnexpectedError(BraintreeError): """ Raised for unknown or unexpected errors. """ pass braintree_python-3.23.0/braintree/exceptions/upgrade_required_error.py000066400000000000000000000004531262761311500264270ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class UpgradeRequiredError(BraintreeError): """ Raised for unsupported client library versions. See https://developers.braintreepayments.com/ios+python/reference/general/exceptions#upgrade-required-error """ pass braintree_python-3.23.0/braintree/facilitator_details.py000066400000000000000000000001541262761311500235120ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class FacilitatorDetails(AttributeGetter): pass braintree_python-3.23.0/braintree/ids_search.py000066400000000000000000000001471262761311500216120ustar00rootroot00000000000000from braintree.search import Search class IdsSearch: ids = Search.MultipleValueNodeBuilder("ids") braintree_python-3.23.0/braintree/merchant.py000066400000000000000000000001141262761311500213010ustar00rootroot00000000000000from braintree.resource import Resource class Merchant(Resource): pass braintree_python-3.23.0/braintree/merchant_account/000077500000000000000000000000001262761311500224475ustar00rootroot00000000000000braintree_python-3.23.0/braintree/merchant_account/__init__.py000066400000000000000000000004421262761311500245600ustar00rootroot00000000000000from 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.23.0/braintree/merchant_account/address_details.py000066400000000000000000000006071262761311500261560ustar00rootroot00000000000000from 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.23.0/braintree/merchant_account/business_details.py000066400000000000000000000010341262761311500263570ustar00rootroot00000000000000from 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.23.0/braintree/merchant_account/funding_details.py000066400000000000000000000006531262761311500261640ustar00rootroot00000000000000from 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.23.0/braintree/merchant_account/individual_details.py000066400000000000000000000011401262761311500266520ustar00rootroot00000000000000from 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.23.0/braintree/merchant_account/merchant_account.py000066400000000000000000000030361262761311500263400ustar00rootroot00000000000000from 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", "status", "master_merchant_account", "individual_details", "business_details", "funding_details"] 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.23.0/braintree/merchant_account_gateway.py000066400000000000000000000124101262761311500245400ustar00rootroot00000000000000from braintree.error_result import ErrorResult from braintree.merchant_account import MerchantAccount from braintree.resource import Resource 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 _post(self, url, params={}): response = self.config.http().post(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"]) 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.23.0/braintree/merchant_gateway.py000066400000000000000000000023051262761311500230260ustar00rootroot00000000000000from 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"]: merchant = Merchant(self.gateway, response["response"]["merchant"]) 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.23.0/braintree/modification.py000066400000000000000000000003601262761311500221500ustar00rootroot00000000000000from 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.23.0/braintree/oauth_credentials.py000066400000000000000000000001241262761311500231760ustar00rootroot00000000000000from braintree.resource import Resource class OAuthCredentials(Resource): pass braintree_python-3.23.0/braintree/oauth_gateway.py000066400000000000000000000050001262761311500223400ustar00rootroot00000000000000import 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 from braintree.util import Crypto 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 _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, params): params["client_id"] = self.config.client_id 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) url = self.config.environment.base_url + "/oauth/connect?" + query_string signature = self._compute_signature(url) return url + "&signature=" + signature + "&algorithm=SHA256" 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 def _compute_signature(self, url): return Crypto.sha256_hmac_hash(self.config.client_secret, url) braintree_python-3.23.0/braintree/partner_merchant.py000066400000000000000000000017721262761311500230470ustar00rootroot00000000000000from 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.23.0/braintree/payment_instrument_type.py000066400000000000000000000005451262761311500245160ustar00rootroot00000000000000 class PaymentInstrumentType(): PayPalAccount = "paypal_account" 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" braintree_python-3.23.0/braintree/payment_method.py000066400000000000000000000045431262761311500225270ustar00rootroot00000000000000import 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): return Configuration.gateway().payment_method.delete(payment_method_token) @staticmethod def create_signature(): return PaymentMethod.signature("create") @staticmethod def signature(type): signature = [ "billing_address_id", "cardholder_name", "customer_id", "cvv", "device_data", "device_session_id", "expiration_date", "expiration_month", "expiration_year", "number", "payment_method_nonce", "token", {"billing_address": Address.create_signature()}, {"options": [ "fail_on_duplicate_payment_method", "make_default", "verification_merchant_account_id", "verify_card", ] } ] 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", "verify_card", "verification_merchant_account_id", "venmo_sdk_session" ] }, {"billing_address" : Address.update_signature() + [{"options": ["update_existing"]}] } ] return signature braintree_python-3.23.0/braintree/payment_method_gateway.py000066400000000000000000000136741262761311500242550ustar00rootroot00000000000000import 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.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.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult 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 self._parse_payment_method(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): self.config.http().delete(self.config.base_merchant_path() + "/payment_methods/any/" + payment_method_token) return SuccessfulResult() def grant(self, payment_method_token, allow_vaulting): if payment_method_token is None or not str(payment_method_token).strip(): raise ValueError try: return self._post( "/payment_methods/grant", { "payment_method": { "shared_payment_method_token": payment_method_token, "allow_vaulting": allow_vaulting } }, "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 } }, None ) 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 None: return SuccessfulResult() else: payment_method = self._parse_payment_method(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 = self._parse_payment_method(response) return SuccessfulResult({"payment_method": payment_method}) def _parse_payment_method(self, response): if "paypal_account" in response: return PayPalAccount(self.gateway, response["paypal_account"]) elif "credit_card" in response: return CreditCard(self.gateway, response["credit_card"]) elif "europe_bank_account" in response: return EuropeBankAccount(self.gateway, response["europe_bank_account"]) elif "apple_pay_card" in response: return ApplePayCard(self.gateway, response["apple_pay_card"]) elif "android_pay_card" in response: return AndroidPayCard(self.gateway, response["android_pay_card"]) elif "amex_express_checkout_card" in response: return AmexExpressCheckoutCard(self.gateway, response["amex_express_checkout_card"]) elif "coinbase_account" in response: return CoinbaseAccount(self.gateway, response["coinbase_account"]) elif "venmo_account" in response: return VenmoAccount(self.gateway, response["venmo_account"]) elif "payment_method_nonce" in response: return PaymentMethodNonce(self.gateway, response["payment_method_nonce"]) elif "success" in response: return None else: name = list(response)[0] return UnknownPaymentMethod(self.gateway, response[name]) braintree_python-3.23.0/braintree/payment_method_nonce.py000066400000000000000000000015051262761311500237040ustar00rootroot00000000000000import braintree from braintree.resource import Resource from braintree.configuration import Configuration from braintree.three_d_secure_info import ThreeDSecureInfo 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 braintree_python-3.23.0/braintree/payment_method_nonce_gateway.py000066400000000000000000000031651262761311500254310ustar00rootroot00000000000000import 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 " + payment_method_token + " not found") def find(self, payment_method_nonce): try: 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 " + payment_method_nonce + " not found") def _parse_payment_method_nonce(self, response): return PaymentMethodNonce(self.gateway, response["payment_method_nonce"]) braintree_python-3.23.0/braintree/paypal_account.py000066400000000000000000000017571262761311500225200ustar00rootroot00000000000000import 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.23.0/braintree/paypal_account_gateway.py000066400000000000000000000033401262761311500242270ustar00rootroot00000000000000import 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.23.0/braintree/plan.py000066400000000000000000000013321262761311500204350ustar00rootroot00000000000000from 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.23.0/braintree/plan_gateway.py000066400000000000000000000012421262761311500221560ustar00rootroot00000000000000import 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.23.0/braintree/resource.py000066400000000000000000000045651262761311500213450ustar00rootroot00000000000000import re import string from braintree.attribute_getter import AttributeGetter 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, str): 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 = parent + "[" + key + "]" if parent else key flat_sig += Resource.__flattened_signature(val, full_key) else: full_key = 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.23.0/braintree/resource_collection.py000066400000000000000000000031331262761311500235460ustar00rootroot00000000000000class 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): self.__page_size = results["search_results"]["page_size"] self.__ids = results["search_results"]["ids"] self.__query = query self.__method = method @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 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.23.0/braintree/risk_data.py000066400000000000000000000001421262761311500214420ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class RiskData(AttributeGetter): pass braintree_python-3.23.0/braintree/search.py000066400000000000000000000051701262761311500207540ustar00rootroot00000000000000class Search: class IsNodeBuilder(object): 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): 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): 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): 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 TextNodeBuilder(PartialMatchNodeBuilder): def contains(self, value): return Search.Node(self.name, {"contains": value}) class Node(object): def __init__(self, name, dict): self.name = name self.dict = dict def to_param(self): return self.dict class MultipleValueNodeBuilder(object): 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): def __init__(self, name, whitelist = []): Search.MultipleValueNodeBuilder.__init__(self, name, whitelist) class RangeNodeBuilder(object): 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.23.0/braintree/settlement_batch_summary.py000066400000000000000000000011571262761311500246120ustar00rootroot00000000000000from 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.23.0/braintree/settlement_batch_summary_gateway.py000066400000000000000000000020621262761311500263270ustar00rootroot00000000000000import 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.23.0/braintree/signature_service.py000066400000000000000000000010111262761311500232160ustar00rootroot00000000000000import 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.23.0/braintree/ssl/000077500000000000000000000000001262761311500177335ustar00rootroot00000000000000braintree_python-3.23.0/braintree/ssl/api_braintreegateway_com.ca.crt000066400000000000000000000514271262761311500260640ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY oJ2daZH9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te 2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC 4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- -----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----- MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i 2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ 2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ -----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----- MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m 1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH 6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----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----- MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL 5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe 2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv /NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz 4iIprn2DQKi6bA== -----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----- 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----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta 3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk 6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 /qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 jVaMaA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd -----END CERTIFICATE----- braintree_python-3.23.0/braintree/status_event.py000066400000000000000000000003601262761311500222270ustar00rootroot00000000000000from 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.23.0/braintree/subscription.py000066400000000000000000000211411262761311500222270ustar00rootroot00000000000000from 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/ios+python/reference/request/subscription/create """ 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" ] } ] + 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): return Configuration.gateway().subscription.retry_charge(subscription_id, amount) @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" ] } ] + 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 "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.23.0/braintree/subscription_details.py000066400000000000000000000001551262761311500237360ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class SubscriptionDetails(AttributeGetter): pass braintree_python-3.23.0/braintree/subscription_gateway.py000066400000000000000000000100571262761311500237540ustar00rootroot00000000000000import 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 " + subscription_id + " not found") def retry_charge(self, subscription_id, amount=None): response = self.config.http().post(self.config.base_merchant_path() + "/transactions", {"transaction": { "amount": amount, "subscription_id": subscription_id, "type": Transaction.Type.Sale }}) 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.23.0/braintree/subscription_search.py000066400000000000000000000015611262761311500235600ustar00rootroot00000000000000from braintree.util import Constants from braintree import Subscription from braintree.search import Search class SubscriptionSearch: billing_cycles_remaining = Search.RangeNodeBuilder("billing_cycles_remaining") 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.23.0/braintree/subscription_status_event.py000066400000000000000000000004471262761311500250410ustar00rootroot00000000000000from 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.23.0/braintree/successful_result.py000066400000000000000000000011671262761311500232660ustar00rootroot00000000000000from 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.23.0/braintree/test/000077500000000000000000000000001262761311500201115ustar00rootroot00000000000000braintree_python-3.23.0/braintree/test/__init__.py000066400000000000000000000000001262761311500222100ustar00rootroot00000000000000braintree_python-3.23.0/braintree/test/credit_card_defaults.py000066400000000000000000000001411262761311500246110ustar00rootroot00000000000000class CreditCardDefaults(object): CountryOfIssuance = "USA" IssuingBank = "NETWORK ONLY" braintree_python-3.23.0/braintree/test/credit_card_numbers.py000066400000000000000000000021241262761311500244600ustar00rootroot00000000000000class 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" class FailsSandboxVerification(object): AmEx = "378734493671000" Discover = "6011000990139424" MasterCard = "5105105105105100" Visa = "4000111111111115" class AmexPayWithPoints(object): Success = "371260714673002" IneligibleCard = "378267515471109" InsufficientPoints = "371544868764018" braintree_python-3.23.0/braintree/test/merchant_account.py000066400000000000000000000003751262761311500240050ustar00rootroot00000000000000Approve = "approve_me" InsufficientFundsContactUs = "insufficient_funds__contact" AccountNotAuthorizedContactUs = "account_not_authorized__contact" BankRejectedUpdateFundingInformation = "bank_rejected__update" BankRejectedNone = "bank_rejected__none" braintree_python-3.23.0/braintree/test/nonces.py000066400000000000000000000051111262761311500217460ustar00rootroot00000000000000class 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" 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" LuhnInvalid = "fake-luhn-invalid-nonce" PayPalFuturePaymentRefreshToken = "fake-paypal-future-refresh-token-nonce" SEPA = "fake-sepa-bank-account-nonce" GatewayRejectedFraud = "fake-gateway-rejected-fraud-nonce" braintree_python-3.23.0/braintree/test/venmo_sdk.py000066400000000000000000000004701262761311500224510ustar00rootroot00000000000000def 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.23.0/braintree/testing_gateway.py000066400000000000000000000052601262761311500227050ustar00rootroot00000000000000import 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.23.0/braintree/three_d_secure_info.py000066400000000000000000000001521262761311500234750ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class ThreeDSecureInfo(AttributeGetter): pass braintree_python-3.23.0/braintree/transaction.py000066400000000000000000000550141262761311500220360ustar00rootroot00000000000000import braintree import warnings from decimal import Decimal from braintree.add_on import AddOn from braintree.apple_pay_card import ApplePayCard 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.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.facilitator_details import FacilitatorDetails from braintree.payment_instrument_type import PaymentInstrumentType 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/ios+python/reference/request/transaction/sale """ def __repr__(self): detail_list = ["amount", "credit_card", "payment_method_token", "customer_id"] 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" 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.Authorized * braintree.Transaction.Status.Authorizing * braintree.Transaction.Status.Failed * braintree.Transaction.Status.GatewayRejected * braintree.Transaction.Status.ProcessorDeclined * braintree.Transaction.Status.Settled * braintree.Transaction.Status.SettlementFailed * braintree.Transaction.Status.Settling * braintree.Transaction.Status.SubmittedForSettlement * braintree.Transaction.Status.Void """ 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" 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" @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 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=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) @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 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", "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", "tax_exempt", "three_d_secure_token", "type", "venmo_sdk_payment_method_code", "service_fee_amount", { "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" ] }, { "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_email", { "paypal": [ "payee_email", "custom_field", "description", {"supplementary_data": ["__any_key__"]} ], "three_d_secure": [ "required" ], }, { "amex_rewards": [ "request_id", "points", "currency_amount", "currency_iso_code" ] }, ] }, {"custom_fields": ["__any_key__"]}, {"descriptor": ["name", "phone", "url"]}, {"paypal_account": ["payee_email"]}, {"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" ] } ] } ] @staticmethod def submit_for_settlement_signature(): return ["order_id", {"descriptor": ["name", "phone", "url"]}] @staticmethod def submit_for_partial_settlement(transaction_id, amount): """ 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) 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 self.tax_amount: self.tax_amount = Decimal(self.tax_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 "europe_bank_account" in attributes: self.europe_bank_account_details = EuropeBankAccount(gateway, attributes.pop("europe_bank_account")) 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 "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 "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 "facilitator_details" in attributes: self.facilitator_details = FacilitatorDetails(attributes.pop("facilitator_details")) @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 braintree_python-3.23.0/braintree/transaction_amounts.py000066400000000000000000000003071262761311500235770ustar00rootroot00000000000000class TransactionAmounts(object): """ A class of constants for transaction amounts that will cause different statuses. """ Authorize = "1000.00" Decline = "2000.00" Fail = "3000.00" braintree_python-3.23.0/braintree/transaction_details.py000066400000000000000000000004521262761311500235370ustar00rootroot00000000000000from 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.23.0/braintree/transaction_gateway.py000066400000000000000000000203371262761311500235570ustar00rootroot00000000000000import 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=None): """ Refunds an existing transaction. It expects a transaction_id. :: result = braintree.Transaction.refund("my_transaction_id") """ response = self.config.http().post(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/refund", {"transaction": {"amount": amount}}) 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 submit_for_partial_settlement(self, transaction_id, amount): response = self.config.http().post(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/submit_for_partial_settlement", {"transaction": {"amount": amount}}) 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}) return [Transaction(self.gateway, item) for item in ResourceCollection._extract_as_array(response["credit_card_transactions"], "transaction")] 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.23.0/braintree/transaction_search.py000066400000000000000000000126351262761311500233650ustar00rootroot00000000000000from 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.23.0/braintree/transparent_redirect.py000066400000000000000000000022421262761311500237260ustar00rootroot00000000000000import 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.23.0/braintree/transparent_redirect_gateway.py000066400000000000000000000063121262761311500254510ustar00rootroot00000000000000import 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.23.0/braintree/unknown_payment_method.py000066400000000000000000000003161262761311500243000ustar00rootroot00000000000000import 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.23.0/braintree/util/000077500000000000000000000000001262761311500201075ustar00rootroot00000000000000braintree_python-3.23.0/braintree/util/__init__.py000066400000000000000000000004011262761311500222130ustar00rootroot00000000000000from 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.parser import Parser from braintree.util.xml_util import XmlUtil braintree_python-3.23.0/braintree/util/constants.py000066400000000000000000000002701262761311500224740ustar00rootroot00000000000000class 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.23.0/braintree/util/crypto.py000066400000000000000000000024071262761311500220040ustar00rootroot00000000000000import 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.23.0/braintree/util/generator.py000066400000000000000000000050221262761311500224460ustar00rootroot00000000000000import 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.23.0/braintree/util/http.py000066400000000000000000000122201262761311500214350ustar00rootroot00000000000000import sys import requests if sys.version_info[0] == 2: from base64 import encodestring as encodebytes else: from base64 import encodebytes import braintree from braintree import version 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.unexpected_error import UnexpectedError 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 class Http(object): @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 == 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={}): return self.__http_do("POST", path, params) def delete(self, path): return self.__http_do("DELETE", path) def get(self, path): return self.__http_do("GET", path) def put(self, path, params={}): return self.__http_do("PUT", path, params) def __http_do(self, http_verb, path, params=None): http_strategy = self.config.http_strategy() request_body = XmlUtil.xml_from_dict(params) if params else '' full_path = path if path.startswith(self.config.base_url()) else (self.config.base_url() + path) try: status, response_body = http_strategy.http_do(http_verb, full_path, self.__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: return XmlUtil.dict_from_xml(response_body) def http_do(self, http_verb, path, headers, request_body): response = self.__request_function(http_verb)( path if path.startswith(self.config.base_url()) else self.config.base_url() + path, headers=headers, data=request_body, verify=self.environment.ssl_certificate, timeout=self.config.timeout ) return [response.status_code, response.text] def handle_exception(self, exception): if 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): return { "Accept": "application/xml", "Authorization": self.__authorization_header(), "Content-type": "application/xml", "User-Agent": "Braintree Python " + version.Version, "X-ApiVersion": braintree.configuration.Configuration.api_version() } braintree_python-3.23.0/braintree/util/parser.py000066400000000000000000000063571262761311500217700ustar00rootroot00000000000000from xml.dom import minidom from datetime import 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 datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ") 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.23.0/braintree/util/xml_util.py000066400000000000000000000004331262761311500223160ustar00rootroot00000000000000from 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.23.0/braintree/validation_error.py000066400000000000000000000007111262761311500230460ustar00rootroot00000000000000from 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.23.0/braintree/validation_error_collection.py000066400000000000000000000056501262761311500252700ustar00rootroot00000000000000from 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/ios+python/reference/general/validation-errors/overview """ 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.23.0/braintree/venmo_account.py000066400000000000000000000006551262761311500223520ustar00rootroot00000000000000import 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.23.0/braintree/version.py000066400000000000000000000000231262761311500211640ustar00rootroot00000000000000Version = "3.23.0" braintree_python-3.23.0/braintree/webhook_notification.py000066400000000000000000000060701262761311500237130ustar00rootroot00000000000000from 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.disbursement import Disbursement from braintree.dispute import Dispute from braintree.error_result import ErrorResult from braintree.validation_error_collection import ValidationErrorCollection class WebhookNotification(Resource): class Kind(object): Check = "check" PartnerMerchantConnected = "partner_merchant_connected" PartnerMerchantDisconnected = "partner_merchant_disconnected" PartnerMerchantDeclined = "partner_merchant_declined" 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" DisbursementException = "disbursement_exception" Disbursement = "disbursement" DisputeOpened = "dispute_opened" DisputeLost = "dispute_lost" DisputeWon = "dispute_won" @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 "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 "partner_merchant" in node_wrapper: self.partner_merchant = PartnerMerchant(gateway, node_wrapper['partner_merchant']) elif "disbursement" in node_wrapper: self.disbursement = Disbursement(gateway, node_wrapper['disbursement']) elif "dispute" in node_wrapper: self.dispute = Dispute(node_wrapper['dispute']) if "errors" in node_wrapper: self.errors = ValidationErrorCollection(node_wrapper['errors']) self.message = node_wrapper['message'] braintree_python-3.23.0/braintree/webhook_notification_gateway.py000066400000000000000000000043341262761311500254350ustar00rootroot00000000000000import re import base64 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 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(base64.decodestring(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.23.0/braintree/webhook_testing.py000066400000000000000000000003601262761311500226760ustar00rootroot00000000000000import braintree from braintree.configuration import Configuration class WebhookTesting(object): @staticmethod def sample_notification(kind, id): return Configuration.gateway().webhook_testing.sample_notification(kind, id) braintree_python-3.23.0/braintree/webhook_testing_gateway.py000066400000000000000000000253551262761311500244320ustar00rootroot00000000000000from braintree.util.crypto import Crypto from braintree.webhook_notification import WebhookNotification import base64 from datetime import datetime class WebhookTestingGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def sample_notification(self, kind, id): payload = base64.encodestring(self.__sample_xml(kind, 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): timestamp = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") sample_xml = """ %s %s %s """ % (timestamp, kind, 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.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.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.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) 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 __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): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback open fraud %s %s 250.00 2014-03-28 """ % (id, id) def __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 __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 __subscription_sample_xml(self, id): return """ %s """ % id def __subscription_charged_successfully_sample_xml(self, id): return """ %s submitted_for_settlement 49.99 """ % 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 __partner_merchant_declined_sample_xml(self): return """ abc123 """ braintree_python-3.23.0/ci.sh000077500000000000000000000003501262761311500161070ustar00rootroot00000000000000#!/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 PATH=/usr/local/python/2.7.1/bin:$PATH rake $python_tests --trace fi braintree_python-3.23.0/docs/000077500000000000000000000000001262761311500161075ustar00rootroot00000000000000braintree_python-3.23.0/docs/Makefile000066400000000000000000000060741262761311500175560ustar00rootroot00000000000000# 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.23.0/docs/_static/000077500000000000000000000000001262761311500175355ustar00rootroot00000000000000braintree_python-3.23.0/docs/_static/.git_empty_dir000066400000000000000000000000001262761311500223630ustar00rootroot00000000000000braintree_python-3.23.0/docs/address.rst000066400000000000000000000001361262761311500202660ustar00rootroot00000000000000Address ===================================== .. automodule:: braintree.address :members: braintree_python-3.23.0/docs/conf.py000066400000000000000000000144601262761311500174130ustar00rootroot00000000000000# -*- 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.23.0/docs/configuration.rst000066400000000000000000000001521262761311500215060ustar00rootroot00000000000000Configuration ===================================== .. automodule:: braintree.configuration :members: braintree_python-3.23.0/docs/credit_card.rst000066400000000000000000000001461262761311500211050ustar00rootroot00000000000000Credit Card ===================================== .. automodule:: braintree.credit_card :members: braintree_python-3.23.0/docs/credit_card_verification.rst000066400000000000000000000002001262761311500236360ustar00rootroot00000000000000Credit Card Verification ===================================== .. automodule:: braintree.credit_card_verification :members: braintree_python-3.23.0/docs/customer.rst000066400000000000000000000001401262761311500204750ustar00rootroot00000000000000Customer ===================================== .. automodule:: braintree.customer :members: braintree_python-3.23.0/docs/environment.rst000066400000000000000000000001461262761311500212060ustar00rootroot00000000000000Environment ===================================== .. automodule:: braintree.environment :members: braintree_python-3.23.0/docs/error_codes.rst000066400000000000000000000001461262761311500211500ustar00rootroot00000000000000Error Codes ===================================== .. automodule:: braintree.error_codes :members: braintree_python-3.23.0/docs/error_result.rst000066400000000000000000000001501262761311500213640ustar00rootroot00000000000000Error Result ===================================== .. automodule:: braintree.error_result :members: braintree_python-3.23.0/docs/exceptions/000077500000000000000000000000001262761311500202705ustar00rootroot00000000000000braintree_python-3.23.0/docs/exceptions/authentication_error.rst000066400000000000000000000002031262761311500252450ustar00rootroot00000000000000Authentication Error ===================================== .. automodule:: braintree.exceptions.authentication_error :members: braintree_python-3.23.0/docs/exceptions/authorization_error.rst000066400000000000000000000002011262761311500251240ustar00rootroot00000000000000Authorization Error ===================================== .. automodule:: braintree.exceptions.authorization_error :members: braintree_python-3.23.0/docs/exceptions/down_for_maintenance_error.rst000066400000000000000000000002171262761311500264120ustar00rootroot00000000000000Down For Maintenance Error ===================================== .. automodule:: braintree.exceptions.down_for_maintenance_error :members: braintree_python-3.23.0/docs/exceptions/forged_query_string_error.rst000066400000000000000000000002151262761311500263120ustar00rootroot00000000000000Forged Query String Error ===================================== .. automodule:: braintree.exceptions.forged_query_string_error :members: braintree_python-3.23.0/docs/exceptions/not_found_error.rst000066400000000000000000000001711262761311500242250ustar00rootroot00000000000000Not Found Error ===================================== .. automodule:: braintree.exceptions.not_found_error :members: braintree_python-3.23.0/docs/exceptions/server_error.rst000066400000000000000000000001631262761311500235410ustar00rootroot00000000000000Server Error ===================================== .. automodule:: braintree.exceptions.server_error :members: braintree_python-3.23.0/docs/exceptions/unexpected_error.rst000066400000000000000000000001731262761311500244000ustar00rootroot00000000000000Unexpected Error ===================================== .. automodule:: braintree.exceptions.unexpected_error :members: braintree_python-3.23.0/docs/exceptions/upgrade_required_error.rst000066400000000000000000000002071262761311500255610ustar00rootroot00000000000000Upgrade Required Error ===================================== .. automodule:: braintree.exceptions.upgrade_required_error :members: braintree_python-3.23.0/docs/index.rst000066400000000000000000000025511262761311500177530ustar00rootroot00000000000000.. 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/ios+python/start/hello-server 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.23.0/docs/resource_collection.rst000066400000000000000000000001661262761311500227060ustar00rootroot00000000000000Resource Collection ===================================== .. automodule:: braintree.resource_collection :members: braintree_python-3.23.0/docs/subscription.rst000066400000000000000000000001501262761311500213610ustar00rootroot00000000000000Subscription ===================================== .. automodule:: braintree.subscription :members: braintree_python-3.23.0/docs/successful_result.rst000066400000000000000000000001621262761311500224150ustar00rootroot00000000000000Successful Result ===================================== .. automodule:: braintree.successful_result :members: braintree_python-3.23.0/docs/transaction.rst000066400000000000000000000001461262761311500211670ustar00rootroot00000000000000Transaction ===================================== .. automodule:: braintree.transaction :members: braintree_python-3.23.0/docs/transparent_redirect.rst000066400000000000000000000001701262761311500230610ustar00rootroot00000000000000Transparent Redirect ===================================== .. automodule:: braintree.transparent_redirect :members: braintree_python-3.23.0/docs/validation_error.rst000066400000000000000000000001601262761311500222010ustar00rootroot00000000000000Validation Error ===================================== .. automodule:: braintree.validation_error :members: braintree_python-3.23.0/docs/validation_error_collection.rst000066400000000000000000000002061262761311500244150ustar00rootroot00000000000000Validation Error Collection ===================================== .. automodule:: braintree.validation_error_collection :members: braintree_python-3.23.0/requirements.txt000066400000000000000000000000261262761311500204410ustar00rootroot00000000000000requests>=0.11.1,<3.0 braintree_python-3.23.0/setup.py000066400000000000000000000010341262761311500166670ustar00rootroot00000000000000from distutils.core import setup setup( name="braintree", version="3.23.0", description="Braintree Python Library", author="Braintree", author_email="support@braintreepayments.com", url="https://developers.braintreepayments.com/python/sdk/server/overview", packages=["braintree", "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 ) braintree_python-3.23.0/tests/000077500000000000000000000000001262761311500163215ustar00rootroot00000000000000braintree_python-3.23.0/tests/__init__.py000066400000000000000000000000001262761311500204200ustar00rootroot00000000000000braintree_python-3.23.0/tests/integration/000077500000000000000000000000001262761311500206445ustar00rootroot00000000000000braintree_python-3.23.0/tests/integration/__init__.py000066400000000000000000000000001262761311500227430ustar00rootroot00000000000000braintree_python-3.23.0/tests/integration/test_add_ons.py000066400000000000000000000023061262761311500236650ustar00rootroot00000000000000from 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.assertNotEquals(None, add_on) self.assertEquals(add_on.amount, Decimal("100.00")) self.assertEquals(add_on.description, "some description") self.assertEquals(add_on.id, new_id) self.assertEquals(add_on.kind, "add_on") self.assertEquals(add_on.name, "python_add_on") self.assertEquals(add_on.never_expires, False) self.assertEquals(add_on.number_of_billing_cycles, 1) braintree_python-3.23.0/tests/integration/test_address.py000066400000000000000000000151611262761311500237060ustar00rootroot00000000000000from 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.assertEquals(customer.id, address.customer_id) self.assertEquals("Ben", address.first_name) self.assertEquals("Moore", address.last_name) self.assertEquals("Moore Co.", address.company) self.assertEquals("1811 E Main St", address.street_address) self.assertEquals("Suite 200", address.extended_address) self.assertEquals("Chicago", address.locality) self.assertEquals("Illinois", address.region) self.assertEquals("60622", address.postal_code) self.assertEquals("US", address.country_code_alpha2) self.assertEquals("USA", address.country_code_alpha3) self.assertEquals("840", address.country_code_numeric) self.assertEquals("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) self.assertEquals(ErrorCodes.Address.CountryNameIsNotAccepted, result.errors.for_object("address").on("country_name")[0].code) self.assertEquals(ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, result.errors.for_object("address").on("country_code_alpha2")[0].code) self.assertEquals(ErrorCodes.Address.CountryCodeAlpha3IsNotAccepted, result.errors.for_object("address").on("country_code_alpha3")[0].code) self.assertEquals(ErrorCodes.Address.CountryCodeNumericIsNotAccepted, result.errors.for_object("address").on("country_code_numeric")[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) self.assertEquals(ErrorCodes.Address.InconsistentCountry, result.errors.for_object("address").on("base")[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 result = 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.assertEquals(address.street_address, found_address.street_address) def test_find_with_invalid_customer_id_and_address_id(self): try: Address.find("notreal", "badaddress") self.assertTrue(False) except NotFoundError as e: self.assertEquals("address for customer 'notreal' with id 'badaddress' not found", str(e)) 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.assertEquals(customer.id, address.customer_id) self.assertEquals("123 E New St", address.street_address) self.assertEquals("New Suite 3", address.extended_address) self.assertEquals("Chicago", address.locality) self.assertEquals("Illinois", address.region) self.assertEquals("60621", address.postal_code) self.assertEquals("MX", address.country_code_alpha2) self.assertEquals("MEX", address.country_code_alpha3) self.assertEquals("484", address.country_code_numeric) self.assertEquals("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) self.assertEquals(ErrorCodes.Address.CountryNameIsNotAccepted, result.errors.for_object("address").on("country_name")[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.23.0/tests/integration/test_client_token.py000066400000000000000000000152621262761311500247410ustar00rootroot00000000000000from tests.test_helper import * import base64 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(version, 1) 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, response = http.get_cards() self.assertEqual(status_code, 200) def test_client_token_version_defaults_to_two(self): client_token = TestHelper.generate_decoded_client_token() version = json.loads(client_token)["version"] self.assertEqual(version, 2) 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, response = http.add_card({ "credit_card": { "number": "4000111111111115", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(status_code, 422) 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, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(status_code, 201) status_code, response = http.add_card({ "credit_card": { "number": "4005519200000004", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(status_code, 201) customer = braintree.Customer.find(customer_id) self.assertEqual(len(customer.credit_cards), 2) 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, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(status_code, 201) 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, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(status_code, 422) customer = braintree.Customer.find(customer_id) self.assertEqual(len(customer.credit_cards), 1) def test_can_pass_sepa_params(self): result = braintree.Customer.create() customer_id = result.customer.id client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, "sepa_mandate_acceptance_location": "Hamburg, Germany", "sepa_mandate_type": EuropeBankAccount.MandateType.Business }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] self.assertNotEqual(authorization_fingerprint, None) def test_can_pass_merchant_account_id(self): client_token = TestHelper.generate_decoded_client_token({ "merchant_account_id": "my_merchant_account" }) merchant_account_id = json.loads(client_token)["merchantAccountId"] self.assertEqual(merchant_account_id, "my_merchant_account") def test_required_data_cannot_be_overridden(self): try: client_token = TestHelper.generate_decoded_client_token({ "merchant_id": "1234" }) self.fail("Should have raised exception!") except Exception as e: self.assertEqual("'Invalid keys: merchant_id'", str(e)) braintree_python-3.23.0/tests/integration/test_coinbase.py000066400000000000000000000024641262761311500240460ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.nonces import Nonces from braintree.exceptions.not_found_error import NotFoundError class TestCoinbase(unittest.TestCase): def _assert_valid_coinbase_account(self, account): for attr in ["user_name", "user_email", "user_id"]: self.assertIsNotNone(getattr(account, attr)) def test_customer(self): result = Customer.create({"payment_method_nonce": Nonces.Coinbase}) customer = Customer.find(result.customer.id) account = customer.coinbase_accounts[0] self.assertIsNotNone(account) self._assert_valid_coinbase_account(account) def test_vault(self): result = Customer.create() result = PaymentMethod.create({ "customer_id": result.customer.id, "payment_method_nonce": Nonces.Coinbase }) account = result.payment_method self._assert_valid_coinbase_account(account) PaymentMethod.delete(account.token) self.assertRaises(braintree.exceptions.NotFoundError, PaymentMethod.find, account.token) def test_transaction(self): result = Transaction.sale({"payment_method_nonce": Nonces.Coinbase, "amount": "1.00"}) account = result.transaction.coinbase_details self._assert_valid_coinbase_account(account) braintree_python-3.23.0/tests/integration/test_credentials_parser.py000066400000000000000000000067661262761311500261450ustar00rootroot00000000000000from 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(parser.client_id, "client_id$development$integration_client_id") self.assertEqual(parser.client_secret, "client_secret$development$integration_client_secret") self.assertEqual(parser.environment, braintree.Environment.Development) 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(parser.access_token, "access_token$development$integration_merchant_id$fb27c79dd") self.assertEqual(parser.merchant_id, "integration_merchant_id") self.assertEqual(parser.environment, braintree.Environment.Development) braintree_python-3.23.0/tests/integration/test_credit_card.py000066400000000000000000001413241262761311500245250ustar00rootroot00000000000000from 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_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("\A\w{4,5}\Z", credit_card.token) is not None) self.assertEquals("411111", credit_card.bin) self.assertEquals("1111", credit_card.last_4) self.assertEquals("05", credit_card.expiration_month) self.assertEquals("2014", credit_card.expiration_year) self.assertEquals("05/2014", credit_card.expiration_date) self.assertEquals("John Doe", credit_card.cardholder_name) self.assertNotEquals(re.search("\A\w{32}\Z", credit_card.unique_number_identifier), None) self.assertFalse(credit_card.venmo_sdk) self.assertNotEquals(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.assertEquals("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.assertEquals(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.assertEquals("123 Abc Way", address.street_address) self.assertEquals("Chicago", address.locality) self.assertEquals("Illinois", address.region) self.assertEquals("60622", address.postal_code) self.assertEquals("MX", address.country_code_alpha2) self.assertEquals("MEX", address.country_code_alpha3) self.assertEquals("484", address.country_code_numeric) self.assertEquals("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.assertEquals(address.id, billing_address.id) self.assertEquals("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.assertEquals(None, result.credit_card.billing_address) def test_create_with_card_verification_returns_risk_data(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.assertIsInstance(verification.risk_data, RiskData) self.assertEquals(verification.risk_data.id, None) self.assertEquals(verification.risk_data.decision, "Not Evaluated") def test_successful_create_with_card_verification_returns_risk_data(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "options": {"verify_card": True} }) self.assertTrue(result.is_success) verification = result.credit_card.verification self.assertIsInstance(verification.risk_data, RiskData) self.assertEquals(verification.risk_data.id, None) self.assertEquals(verification.risk_data.decision, "Not Evaluated") 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.assertEquals(CreditCardVerification.Status.ProcessorDeclined, verification.status) self.assertEquals("2000", verification.processor_response_code) self.assertEquals("Do Not Honor", verification.processor_response_text) self.assertEquals("I", verification.cvv_response_code) self.assertEquals(None, verification.avs_error_response_code) self.assertEquals("I", verification.avs_postal_code_response_code) self.assertEquals("I", verification.avs_street_address_response_code) self.assertEquals(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.assertEquals(CreditCardVerification.Status.ProcessorDeclined, verification.status) self.assertEquals("2000", verification.processor_response_code) self.assertEquals("Do Not Honor", verification.processor_response_text) self.assertEquals("I", verification.cvv_response_code) self.assertEquals(None, verification.avs_error_response_code) self.assertEquals("I", verification.avs_postal_code_response_code) self.assertEquals("I", verification.avs_street_address_response_code) self.assertEquals(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.assertEquals(CreditCardVerification.Status.ProcessorDeclined, verification.status) self.assertEquals(None, verification.gateway_rejection_reason) self.assertEquals(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.assertEquals('1000', result.credit_card_verification.processor_response_code) self.assertEquals('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.assertEquals(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.assertEquals(ErrorCodes.CreditCard.DuplicateCardExists, result.errors.for_object("credit_card").on("number")[0].code) self.assertEquals("Duplicate card exists in the vault.", result.message) 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.assertEquals(ErrorCodes.CreditCard.ExpirationDateIsInvalid, result.errors.for_object("credit_card").on("expiration_date")[0].code) self.assertEquals("Expiration date is invalid.", result.message) 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) self.assertEquals( ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, result.errors.for_object("credit_card").for_object("billing_address").on("country_code_alpha2")[0].code ) self.assertEquals( ErrorCodes.Address.CountryCodeAlpha3IsNotAccepted, result.errors.for_object("credit_card").for_object("billing_address").on("country_code_alpha3")[0].code ) self.assertEquals( ErrorCodes.Address.CountryCodeNumericIsNotAccepted, result.errors.for_object("credit_card").for_object("billing_address").on("country_code_numeric")[0].code ) self.assertEquals( ErrorCodes.Address.CountryNameIsNotAccepted, result.errors.for_object("credit_card").for_object("billing_address").on("country_name")[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.assertEquals("411111", result.credit_card.bin) self.assertTrue(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.assertEquals(result.message, "Invalid VenmoSDK payment method code") self.assertEquals(result.errors.for_object("credit_card") \ .on("venmo_sdk_payment_method_code")[0].code, ErrorCodes.CreditCard.InvalidVenmoSDKPaymentMethodCode) 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" }) status_code, 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.assertEquals("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.assertTrue(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("\A\w{4,5}\Z", credit_card.token) is not None) self.assertEquals("510510", credit_card.bin) self.assertEquals("5100", credit_card.last_4) self.assertEquals("06", credit_card.expiration_month) self.assertEquals("2010", credit_card.expiration_year) self.assertEquals("06/2010", credit_card.expiration_date) self.assertEquals("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.assertEquals("IL", updated_credit_card.billing_address.region) self.assertEquals("NG", updated_credit_card.billing_address.country_code_alpha2) self.assertEquals("NGA", updated_credit_card.billing_address.country_code_alpha3) self.assertEquals("566", updated_credit_card.billing_address.country_code_numeric) self.assertEquals("Nigeria", updated_credit_card.billing_address.country_name) self.assertEquals(None, updated_credit_card.billing_address.street_address) self.assertNotEquals(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.assertEquals("IL", updated_credit_card.billing_address.region) self.assertEquals("123 Nigeria Ave", updated_credit_card.billing_address.street_address) self.assertEquals(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) result = 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.assertEquals(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.assertEquals(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.assertEquals("123 Abc Way", address.street_address) self.assertEquals("Chicago", address.locality) self.assertEquals("Illinois", address.region) self.assertEquals("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) self.assertEquals(ErrorCodes.CreditCard.ExpirationDateIsInvalid, result.errors.for_object("credit_card").on("expiration_date")[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): result = 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("\A\w{4,5}\Z", credit_card.token) is not None) self.assertEquals("411111", credit_card.bin) self.assertEquals("1111", credit_card.last_4) self.assertEquals("05", credit_card.expiration_month) self.assertEquals("2014", credit_card.expiration_year) self.assertEquals("05/2014", 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 id = "id_" + str(random.randint(1, 1000000)) subscription = Subscription.create({ "id": 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) self.assertEquals(id, found_credit_card.subscriptions[0].id) self.assertEquals(Decimal("1.00"), found_credit_card.subscriptions[0].price) self.assertEquals(credit_card.token, found_credit_card.subscriptions[0].payment_method_token) def test_find_with_invalid_token(self): try: CreditCard.find("bad_token") self.assertTrue(False) except Exception as e: self.assertEquals("payment method with token 'bad_token' not found", str(e)) 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(status_code, 201) nonce = json.loads(response)["creditCards"][0]["nonce"] card = CreditCard.from_nonce(nonce) customer = Customer.find(customer.id) self.assertEquals(customer.credit_cards[0].token, card.token) 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(status_code, 201) nonce = json.loads(response)["creditCards"][0]["nonce"] try: CreditCard.from_nonce(nonce) self.assertTrue(False) except Exception as e: self.assertIn("not found", str(e)) 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(status_code, 201) nonce = json.loads(response)["creditCards"][0]["nonce"] CreditCard.from_nonce(nonce) try: CreditCard.from_nonce(nonce) self.assertTrue(False) except Exception as e: self.assertIn("consumed", str(e)) 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.assertEquals("411111", credit_card.bin) self.assertEquals("1111", credit_card.last_4) self.assertEquals("05", credit_card.expiration_month) self.assertEquals("2012", credit_card.expiration_year) self.assertEquals(customer.id, credit_card.customer_id) self.assertEquals("MX", credit_card.billing_address.country_code_alpha2) self.assertEquals("MEX", credit_card.billing_address.country_code_alpha3) self.assertEquals("484", credit_card.billing_address.country_code_numeric) self.assertEquals("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) self.assertEquals( ErrorCodes.CreditCard.NumberHasInvalidLength, result.errors.for_object("credit_card").on("number")[0].code ) self.assertEquals( ErrorCodes.CreditCard.ExpirationDateIsInvalid, result.errors.for_object("credit_card").on("expiration_date")[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.assertEquals(new_token, credit_card.token) self.assertEquals("411111", credit_card.bin) self.assertEquals("1111", credit_card.last_4) self.assertEquals("05", credit_card.expiration_month) self.assertEquals("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()) result = 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()) result = CreditCard.confirm_transparent_redirect(query_string) self.assertEquals(1, len(Customer.find(customer.id).addresses)) updated_card = CreditCard.find(card.token) self.assertEquals("123 New St", updated_card.billing_address.street_address) self.assertEquals("Columbus", updated_card.billing_address.locality) self.assertEquals("Ohio", updated_card.billing_address.region) self.assertEquals("43215", updated_card.billing_address.postal_code) def test_update_from_transparent_redirect_with_error_result(self): old_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": "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) self.assertEquals( ErrorCodes.CreditCard.TokenInvalid, result.errors.for_object("credit_card").on("token")[0].code ) def test_expired_can_iterate_over_all_items(self): customer_id = Customer.all().first.id for i in range(110 - CreditCard.expired().maximum_size): CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }) collection = CreditCard.expired() self.assertTrue(collection.maximum_size > 100) credit_card_tokens = [credit_card.token for credit_card in collection.items] self.assertEquals(collection.maximum_size, len(TestHelper.unique(credit_card_tokens))) self.assertEquals(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 i 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.assertEquals(collection.maximum_size, len(TestHelper.unique(credit_card_tokens))) self.assertEquals(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.assertEquals(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.assertEquals(credit_card.issuing_bank, CreditCardDefaults.IssuingBank) 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.assertEquals(credit_card.country_of_issuance, CreditCardDefaults.CountryOfIssuance) 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.assertEquals(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.assertEquals(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.assertEquals(CreditCard.Healthcare.Yes, credit_card.healthcare) 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.assertEquals(CreditCard.Payroll.Yes, credit_card.payroll) 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.assertEquals(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.assertEquals(CreditCard.Debit.No, credit_card.debit) self.assertEquals(CreditCard.DurbinRegulated.No, credit_card.durbin_regulated) self.assertEquals(CreditCard.Prepaid.No, credit_card.prepaid) self.assertEquals(CreditCard.Payroll.No, credit_card.payroll) self.assertEquals(CreditCard.Commercial.No, credit_card.commercial) self.assertEquals(CreditCard.Healthcare.No, credit_card.healthcare) 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.assertEquals(CreditCard.Debit.Unknown, credit_card.debit) self.assertEquals(CreditCard.DurbinRegulated.Unknown, credit_card.durbin_regulated) self.assertEquals(CreditCard.Prepaid.Unknown, credit_card.prepaid) self.assertEquals(CreditCard.Payroll.Unknown, credit_card.payroll) self.assertEquals(CreditCard.Commercial.Unknown, credit_card.commercial) self.assertEquals(CreditCard.Healthcare.Unknown, credit_card.healthcare) self.assertEquals(CreditCard.IssuingBank.Unknown, credit_card.issuing_bank) self.assertEquals(CreditCard.CountryOfIssuance.Unknown, credit_card.country_of_issuance) braintree_python-3.23.0/tests/integration/test_credit_card_verification.py000066400000000000000000000043151262761311500272650ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestCreditCardVerfication(unittest.TestCase): 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.assertEquals(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" % 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.CardTypeIndicator.Unknown, found_verifications.first.credit_card['issuing_bank']) self.assertEqual(CreditCard.CardTypeIndicator.Unknown, found_verifications.first.credit_card['country_of_issuance']) braintree_python-3.23.0/tests/integration/test_credit_card_verification_search.py000066400000000000000000000132021262761311500306050ustar00rootroot00000000000000from 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.assertEquals(0, collection.maximum_size) def test_search_on_verification_id(self): customer_id = "%s" % 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" % randint(1, 10000) customer_id = "%s" % 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" % 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" % 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.assertEquals(2, search_results.maximum_size) def test_range_field(self): cardholder_name = "Tom %s" % 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.assertEquals(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.assertEquals(0, found_verifications.maximum_size) found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.id == created_verification.id, CreditCardVerificationSearch.created_at == created_time) self.assertEquals(1, found_verifications.maximum_size) braintree_python-3.23.0/tests/integration/test_customer.py000066400000000000000000000677511262761311500241360ustar00rootroot00000000000000from 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.assertEquals(collection.maximum_size, len(TestHelper.unique(customer_ids))) self.assertEquals(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("\A\d{6,7}\Z", 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_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("\A\d{6,7}\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.assertNotEqual(None, customer.apple_pay_cards[0]) 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.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.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.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.assertIsInstance(customer.venmo_accounts[0], VenmoAccount) 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.assertNotEqual(None, customer.paypal_accounts[0]) def test_create_with_paypal_one_time_nonce_fails(self): http = ClientApiHttp.create() result = Customer.create({"payment_method_nonce": Nonces.PayPalOneTimePayment}) self.assertFalse(result.is_success) self.assertEquals( result.errors.for_object("customer").for_object("paypal_account").on("base")[0].code, ErrorCodes.PayPalAccount.CannotVaultOneTimeUsePayPalAccount ) 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) self.assertEquals(2, result.errors.size) self.assertEquals(ErrorCodes.Customer.EmailIsInvalid, result.errors.for_object("customer").on("email")[0].code) self.assertEquals( ErrorCodes.Address.InconsistentCountry, result.errors.for_object("customer").for_object("credit_card").for_object("billing_address").on("base")[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.assertEquals(CreditCardVerification.Status.ProcessorDeclined, result.credit_card_verification.status) 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.assertEquals(ErrorCodes.CreditCard.DuplicateCardExists, result.errors.for_object("customer").for_object("credit_card").on("number")[0].code) self.assertEquals("Duplicate card exists in the vault.", result.message) 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.assertEquals("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) self.assertEquals( ErrorCodes.Customer.EmailIsInvalid, result.errors.for_object("customer").on("email")[0].code ) self.assertEquals( ErrorCodes.CreditCard.NumberHasInvalidLength, result.errors.for_object("customer").for_object("credit_card").on("number")[0].code ) self.assertEquals( ErrorCodes.Address.CountryNameIsNotAccepted, result.errors.for_object("customer").for_object("credit_card").for_object("billing_address").on("country_name")[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) self.assertEquals(ErrorCodes.Customer.CustomFieldIsInvalid, result.errors.for_object("customer").on("custom_fields")[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.assertTrue(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.assertEquals("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" }) status_code, 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.assertEquals("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.assertEquals(customer.id, found_customer.id) self.assertEquals(customer.first_name, found_customer.first_name) self.assertEquals(customer.last_name, found_customer.last_name) def test_find_with_invalid_customer(self): try: Customer.find("badid") self.assertTrue(False) except NotFoundError as e: self.assertEquals("customer with id 'badid' not found", str(e)) 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("\A\d{6,7}\Z", customer.id)) 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) self.assertEquals( ErrorCodes.Customer.EmailIsInvalid, result.errors.for_object("customer").on("email")[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) self.assertEquals( result.errors.for_object("customer").for_object("paypal_account").on("base")[0].code, ErrorCodes.PayPalAccount.CannotVaultOneTimeUsePayPalAccount ) 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.assertEquals("John", customer.first_name) self.assertEquals("Doe", customer.last_name) self.assertEquals("Doe Co", customer.company) self.assertEquals("john@doe.com", customer.email) self.assertEquals("312.555.2323", customer.phone) self.assertEquals("614.555.5656", customer.fax) self.assertEquals("www.johndoe.com", customer.website) self.assertEquals("05/2012", customer.credit_cards[0].expiration_date) self.assertEquals("MX", customer.credit_cards[0].billing_address.country_code_alpha2) self.assertEquals("MEX", customer.credit_cards[0].billing_address.country_code_alpha3) self.assertEquals("484", customer.credit_cards[0].billing_address.country_code_numeric) self.assertEquals("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) self.assertEquals(ErrorCodes.Customer.EmailIsInvalid, result.errors.for_object("customer").on("email")[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.assertEquals("John", customer.first_name) self.assertEquals("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) self.assertEquals(ErrorCodes.Customer.EmailIsInvalid, result.errors.for_object("customer").on("email")[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"} ], "europe_bank_accounts": [ {"token": "europe_bank_account"} ], "coinbase_accounts": [ {"token": "coinbase_account"} ] }) payment_method_tokens = map(lambda payment_method: payment_method.token, customer.payment_methods) self.assertEqual(sorted(payment_method_tokens), ["android_pay_card", "apple_pay_card", "coinbase_account", "credit_card", "europe_bank_account", "paypal_account"]) braintree_python-3.23.0/tests/integration/test_customer_search.py000066400000000000000000000125331262761311500254470ustar00rootroot00000000000000from 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.assertEquals(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" % 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.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(customer.id, collection.first.id) collection = Customer.search( CustomerSearch.id == customer.id, CustomerSearch.created_at <= future ) self.assertEquals(1, collection.maximum_size) self.assertEquals(customer.id, collection.first.id) collection = Customer.search( CustomerSearch.id == customer.id, CustomerSearch.created_at >= past ) self.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(status_code, 202) customer = Customer.create({"payment_method_nonce": nonce}).customer collection = Customer.search( CustomerSearch.paypal_account_email == "jane.doe@example.com", CustomerSearch.id == customer.id ) self.assertEquals(1, collection.maximum_size) self.assertEquals(customer.id, collection.first.id) braintree_python-3.23.0/tests/integration/test_disbursement.py000066400000000000000000000017151262761311500247650ustar00rootroot00000000000000from 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.assertEquals(1, transactions.maximum_size) self.assertEquals("sub_merchant_transaction", transactions.first.id) braintree_python-3.23.0/tests/integration/test_discounts.py000066400000000000000000000023621262761311500242730ustar00rootroot00000000000000from 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.assertNotEquals(None, discount) self.assertEquals(discount.amount, Decimal("100.00")) self.assertEquals(discount.description, "some description") self.assertEquals(discount.id, new_id) self.assertEquals(discount.kind, "discount") self.assertEquals(discount.name, "python_discount") self.assertEquals(discount.never_expires, False) self.assertEquals(discount.number_of_billing_cycles, 1) braintree_python-3.23.0/tests/integration/test_http.py000066400000000000000000000070561262761311500232440ustar00rootroot00000000000000from 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 def get_http(self, environment): config = Configuration(environment, "merchant_id", public_key="public_key", private_key="private_key") return config.http() def test_successful_connection_sandbox(self): http = self.get_http(Environment.Sandbox) try: http.get("/") except AuthenticationError: pass else: self.assertTrue(False) def test_successful_connection_production(self): http = self.get_http(Environment.Production) try: http.get("/") except AuthenticationError: pass else: self.assertTrue(False) 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 as e: correct_exception = False self.assertTrue(correct_exception) def test_unsuccessful_connection_to_good_ssl_server_with_wrong_cert(self): if platform.system() == "Darwin": return environment = Environment("test", "www.google.com", "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 as e: 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 as e: correct_exception = False self.assertTrue(correct_exception) braintree_python-3.23.0/tests/integration/test_merchant.py000066400000000000000000000041231262761311500240560ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.nonces import Nonces class TestMerchantGateway(unittest.TestCase): def test_create_merchant(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"] }) merchant = result.merchant self.assertIsNotNone(merchant.id) self.assertEquals(merchant.email, "name@email.com") self.assertEquals(merchant.country_code_alpha3, "USA") self.assertEquals(merchant.country_code_alpha2, "US") self.assertEquals(merchant.country_code_numeric, "840") self.assertEquals(merchant.country_name, "United States of America") self.assertEquals(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.assertEquals("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", environment = Environment.Development ) result = gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "USA", "payment_methods": ["fake_money"] }) self.assertFalse(result.is_success) self.assertEqual( result.errors.for_object("merchant").on("payment_methods")[0].code, ErrorCodes.Merchant.PaymentMethodsAreInvalid ) self.assertIn("One or more payment methods passed are not accepted.", result.message) braintree_python-3.23.0/tests/integration/test_merchant_account.py000066400000000000000000000500031262761311500255700ustar00rootroot00000000000000from 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.assertEquals(MerchantAccount.Status.Pending, result.merchant_account.status) self.assertEquals("sandbox_master_merchant_account", result.merchant_account.master_merchant_account.id) def test_create_application_with_valid_params_and_no_id(self): customer = Customer.create().customer result = MerchantAccount.create(self.VALID_APPLICATION_PARAMS) self.assertTrue(result.is_success) self.assertEquals(MerchantAccount.Status.Pending, result.merchant_account.status) self.assertEquals("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.randrange(1000000)) params_with_id['id'] = 'sub_merchant_account_id' + rand result = MerchantAccount.create(params_with_id) self.assertTrue(result.is_success) self.assertEquals(MerchantAccount.Status.Pending, result.merchant_account.status) self.assertEquals(params_with_id['id'], result.merchant_account.id) self.assertEquals("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) self.assertEquals(ErrorCodes.MerchantAccount.MasterMerchantAccountIdIsRequired, result.errors.for_object("merchant_account").on("master_merchant_account_id")[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) self.assertEquals(ErrorCodes.MerchantAccount.ApplicantDetails.FirstNameIsRequired, result.errors.for_object("merchant_account").for_object("applicant_details").on("first_name")[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.assertEquals(result.merchant_account.status, "active") self.assertEquals(result.merchant_account.id, "sandbox_sub_merchant_account") self.assertEquals(result.merchant_account.master_merchant_account.id, "sandbox_master_merchant_account") self.assertEquals(result.merchant_account.individual_details.first_name, "John") self.assertEquals(result.merchant_account.individual_details.last_name, "Doe") self.assertEquals(result.merchant_account.individual_details.email, "john.doe@example.com") self.assertEquals(result.merchant_account.individual_details.date_of_birth, "1970-01-01") self.assertEquals(result.merchant_account.individual_details.phone, "3125551234") self.assertEquals(result.merchant_account.individual_details.address_details.street_address, "123 Fake St") self.assertEquals(result.merchant_account.individual_details.address_details.locality, "Chicago") self.assertEquals(result.merchant_account.individual_details.address_details.region, "IL") self.assertEquals(result.merchant_account.individual_details.address_details.postal_code, "60622") self.assertEquals(result.merchant_account.business_details.dba_name, "James's Bloggs") self.assertEquals(result.merchant_account.business_details.legal_name, "James's Junkyard") self.assertEquals(result.merchant_account.business_details.tax_id, "987654321") self.assertEquals(result.merchant_account.business_details.address_details.street_address, "456 Fake St") self.assertEquals(result.merchant_account.business_details.address_details.postal_code, "48104") self.assertEquals(result.merchant_account.business_details.address_details.locality, "Ann Arbor") self.assertEquals(result.merchant_account.business_details.address_details.region, "MI") self.assertEquals(result.merchant_account.funding_details.routing_number, "071000013") self.assertEquals(result.merchant_account.funding_details.account_number_last_4, "6789") self.assertEquals(result.merchant_account.funding_details.destination, MerchantAccount.FundingDestination.Email) self.assertEquals(result.merchant_account.funding_details.email, "check@this.com") self.assertEquals(result.merchant_account.funding_details.mobile_phone, "9998887777") self.assertEquals(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.assertEquals(result.errors.for_object("merchant_account").for_object("individual").on("first_name")[0].code, ErrorCodes.MerchantAccount.Individual.FirstNameIsRequired) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").on("last_name")[0].code, ErrorCodes.MerchantAccount.Individual.LastNameIsRequired) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").on("date_of_birth")[0].code, ErrorCodes.MerchantAccount.Individual.DateOfBirthIsRequired) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").on("email")[0].code, ErrorCodes.MerchantAccount.Individual.EmailAddressIsRequired) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Individual.Address.StreetAddressIsRequired) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Individual.Address.PostalCodeIsRequired) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("locality")[0].code, ErrorCodes.MerchantAccount.Individual.Address.LocalityIsRequired) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Individual.Address.RegionIsRequired) self.assertEquals(result.errors.for_object("merchant_account").for_object("funding").on("destination")[0].code, ErrorCodes.MerchantAccount.Funding.DestinationIsRequired) self.assertEquals(len(result.errors.for_object("merchant_account").on("base")), 0) 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.assertEquals(result.errors.for_object("merchant_account").for_object("individual").on("first_name")[0].code, ErrorCodes.MerchantAccount.Individual.FirstNameIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").on("last_name")[0].code, ErrorCodes.MerchantAccount.Individual.LastNameIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").on("email")[0].code, ErrorCodes.MerchantAccount.Individual.EmailAddressIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").on("phone")[0].code, ErrorCodes.MerchantAccount.Individual.PhoneIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Individual.Address.StreetAddressIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Individual.Address.PostalCodeIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Individual.Address.RegionIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("individual").on("ssn")[0].code, ErrorCodes.MerchantAccount.Individual.SsnIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("business").on("legal_name")[0].code, ErrorCodes.MerchantAccount.Business.LegalNameIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("business").on("dba_name")[0].code, ErrorCodes.MerchantAccount.Business.DbaNameIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("business").on("tax_id")[0].code, ErrorCodes.MerchantAccount.Business.TaxIdIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("business").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Business.Address.StreetAddressIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("business").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Business.Address.PostalCodeIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("business").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Business.Address.RegionIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("funding").on("destination")[0].code, ErrorCodes.MerchantAccount.Funding.DestinationIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("funding").on("routing_number")[0].code, ErrorCodes.MerchantAccount.Funding.RoutingNumberIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("funding").on("account_number")[0].code, ErrorCodes.MerchantAccount.Funding.AccountNumberIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("funding").on("email")[0].code, ErrorCodes.MerchantAccount.Funding.EmailAddressIsInvalid) self.assertEquals(result.errors.for_object("merchant_account").for_object("funding").on("mobile_phone")[0].code, ErrorCodes.MerchantAccount.Funding.MobilePhoneIsInvalid) self.assertEquals(len(result.errors.for_object("merchant_account").on("base")), 0) 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.assertEquals(result.errors.for_object("merchant_account").for_object("business").on("legal_name")[0].code, ErrorCodes.MerchantAccount.Business.LegalNameIsRequiredWithTaxId) self.assertEquals(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.assertEquals(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.assertEquals(result.errors.for_object("merchant_account").for_object("funding").on("routing_number")[0].code, ErrorCodes.MerchantAccount.Funding.RoutingNumberIsRequired) self.assertEquals(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.assertEquals(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.assertEquals(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 merchant_account = 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_find_404(self): try: MerchantAccount.find("not_a_real_id") except NotFoundError: pass else: self.assertTrue(False) braintree_python-3.23.0/tests/integration/test_oauth.py000066400000000000000000000143751262761311500234070ustar00rootroot00000000000000from 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.assertEquals("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.assertEqual( result.errors.for_object("credentials").on("code")[0].code, ErrorCodes.OAuth.InvalidGrant ) self.assertIn(result.message, "Invalid grant: code not found") 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: result = 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.assertEquals("bearer", credentials.token_type) 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", "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["user[country]"], ["USA"]) self.assertEqual(params["business[name]"], ["14 Ladders"]) self.assertEqual(params["payment_methods[]"], ["credit_card", "paypal"]) self.assertEqual(len(params["signature"][0]), 64) self.assertEqual(params["algorithm"], ["SHA256"]) 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_compute_signature(self): url = "http://localhost:3000/oauth/connect?business%5Bname%5D=We+Like+Spaces&client_id=client_id%24development%24integration_client_id" signature = self.gateway.oauth._compute_signature(url) self.assertEqual(signature, "a36bcf10dd982e2e47e0d6a2cb930aea47ade73f954b7d59c58dae6167894d41") braintree_python-3.23.0/tests/integration/test_payment_method.py000066400000000000000000001314461262761311500253030ustar00rootroot00000000000000import time from datetime import datetime from random import randint 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_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.assertEquals(created_account.__class__, PayPalAccount) self.assertEquals(created_account.email, "jane.doe@example.com") self.assertNotEquals(created_account.image_url, None) found_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEquals(found_account.token, created_account.token) self.assertEquals(found_account.customer_id, created_account.customer_id) def test_create_returns_validation_failures(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "options": {"validate": False} }) self.assertEquals(status_code, 202) 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.assertEquals(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) error_code = result.errors.for_object("paypal_account").on("base")[0].code self.assertEquals(error_code, ErrorCodes.PayPalAccount.CannotVaultOneTimeUsePayPalAccount) 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.assertEquals(status_code, 202) 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.assertEquals(created_credit_card.__class__, CreditCard) self.assertEquals(created_credit_card.bin, "411111") found_credit_card = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_credit_card) self.assertEquals(found_credit_card.token, created_credit_card.token) self.assertEquals(found_credit_card.customer_id, created_credit_card.customer_id) def test_create_with_europe_bank_account_nonce(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id token = TestHelper.generate_decoded_client_token({"customer_id": customer_id, "sepa_mandate_type": EuropeBankAccount.MandateType.Business}) authorization_fingerprint = json.loads(token)["authorizationFingerprint"] client_api = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) nonce = client_api.get_europe_bank_account_nonce({ "locale": "de-DE", "bic": "DEUTDEFF", "iban": "DE89370400440532013000", "accountHolderName": "Baron Von Holder", "billingAddress": {"region": "Hesse", "country_name": "Germany"} }) self.assertNotEquals(nonce, None) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce }) self.assertTrue(result.is_success) self.assertNotEqual(result.payment_method.image_url, None) self.assertEqual(result.payment_method.customer_id, customer_id) found_bank_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(found_bank_account, None) self.assertEquals(found_bank_account.bic, "DEUTDEFF") self.assertEquals(found_bank_account.__class__, EuropeBankAccount) 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.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(android_pay_card.customer_id, 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("Visa 1111", android_pay_card.source_description) self.assertEqual(CreditCard.CardType.Visa, 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(android_pay_card.customer_id, 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(amex_express_checkout_card.card_type, "American Express") 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(amex_express_checkout_card.customer_id, 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(venmo_account.username, "venmojoe") self.assertEqual(venmo_account.venmo_user_id, "Venmo-Joe-1") self.assertEqual(venmo_account.source_description, "Venmo Account: venmojoe") self.assertRegexpMatches(venmo_account.image_url, r"\.png") self.assertEqual(venmo_account.customer_id, 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_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_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(result.payment_method.token, found_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.assertEquals(found_account.__class__, PayPalAccount) self.assertEquals(found_account.email, "jane.doe@example.com") 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) credit_card = result.credit_card found_credit_card = PaymentMethod.find(result.credit_card.token) self.assertNotEqual(None, found_credit_card) self.assertEquals(found_credit_card.__class__, CreditCard) self.assertEquals(found_credit_card.bin, "411111") 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.assertEquals(found_android_pay_card.__class__, AndroidPayCard) self.assertEqual(android_pay_card.token, found_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) 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_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_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) self.assertTrue(update_result.errors.for_object("credit_card").on("number")[0].message == "Credit card number must be 12-19 digits.") 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 == True) self.assertTrue(card2.default == False) update_result = PaymentMethod.update(card2.token, { "options": { "make_default": True } }) self.assertTrue(CreditCard.find(card1.token).default == False) self.assertTrue(CreditCard.find(card2.token).default == True) 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(randint(0,100000000)) updated_result = 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 updated_result = PaymentMethod.update( original_token, {"options": {"make_default": "true"}} ) updated_paypal_account = PayPalAccount.find(original_token) self.assertTrue(updated_paypal_account.default == True) def test_update_updates_a_paypal_accounts_token(self): customer_id = Customer.create().customer.id first_token = "paypal-account-" + str(randint(0,100000000)) second_token = "paypal-account-" + str(randint(0,100000000)) first_nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code", "token": first_token }) first_result = 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 }) second_result = PaymentMethod.create({ "payment_method_nonce": second_nonce, "customer_id": customer_id }) updated_result = PaymentMethod.update( first_token, {"token": second_token} ) self.assertTrue(updated_result.is_success == False) self.assertTrue(updated_result.errors.deep_errors[0].code == "92906") def test_payment_method_grant_raises_on_non_existent_tokens(self): granting_gateway, credit_card = 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, 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, 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, False) 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, credit_card = 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(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 forward_result = CreditCard.forward( source_merchant_card.token, "integration_merchant_id" ) self.assertTrue(forward_result.is_success) braintree.Configuration.configure( braintree.Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) customer = Customer.create().customer credit_card_result = CreditCard.create({ "customer_id": customer.id, "payment_method_nonce": forward_result.nonce }) self.assertTrue(credit_card_result.is_success) receiving_merchant_card = credit_card_result.credit_card self.assertEqual(source_merchant_card.bin, receiving_merchant_card.bin) self.assertEqual(source_merchant_card.last_4, receiving_merchant_card.last_4) self.assertEqual(source_merchant_card.expiration_month, receiving_merchant_card.expiration_month) self.assertEqual(source_merchant_card.expiration_year, receiving_merchant_card.expiration_year) 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.23.0/tests/integration/test_payment_method_nonce.py000066400000000000000000000036021262761311500264550ustar00rootroot00000000000000from 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): nonce = PaymentMethodNonce.find("threedsecurednonce") three_d_secure_info = nonce.three_d_secure_info self.assertEquals("CreditCard", nonce.type) self.assertEquals("threedsecurednonce", nonce.nonce) self.assertEquals("Y", three_d_secure_info.enrolled) self.assertEquals("authenticate_successful", three_d_secure_info.status) self.assertEquals(True, three_d_secure_info.liability_shifted) self.assertEquals(True, three_d_secure_info.liability_shift_possible) 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.assertEquals(nonce, found_nonce.nonce) self.assertEquals(None, found_nonce.three_d_secure_info) def test_find_raises_not_found_when_404(self): self.assertRaises(NotFoundError, PaymentMethodNonce.find, "not-a-nonce") braintree_python-3.23.0/tests/integration/test_paypal_account.py000066400000000000000000000142621262761311500252640ustar00rootroot00000000000000from tests.test_helper import * import time from braintree.test.nonces import Nonces import braintree.test.venmo_sdk as venmo_sdk 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.assertEquals(found_account.__class__, PayPalAccount) self.assertEquals(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) 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 payment_method_token = "paypal-account-" + str(int(time.time())) 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.assertNotEquals(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 credit_card = CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "12/2099" }).credit_card 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.assertEquals(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 credit_card = CreditCard.create({ "token": payment_method_token, "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "12/2099" }).credit_card 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) self.assertEquals( ErrorCodes.PayPalAccount.TokenIsInUse, result.errors.for_object("paypal_account").on("token")[0].code ) result = PayPalAccount.update(old_token, { "token": payment_method_token, }) self.assertFalse(result.is_success) self.assertEquals( ErrorCodes.PayPalAccount.TokenIsInUse, result.errors.for_object("paypal_account").on("token")[0].code ) braintree_python-3.23.0/tests/integration/test_plan.py000066400000000000000000000055451262761311500232200ustar00rootroot00000000000000from 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.assertEquals(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.assertNotEquals(None, actual_plan) self.assertEquals(attributes["billing_day_of_month"], 1) self.assertEquals(attributes["billing_frequency"], 1) self.assertEquals(attributes["currency_iso_code"], "USD") self.assertEquals(attributes["description"], "some description") self.assertEquals(attributes["name"], "python test plan") self.assertEquals(attributes["number_of_billing_cycles"], 1) self.assertEquals(attributes["price"], "1.00") self.assertEquals(add_on_attributes["name"], actual_plan.add_ons[0].name) self.assertEquals(discount_attributes["name"], actual_plan.discounts[0].name) braintree_python-3.23.0/tests/integration/test_search.py000066400000000000000000000316141262761311500235270ustar00rootroot00000000000000from 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" % randint(1,100000) 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.assertEquals(1, collection.maximum_size) self.assertEquals(t_1800.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.greater_than_or_equal_to("1700") ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(t_1800.id, collection.first.id) def test_range_node_max(self): name = "Henrietta Livingston%s" % randint(1,100000) 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.assertEquals(1, collection.maximum_size) self.assertEquals(t_1500.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.less_than_or_equal_to("1700") ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(t_1500.id, collection.first.id) def test_range_node_is(self): name = "Henrietta Livingston%s" % randint(1,100000) 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 == "1800" ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(t_1800.id, collection.first.id) def test_range_node_between(self): name = "Henrietta Livingston%s" % 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.between("1100", "1600") ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(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.23.0/tests/integration/test_settlement_batch_summary.py000066400000000000000000000050151262761311500273600ustar00rootroot00000000000000from 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.assertEquals([], 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) code = result.errors.for_object('settlement_batch_summary').on('settlement_date')[0].code self.assertEquals(ErrorCodes.SettlementBatchSummary.SettlementDateIsInvalid, 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" }, "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'][0] count = int(visa_records['count']) self.assertGreaterEqual(count, 1) self.assertGreaterEqual(float(visa_records['amount_settled']), float(TransactionAmounts.Authorize)) 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.23.0/tests/integration/test_subscription.py000066400000000000000000001525761262761311500250210ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.nonces import Nonces 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.assertNotEquals(None, re.search("\A\w{6}\Z", subscription.id)) self.assertEquals(Decimal("12.34"), subscription.price) self.assertEquals(Decimal("12.34"), subscription.next_bill_amount) self.assertEquals(Decimal("12.34"), subscription.next_billing_period_amount) self.assertEquals(Subscription.Status.Active, subscription.status) self.assertEquals("integration_trialless_plan", subscription.plan_id) self.assertEquals(TestHelper.default_merchant_account_id, subscription.merchant_account_id) self.assertEquals(Decimal("0.00"), subscription.balance) self.assertEquals(date, type(subscription.first_billing_date)) self.assertEquals(date, type(subscription.next_billing_date)) self.assertEquals(date, type(subscription.billing_period_start_date)) self.assertEquals(date, type(subscription.billing_period_end_date)) self.assertEquals(date, type(subscription.paid_through_date)) self.assertEquals(datetime, type(subscription.created_at)) self.assertEquals(datetime, type(subscription.updated_at)) self.assertEquals(1, subscription.current_billing_cycle) self.assertEquals(0, subscription.failure_count) self.assertEquals(self.credit_card.token, subscription.payment_method_token) self.assertEquals(Subscription.Status.Active, subscription.status_history[0].status) self.assertEquals(Decimal("12.34"), subscription.status_history[0].price) self.assertEquals(Decimal("0.00"), subscription.status_history[0].balance) self.assertEquals(Subscription.Source.Api, subscription.status_history[0].subscription_source) 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" }) status_code, 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.assertEquals(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.assertEquals(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.assertEquals(TestHelper.trialless_plan["trial_period"], subscription.trial_period) self.assertEquals(None, subscription.trial_duration) self.assertEquals(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.assertEquals(TestHelper.trial_plan["trial_period"], subscription.trial_period) self.assertEquals(TestHelper.trial_plan["trial_duration"], subscription.trial_duration) self.assertEquals(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.assertEquals(True, subscription.trial_period) self.assertEquals(5, subscription.trial_duration) self.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(1, len(subscription.transactions)) transaction = subscription.transactions[0] self.assertEquals(Transaction, type(transaction)) self.assertEquals(TestHelper.trialless_plan["price"], transaction.amount) self.assertEquals("sale", transaction.type) self.assertEquals(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.assertEquals(subscription.billing_period_start_date, transaction.subscription_details.billing_period_start_date) self.assertEquals(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.assertEquals(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.assertEquals(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) self.assertEquals("81906", result.errors.for_object("subscription").on("id")[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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(date.today() + timedelta(days=3), result.subscription.first_billing_date) self.assertEquals(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) self.assertEquals( ErrorCodes.Subscription.FirstBillingDateCannotBeInThePast, result.errors.for_object("subscription").on("first_billing_date")[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.assertEquals(0, len(subscription.add_ons)) self.assertEquals(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.assertEquals(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEquals("increase_10", add_ons[0].id) self.assertEquals(Decimal("10.00"), add_ons[0].amount) self.assertEquals(1, add_ons[0].quantity) self.assertEquals(None, add_ons[0].number_of_billing_cycles) self.assertTrue(add_ons[0].never_expires) self.assertEquals(0, add_ons[0].current_billing_cycle) self.assertEquals("increase_20", add_ons[1].id) self.assertEquals(Decimal("20.00"), add_ons[1].amount) self.assertEquals(1, add_ons[1].quantity) self.assertEquals(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEquals(0, add_ons[1].current_billing_cycle) self.assertEquals(2, len(subscription.discounts)) discounts = sorted(subscription.discounts, key=lambda discount: discount.id) self.assertEquals("discount_11", discounts[0].id) self.assertEquals(Decimal("11.00"), discounts[0].amount) self.assertEquals(1, discounts[0].quantity) self.assertEquals(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) self.assertEquals(0, discounts[0].current_billing_cycle) self.assertEquals("discount_7", discounts[1].id) self.assertEquals(Decimal("7.00"), discounts[1].amount) self.assertEquals(1, discounts[1].quantity) self.assertEquals(None, discounts[1].number_of_billing_cycles) self.assertTrue(discounts[1].never_expires) self.assertEquals(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.assertEquals(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEquals("increase_10", add_ons[0].id) self.assertEquals(Decimal("50.00"), add_ons[0].amount) self.assertEquals(2, add_ons[0].quantity) self.assertEquals(5, add_ons[0].number_of_billing_cycles) self.assertFalse(add_ons[0].never_expires) self.assertEquals(0, add_ons[0].current_billing_cycle) self.assertEquals("increase_20", add_ons[1].id) self.assertEquals(Decimal("100.00"), add_ons[1].amount) self.assertEquals(4, add_ons[1].quantity) self.assertEquals(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEquals(0, add_ons[1].current_billing_cycle) self.assertEquals(2, len(subscription.discounts)) discounts = sorted(subscription.discounts, key=lambda discount: discount.id) self.assertEquals("discount_11", discounts[0].id) self.assertEquals(Decimal("11.00"), discounts[0].amount) self.assertEquals(1, discounts[0].quantity) self.assertEquals(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) self.assertEquals(0, discounts[0].current_billing_cycle) self.assertEquals("discount_7", discounts[1].id) self.assertEquals(Decimal("15.00"), discounts[1].amount) self.assertEquals(3, discounts[1].quantity) self.assertEquals(19, discounts[1].number_of_billing_cycles) self.assertFalse(discounts[1].never_expires) self.assertEquals(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.assertEquals(0, len(subscription.add_ons)) self.assertEquals(1, len(subscription.discounts)) self.assertEquals("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.assertEquals(1, len(subscription.add_ons)) self.assertEquals("increase_30", subscription.add_ons[0].id) self.assertEquals(Decimal("50.00"), subscription.add_ons[0].amount) self.assertEquals(2, subscription.add_ons[0].quantity) self.assertEquals(5, subscription.add_ons[0].number_of_billing_cycles) self.assertFalse(subscription.add_ons[0].never_expires) self.assertEquals(0, subscription.add_ons[0].current_billing_cycle) self.assertEquals(1, len(subscription.discounts)) self.assertEquals("discount_15", subscription.discounts[0].id) self.assertEquals(Decimal("17.00"), subscription.discounts[0].amount) self.assertEquals(1, subscription.discounts[0].quantity) self.assertEquals(None, subscription.discounts[0].number_of_billing_cycles) self.assertTrue(subscription.discounts[0].never_expires) self.assertEquals(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.assertEquals( ErrorCodes.Subscription.Modification.AmountIsInvalid, result.errors.for_object("subscription").for_object("add_ons").for_object("update").for_index(0).on("amount")[0].code ) self.assertEquals( 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.assertEquals("123*123456789012345678", subscription.descriptor.name) self.assertEquals("3334445555", subscription.descriptor.phone) transaction = subscription.transactions[0] self.assertEquals("123*123456789012345678", transaction.descriptor.name) self.assertEquals("3334445555", transaction.descriptor.phone) self.assertEquals("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) transaction = result.transaction self.assertEquals( ErrorCodes.Descriptor.NameFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("name")[0].code ) self.assertEquals( ErrorCodes.Descriptor.PhoneFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("phone")[0].code ) 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.assertEquals(subscription.id, found_subscription.id) def test_find_with_invalid_token(self): try: Subscription.find("bad_token") self.assertTrue(False) except Exception as e: self.assertEquals("subscription with id bad_token not found", str(e)) def test_update_creates_a_prorated_transaction_when_merchant_is_set_to_prorate(self): new_id = str(random.randint(1, 1000000)) result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("1"), }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEquals(2, len(subscription.transactions)) def test_update_creates_a_prorated_transaction_when_flag_is_passed_as_True(self): new_id = str(random.randint(1, 1000000)) 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.assertEquals(2, len(subscription.transactions)) def test_update_does_not_create_a_prorated_transaction_when_flag_is_passed_as_False(self): new_id = str(random.randint(1, 1000000)) 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.assertEquals(1, len(subscription.transactions)) def test_update_does_not_update_subscription_when_revert_subscription_on_proration_failure_is_true(self): new_id = str(random.randint(1, 1000000)) 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.assertEquals(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.assertEquals(self.updateable_subscription.price, found_subscription.price) def test_update_updates_subscription_when_revert_subscription_on_proration_failure_is_false(self): new_id = str(random.randint(1, 1000000)) 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.assertEquals(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.assertEquals(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.assertEquals(new_id, subscription.id) self.assertEquals(TestHelper.trial_plan["id"], subscription.plan_id) self.assertEquals(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.assertEquals(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.assertEquals(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" }) status_code, 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.assertEquals("4242", newCard.last_4) self.assertNotEquals(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.assertEquals(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.assertEquals(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) self.assertEquals("81906", result.errors.for_object("subscription").on("id")[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.assertEquals(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEquals("increase_10", add_ons[0].id) self.assertEquals(Decimal("50.00"), add_ons[0].amount) self.assertEquals(2, add_ons[0].quantity) self.assertEquals(5, add_ons[0].number_of_billing_cycles) self.assertFalse(add_ons[0].never_expires) self.assertEquals("increase_20", add_ons[1].id) self.assertEquals(Decimal("100.00"), add_ons[1].amount) self.assertEquals(4, add_ons[1].quantity) self.assertEquals(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEquals(2, len(subscription.discounts)) discounts = sorted(subscription.discounts, key=lambda discount: discount.id) self.assertEquals("discount_11", discounts[0].id) self.assertEquals(Decimal("11.00"), discounts[0].amount) self.assertEquals(1, discounts[0].quantity) self.assertEquals(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) self.assertEquals("discount_7", discounts[1].id) self.assertEquals(Decimal("15.00"), discounts[1].amount) self.assertEquals(3, discounts[1].quantity) self.assertEquals(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.assertEquals(1, len(subscription.add_ons)) self.assertEquals("increase_30", subscription.add_ons[0].id) self.assertEquals(Decimal("50.00"), subscription.add_ons[0].amount) self.assertEquals(2, subscription.add_ons[0].quantity) self.assertEquals(5, subscription.add_ons[0].number_of_billing_cycles) self.assertFalse(subscription.add_ons[0].never_expires) self.assertEquals(1, len(subscription.discounts)) self.assertEquals("discount_15", subscription.discounts[0].id) self.assertEquals(Decimal("17.00"), subscription.discounts[0].amount) self.assertEquals(1, subscription.discounts[0].quantity) self.assertEquals(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.assertEquals(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEquals("increase_20", add_ons[0].id) self.assertEquals(Decimal("20.00"), add_ons[0].amount) self.assertEquals(1, add_ons[0].quantity) self.assertEquals(None, add_ons[0].number_of_billing_cycles) self.assertTrue(add_ons[0].never_expires) self.assertEquals("increase_30", add_ons[1].id) self.assertEquals(Decimal("30.00"), add_ons[1].amount) self.assertEquals(1, add_ons[1].quantity) self.assertEquals(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEquals(1, len(subscription.discounts)) self.assertEquals("discount_15", subscription.discounts[0].id) self.assertEquals(Decimal("15.00"), subscription.discounts[0].amount) self.assertEquals(1, subscription.discounts[0].quantity) self.assertEquals(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.assertEquals("999*99", updated_subscription.descriptor.name) self.assertEquals("1234567890", updated_subscription.descriptor.phone) 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) self.assertEquals("81905", result.errors.for_object("subscription").on("status")[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_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): trial_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("3") }).subscription trialless_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": Decimal("3") }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id == "no such plan id", SubscriptionSearch.price == Decimal("3") ]) self.assertEquals(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.assertEquals(subscription.price, transaction.amount); self.assertNotEqual(None, transaction.processor_authorization_code); self.assertEquals(Transaction.Type.Sale, transaction.type); self.assertEquals(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.assertEquals(subscription.price, transaction.amount); self.assertNotEqual(None, transaction.processor_authorization_code); self.assertEquals(Transaction.Type.Sale, transaction.type); self.assertEquals(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.assertEquals(Decimal(TransactionAmounts.Authorize), transaction.amount); self.assertNotEqual(None, transaction.processor_authorization_code); self.assertEquals(Transaction.Type.Sale, transaction.type); self.assertEquals(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.assertEquals(Decimal(TransactionAmounts.Authorize), transaction.amount); self.assertNotEqual(None, transaction.processor_authorization_code); self.assertEquals(Transaction.Type.Sale, transaction.type); self.assertEquals(Transaction.Status.Authorized, 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.assertEquals(status_code, 202) 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.assertEquals(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.assertEquals( 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.assertEquals( ErrorCodes.Subscription.PaymentMethodNonceIsInvalid, result.errors.for_object("subscription")[0].code ) braintree_python-3.23.0/tests/integration/test_test_helper.py000066400000000000000000000022321262761311500245720ustar00rootroot00000000000000from 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.assertEquals(Transaction.Status.Settled, Transaction.find(self.transaction.id).status) def test_settlement_confirm_transaction(self): TestHelper.settlement_confirm_transaction(self.transaction.id) self.assertEquals(Transaction.Status.SettlementConfirmed, Transaction.find(self.transaction.id).status) def test_settlement_decline_transaction(self): TestHelper.settlement_decline_transaction(self.transaction.id) self.assertEquals(Transaction.Status.SettlementDeclined, Transaction.find(self.transaction.id).status) braintree_python-3.23.0/tests/integration/test_testing_gateway.py000066400000000000000000000032201262761311500254500ustar00rootroot00000000000000from 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, "", "", "") 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.23.0/tests/integration/test_transaction.py000066400000000000000000003616151262761311500246160ustar00rootroot00000000000000import 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 import braintree.test.venmo_sdk as venmo_sdk class TestTransaction(unittest.TestCase): def test_sale_returns_risk_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertIsInstance(transaction.risk_data, RiskData) self.assertEquals(transaction.risk_data.id, None) self.assertEquals(transaction.risk_data.decision, "Not Evaluated") 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("\A\w{6}\Z", transaction.id)) self.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEquals("411111", transaction.credit_card_details.bin) self.assertEquals("1111", transaction.credit_card_details.last_4) self.assertEquals("05/2009", transaction.credit_card_details.expiration_date) self.assertEquals(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("\A\w{6}\Z", transaction.id)) self.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEquals("411111", transaction.credit_card_details.bin) self.assertEquals("1111", transaction.credit_card_details.last_4) self.assertEquals("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.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals("05", transaction.credit_card_details.expiration_month) self.assertEquals("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.assertNotEquals(None, re.search("\A\w{6}\Z", transaction.id)) self.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals(Transaction.Status.Authorized, transaction.status) self.assertEquals(Decimal("100.00"), transaction.amount) self.assertEquals("123", transaction.order_id) self.assertEquals("MyShoppingCartProvider", transaction.channel) self.assertEquals("1000", transaction.processor_response_code) self.assertEquals(datetime, type(transaction.created_at)) self.assertEquals(datetime, type(transaction.updated_at)) self.assertEquals("510510", transaction.credit_card_details.bin) self.assertEquals("5100", transaction.credit_card_details.last_4) self.assertEquals("510510******5100", transaction.credit_card_details.masked_number) self.assertEquals("MasterCard", transaction.credit_card_details.card_type) self.assertEquals("The Cardholder", transaction.credit_card_details.cardholder_name) self.assertEquals(None, transaction.avs_error_response_code) self.assertEquals("M", transaction.avs_postal_code_response_code) self.assertEquals("M", transaction.avs_street_address_response_code) self.assertEquals("Dan", transaction.customer_details.first_name) self.assertEquals("Smith", transaction.customer_details.last_name) self.assertEquals("Braintree", transaction.customer_details.company) self.assertEquals("dan@example.com", transaction.customer_details.email) self.assertEquals("419-555-1234", transaction.customer_details.phone) self.assertEquals("419-555-1235", transaction.customer_details.fax) self.assertEquals("http://braintreepayments.com", transaction.customer_details.website) self.assertEquals("Carl", transaction.billing_details.first_name) self.assertEquals("Jones", transaction.billing_details.last_name) self.assertEquals("Braintree", transaction.billing_details.company) self.assertEquals("123 E Main St", transaction.billing_details.street_address) self.assertEquals("Suite 403", transaction.billing_details.extended_address) self.assertEquals("Chicago", transaction.billing_details.locality) self.assertEquals("IL", transaction.billing_details.region) self.assertEquals("60622", transaction.billing_details.postal_code) self.assertEquals("United States of America", transaction.billing_details.country_name) self.assertEquals("US", transaction.billing_details.country_code_alpha2) self.assertEquals("USA", transaction.billing_details.country_code_alpha3) self.assertEquals("840", transaction.billing_details.country_code_numeric) self.assertEquals("Andrew", transaction.shipping_details.first_name) self.assertEquals("Mason", transaction.shipping_details.last_name) self.assertEquals("Braintree", transaction.shipping_details.company) self.assertEquals("456 W Main St", transaction.shipping_details.street_address) self.assertEquals("Apt 2F", transaction.shipping_details.extended_address) self.assertEquals("Bartlett", transaction.shipping_details.locality) self.assertEquals("IL", transaction.shipping_details.region) self.assertEquals("60103", transaction.shipping_details.postal_code) self.assertEquals("Mexico", transaction.shipping_details.country_name) self.assertEquals("MX", transaction.shipping_details.country_code_alpha2) self.assertEquals("MEX", transaction.shipping_details.country_code_alpha3) self.assertEquals("484", transaction.shipping_details.country_code_numeric) self.assertEquals(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.assertEquals(transaction.credit_card_details.masked_number, "411111******1111") self.assertEquals(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.assertEquals("411111******1111", transaction.credit_card_details.masked_number) self.assertEquals("411111******1111", transaction.vault_credit_card.masked_number) 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.assertEquals("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.assertEquals(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.assertEquals(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.assertEquals("123 Fake St.", transaction.shipping_details.street_address) self.assertEquals(address.id, transaction.shipping_details.id) 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.assertEquals("123 Fake St.", transaction.billing_details.street_address) self.assertEquals(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.assertEquals("12345", transaction.purchase_order_number) self.assertEquals(Decimal("10.00"), transaction.tax_amount) self.assertEquals(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) self.assertEquals( ErrorCodes.Transaction.TaxAmountFormatIsInvalid, result.errors.for_object("transaction").on("tax_amount")[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) self.assertEquals( ErrorCodes.Transaction.PurchaseOrderNumberIsTooLong, result.errors.for_object("transaction").on("purchase_order_number")[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) self.assertEquals( ErrorCodes.Transaction.PurchaseOrderNumberIsInvalid, result.errors.for_object("transaction").on("purchase_order_number")[0].code ) def test_sale_with_processor_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.assertEquals(Transaction.Status.ProcessorDeclined, transaction.status) self.assertEquals("2000 : Do Not Honor", 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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(Transaction.GatewayRejectionReason.Fraud, 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) self.assertEquals( ErrorCodes.Transaction.ServiceFeeAmountNotAllowedOnMasterMerchantAccount, result.errors.for_object("transaction").on("service_fee_amount")[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.assertEquals( 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.assertEquals( 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.assertEquals( 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.assertEquals( 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.assertEquals( 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.assertEquals( 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.assertEquals( 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.assertEquals( 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.assertEquals( 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.assertTrue(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" }) status_code, 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_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.assertEquals( 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.assertEquals(CreditCard.Prepaid.Unknown, transaction.credit_card_details.prepaid) self.assertEquals(CreditCard.Debit.Unknown, transaction.credit_card_details.debit) self.assertEquals(CreditCard.Commercial.Unknown, transaction.credit_card_details.commercial) self.assertEquals(CreditCard.Healthcare.Unknown, transaction.credit_card_details.healthcare) self.assertEquals(CreditCard.Payroll.Unknown, transaction.credit_card_details.payroll) self.assertEquals(CreditCard.DurbinRegulated.Unknown, transaction.credit_card_details.durbin_regulated) self.assertEquals(CreditCard.CardTypeIndicator.Unknown, transaction.credit_card_details.issuing_bank) self.assertEquals(CreditCard.CardTypeIndicator.Unknown, transaction.credit_card_details.country_of_issuance) def test_create_can_set_recurring_flag(self): result = Transaction.sale({ "amount": "100", "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "recurring": True }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEquals(True, transaction.recurring) 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("\A\d{6,7}\Z", transaction.customer_details.id)) self.assertEquals(transaction.customer_details.id, transaction.vault_customer.id) self.assertNotEqual(None, re.search("\A\w{4,5}\Z", transaction.credit_card_details.token)) self.assertEquals(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("\A\d{6,7}\Z", transaction.customer_details.id)) self.assertEquals(transaction.customer_details.id, transaction.vault_customer.id) self.assertNotEqual(None, re.search("\A\w{4,5}\Z", transaction.credit_card_details.token)) self.assertEquals(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.assertNotEquals(None, re.search("\A\d{6,7}\Z", transaction.customer_details.id)) self.assertEquals(transaction.customer_details.id, transaction.vault_customer.id) credit_card = CreditCard.find(transaction.vault_credit_card.token) self.assertEquals(credit_card.billing_address.id, transaction.billing_details.id) self.assertEquals(credit_card.billing_address.id, transaction.vault_billing_address.id) self.assertEquals("Carl", credit_card.billing_address.first_name) self.assertEquals("Jones", credit_card.billing_address.last_name) self.assertEquals("Braintree", credit_card.billing_address.company) self.assertEquals("123 E Main St", credit_card.billing_address.street_address) self.assertEquals("Suite 403", credit_card.billing_address.extended_address) self.assertEquals("Chicago", credit_card.billing_address.locality) self.assertEquals("IL", credit_card.billing_address.region) self.assertEquals("60622", credit_card.billing_address.postal_code) self.assertEquals("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.assertNotEquals(None, re.search("\A\d{6,7}\Z", transaction.customer_details.id)) self.assertEquals(transaction.customer_details.id, transaction.vault_customer.id) shipping_address = transaction.vault_customer.addresses[0] self.assertEquals("Carl", shipping_address.first_name) self.assertEquals("Jones", shipping_address.last_name) self.assertEquals("Braintree", shipping_address.company) self.assertEquals("123 E Main St", shipping_address.street_address) self.assertEquals("Suite 403", shipping_address.extended_address) self.assertEquals("Chicago", shipping_address.locality) self.assertEquals("IL", shipping_address.region) self.assertEquals("60622", shipping_address.postal_code) self.assertEquals("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.assertEquals(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.assertEquals(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.assertEquals(customer_id, transaction.customer_details.id) self.assertEquals(customer_id, transaction.vault_customer.id) self.assertEquals(payment_method_token, transaction.credit_card_details.token) self.assertEquals(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.assertEquals(customer.id, transaction.customer_details.id) self.assertEquals(customer.id, transaction.vault_customer.id) self.assertEquals(credit_card.token, transaction.credit_card_details.token) self.assertEquals(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.assertEquals(customer.id, transaction.customer_details.id) self.assertEquals(customer.id, transaction.vault_customer.id) self.assertEquals(credit_card.token, transaction.credit_card_details.token) self.assertEquals(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.assertEquals(customer.id, transaction.customer_details.id) self.assertEquals(customer.id, transaction.vault_customer.id) self.assertEquals(credit_card.token, transaction.credit_card_details.token) self.assertEquals(credit_card.token, transaction.vault_credit_card.token) self.assertEquals("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.assertEquals(params, result.params) self.assertEquals( 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.assertNotEquals(None, re.search("\A\w{6}\Z", transaction.id)) self.assertEquals(Transaction.Type.Credit, transaction.type) self.assertEquals(Decimal(TransactionAmounts.Authorize), transaction.amount) cc_details = transaction.credit_card_details self.assertEquals("411111", cc_details.bin) self.assertEquals("1111", cc_details.last_4) self.assertEquals("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.assertEquals(params, result.params) self.assertEquals( 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.assertEquals( 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.assertEquals(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.assertEquals(TestHelper.default_merchant_account_id, transaction.merchant_account_id) def test_find_returns_a_found_transaction(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction found_transaction = Transaction.find(transaction.id) self.assertEquals(transaction.id, found_transaction.id) def test_find_for_bad_transaction_raises_not_found_error(self): try: Transaction.find("notreal") self.assertTrue(False) except NotFoundError as e: self.assertEquals("transaction with id 'notreal' not found", str(e)) 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.assertEquals(transaction.id, result.transaction.id) self.assertEquals(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.assertEquals( 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.assertEquals(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.assertEquals(ErrorCodes.Transaction.TypeIsRequired, result.errors.for_object("transaction").on("type")[0].code) self.assertEquals( ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_code_alpha2")[0].code ) self.assertEquals( ErrorCodes.Address.CountryCodeAlpha3IsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_code_alpha3")[0].code ) self.assertEquals( ErrorCodes.Address.CountryCodeNumericIsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_code_numeric")[0].code ) self.assertEquals( 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.assertEquals(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals("411111", transaction.credit_card_details.bin) self.assertEquals("1111", transaction.credit_card_details.last_4) self.assertEquals("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: result = Transaction.confirm_transparent_redirect(query_string) self.fail() except AuthorizationError as e: self.assertEquals("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.assertEquals(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEquals(Transaction.Type.Credit, transaction.type) self.assertEquals("411111", transaction.credit_card_details.bin) self.assertEquals("1111", transaction.credit_card_details.last_4) self.assertEquals("05/2010", transaction.credit_card_details.expiration_date) self.assertEquals("US", transaction.billing_details.country_code_alpha2) self.assertEquals("USA", transaction.billing_details.country_code_alpha3) self.assertEquals("840", transaction.billing_details.country_code_numeric) self.assertEquals("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.assertEquals(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEquals(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.assertEquals(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEquals(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.assertEquals(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEquals("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.assertEquals(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEquals("123*123456789012345678", submitted_transaction.descriptor.name) self.assertEquals("3334445555", submitted_transaction.descriptor.phone) self.assertEquals("ebay.com", submitted_transaction.descriptor.url) 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", } try: Transaction.submit_for_settlement(transaction.id, Decimal("900"), params) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: invalid_param'", str(e)) 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.assertEquals( 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.assertEquals( ErrorCodes.Transaction.SettlementAmountIsLessThanServiceFeeAmount, result.errors.for_object("transaction").on("amount")[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.assertEquals(2, len(submitted_transaction.status_history)) self.assertEquals(Transaction.Status.Authorized, submitted_transaction.status_history[0].status) self.assertEquals(Decimal(TransactionAmounts.Authorize), submitted_transaction.status_history[0].amount) self.assertEquals(Transaction.Status.SubmittedForSettlement, submitted_transaction.status_history[1].status) self.assertEquals(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.assertEquals(Transaction.Type.Credit, refund.type) self.assertEquals(Decimal(TransactionAmounts.Authorize), refund.amount) self.assertEquals(transaction.id, refund.refunded_transaction_id) self.assertEquals(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.assertEquals(Transaction.Type.Credit, result.transaction.type) self.assertEquals(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.assertEquals(Transaction.Type.Credit, refund1.type) self.assertEquals(Decimal("500.00"), refund1.amount) refund2 = Transaction.refund(transaction.id, Decimal("500.00")).transaction self.assertEquals(Transaction.Type.Credit, refund2.type) self.assertEquals(Decimal("500.00"), refund2.amount) transaction = Transaction.find(transaction.id) self.assertEquals(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.assertEquals( ErrorCodes.Transaction.HasAlreadyBeenRefunded, result.errors.for_object("transaction").on("base")[0].code ) 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.assertEquals( ErrorCodes.Transaction.CannotRefundUnlessSettled, result.errors.for_object("transaction").on("base")[0].code ) def __create_transaction_to_refund(self): 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 def __create_paypal_transaction(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": { "submit_for_settlement": True } }).transaction return transaction def __create_escrowed_transaction(self): 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.assertEquals(TestHelper.trialless_plan["id"], transaction.plan_id) self.assertEquals(2, len(transaction.add_ons)) add_ons = sorted(transaction.add_ons, key=lambda add_on: add_on.id) self.assertEquals("increase_10", add_ons[0].id) self.assertEquals(Decimal("11.00"), add_ons[0].amount) self.assertEquals(2, add_ons[0].quantity) self.assertEquals(5, add_ons[0].number_of_billing_cycles) self.assertFalse(add_ons[0].never_expires) self.assertEquals("increase_20", add_ons[1].id) self.assertEquals(Decimal("21.00"), add_ons[1].amount) self.assertEquals(3, add_ons[1].quantity) self.assertEquals(6, add_ons[1].number_of_billing_cycles) self.assertFalse(add_ons[1].never_expires) self.assertEquals(1, len(transaction.discounts)) discounts = transaction.discounts self.assertEquals("discount_7", discounts[0].id) self.assertEquals(Decimal("7.50"), discounts[0].amount) self.assertEquals(2, discounts[0].quantity) self.assertEquals(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-08-08", "room_rate": "239.00", } } }) self.assertTrue(result.is_success) transaction = result.transaction 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", } } }) self.assertFalse(result.is_success) self.assertEquals( ErrorCodes.Transaction.Industry.Lodging.CheckOutDateMustFollowCheckInDate, result.errors.for_object("transaction").for_object("industry").on("check_out_date")[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) transaction = result.transaction 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.assertEquals( ErrorCodes.Transaction.Industry.TravelCruise.TravelPackageIsInvalid, result.errors.for_object("transaction").for_object("industry").on("travel_package")[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.assertEquals("123*123456789012345678", transaction.descriptor.name) self.assertEquals("3334445555", transaction.descriptor.phone) self.assertEquals("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) transaction = result.transaction self.assertEquals( ErrorCodes.Descriptor.NameFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("name")[0].code ) self.assertEquals( ErrorCodes.Descriptor.PhoneFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("phone")[0].code ) self.assertEquals( 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.assertNotEquals(transaction.id, clone_transaction.id) self.assertEquals(Transaction.Type.Sale, clone_transaction.type) self.assertEquals(Transaction.Status.Authorized, clone_transaction.status) self.assertEquals(Decimal("123.45"), clone_transaction.amount) self.assertEquals("MyShoppingCartProvider", clone_transaction.channel) self.assertEquals("123", clone_transaction.order_id) self.assertEquals("510510******5100", clone_transaction.credit_card_details.masked_number) self.assertEquals("Dan", clone_transaction.customer_details.first_name) self.assertEquals("Carl", clone_transaction.billing_details.first_name) self.assertEquals("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.assertEquals(Transaction.Type.Sale, clone_transaction.type) self.assertEquals(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.assertEquals( 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.assertEquals(date(2013, 4, 10), disbursement_details.disbursement_date) self.assertEquals("USD", disbursement_details.settlement_currency_iso_code) self.assertEquals(Decimal("1"), disbursement_details.settlement_currency_exchange_rate) self.assertEquals(False, disbursement_details.funds_held) self.assertEquals(True, disbursement_details.success) self.assertEquals(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.assertEquals(Transaction.Status.GatewayRejected, result.transaction.status) self.assertEquals(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.assertEquals( 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.assertEquals( ErrorCodes.Transaction.ThreeDSecureTransactionDataDoesntMatchVerify, result.errors.for_object("transaction").on("three_d_secure_token")[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.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals(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.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals(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.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals(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.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals(Transaction.Status.Authorized, transaction.status) submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEquals(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.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals(Transaction.Status.Authorized, transaction.status) submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEquals(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.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals(Transaction.Status.Authorized, transaction.status) submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEquals(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) def test_find_exposes_disputes(self): transaction = Transaction.find("disputedtransaction") dispute = transaction.disputes[0] self.assertEquals(date(2014, 3, 1), dispute.received_date) self.assertEquals(date(2014, 3, 21), dispute.reply_by_date) self.assertEquals("USD", dispute.currency_iso_code) self.assertEquals(Decimal("250.00"), dispute.amount) self.assertEquals(Dispute.Status.Won, dispute.status) self.assertEquals(Dispute.Reason.Fraud, dispute.reason) self.assertEquals("disputedtransaction", dispute.transaction_details.id) self.assertEquals(Decimal("1000.00"), dispute.transaction_details.amount) self.assertEquals(Dispute.Kind.Chargeback, dispute.kind) self.assertEquals(date(2014, 3, 1), dispute.date_opened) self.assertEquals(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.assertEquals("Y", three_d_secure_info.enrolled) self.assertEquals("authenticate_successful", three_d_secure_info.status) self.assertEquals(True, three_d_secure_info.liability_shifted) self.assertEquals(True, three_d_secure_info.liability_shift_possible) 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.assertEquals(None, three_d_secure_info) def test_find_exposes_retrievals(self): transaction = Transaction.find("retrievaltransaction") dispute = transaction.disputes[0] self.assertEquals("USD", dispute.currency_iso_code) self.assertEquals(Decimal("1000.00"), dispute.amount) self.assertEquals(Dispute.Status.Open, dispute.status) self.assertEquals(Dispute.Reason.Retrieval, dispute.reason) self.assertEquals("retrievaltransaction", dispute.transaction_details.id) self.assertEquals(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.assertEquals(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search('PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search('SALE-\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_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.assertEquals(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search('PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search('SALE-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEquals(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.assertEquals(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search('PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search('SALE-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEquals(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.assertEquals(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search('PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search('SALE-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEquals(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.assertEquals(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search('PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search('SALE-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEquals(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.assertEquals(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search('PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search('SALE-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEquals(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.assertEquals(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.assertEquals(transaction.paypal_details.payer_email, "payer@example.com") self.assertEquals(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.assertEquals(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search('PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search('SALE-\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.assertEquals(status_code, 202) 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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(void_transaction.id, sale_transaction.id) self.assertEquals(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.assertEquals(Transaction.Type.Credit, refund.type) self.assertEquals(Decimal(TransactionAmounts.Authorize), refund.amount) self.assertEquals(transaction.id, refund.refunded_transaction_id) self.assertEquals(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.assertEquals(Transaction.Type.Credit, result.transaction.type) self.assertEquals(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.assertEquals(Transaction.Type.Credit, refund1.type) self.assertEquals(Decimal("500.00"), refund1.amount) refund2 = Transaction.refund(transaction.id, Decimal("500.00")).transaction self.assertEquals(Transaction.Type.Credit, refund2.type) self.assertEquals(Decimal("500.00"), refund2.amount) transaction = Transaction.find(transaction.id) self.assertEquals(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.assertNotEquals(None, transaction.paypal_details.debug_id) self.assertNotEquals(None, transaction.paypal_details.payer_email) self.assertNotEquals(None, transaction.paypal_details.authorization_id) self.assertNotEquals(None, transaction.paypal_details.payer_id) self.assertNotEquals(None, transaction.paypal_details.payer_first_name) self.assertNotEquals(None, transaction.paypal_details.payer_last_name) self.assertNotEquals(None, transaction.paypal_details.seller_protection_status) self.assertNotEquals(None, transaction.paypal_details.capture_id) #self.assertNotEquals(None, transaction.paypal_details.refund_id) self.assertNotEquals(None, transaction.paypal_details.transaction_fee_amount) self.assertNotEquals(None, transaction.paypal_details.transaction_fee_currency_iso_code) def test_paypal_transaction_refund_already_refunded_transation_fails(self): transaction = self.__create_paypal_transaction() Transaction.refund(transaction.id) result = Transaction.refund(transaction.id) self.assertFalse(result.is_success) self.assertEquals( ErrorCodes.Transaction.HasAlreadyBeenRefunded, result.errors.for_object("transaction").on("base")[0].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.assertEquals( ErrorCodes.Transaction.CannotRefundUnlessSettled, result.errors.for_object("transaction").on("base")[0].code ) def test_europe_bank_account_details(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "altpay_merchant" Configuration.public_key = "altpay_merchant_public_key" Configuration.private_key = "altpay_merchant_private_key" customer_id = Customer.create().customer.id token = TestHelper.generate_decoded_client_token({"customer_id": customer_id, "sepa_mandate_type": EuropeBankAccount.MandateType.Business}) authorization_fingerprint = json.loads(token)["authorizationFingerprint"] config = Configuration.instantiate() client_api = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) nonce = client_api.get_europe_bank_account_nonce({ "locale": "de-DE", "bic": "DEUTDEFF", "iban": "DE89370400440532013000", "accountHolderName": "Baron Von Holder", "billingAddress": {"region": "Hesse", "country_name": "Germany"} }) result = Transaction.sale({ "merchant_account_id": "fake_sepa_ma", "amount": "10.00", "payment_method_nonce": nonce }) self.assertTrue(result.is_success) europe_bank_account_details = result.transaction.europe_bank_account_details self.assertEquals(europe_bank_account_details.bic, "DEUTDEFF") self.assertEquals(europe_bank_account_details.account_holder_name, "Baron Von Holder") self.assertEquals(europe_bank_account_details.masked_iban[-4:], "3000") self.assertNotEquals(europe_bank_account_details.image_url, None) self.assertEquals(PaymentInstrumentType.EuropeBankAccount, result.transaction.payment_instrument_type) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key 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_transaction_facilitator(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, False) result = Transaction.sale({ "payment_method_nonce": grant_result.payment_method_nonce.nonce, "amount": TransactionAmounts.Authorize, }) 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") def test_shared_vault_transaction(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 granting_gateway = BraintreeGateway( access_token = access_token, ) result = granting_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) braintree_python-3.23.0/tests/integration/test_transaction_search.py000066400000000000000000001723301262761311500261350ustar00rootroot00000000000000from 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.assertEquals(0, collection.maximum_size) def test_advanced_search_searches_all_text_fields_at_once(self): first_name = "Tim%s" % randint(1, 100000) token = "creditcard%s" % randint(1, 100000) customer_id = "customer%s" % 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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) def test_advanced_search_search_each_text_field(self): first_name = "Tim%s" % randint(1, 100000) token = "creditcard%s" % randint(1, 100000) customer_id = "customer%s" % 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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, text_node == "invalid" ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(transaction.payment_instrument_type, PaymentInstrumentType.CreditCard) self.assertEquals(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.assertEquals(transaction.payment_instrument_type, PaymentInstrumentType.PayPalAccount) self.assertEquals(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.assertEquals(transaction.payment_instrument_type, PaymentInstrumentType.ApplePayCard) self.assertEquals(transaction.id, collection.first.id) def test_advanced_search_with_payment_instrument_type_is_europe(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "altpay_merchant" Configuration.public_key = "altpay_merchant_public_key" Configuration.private_key = "altpay_merchant_private_key" customer_id = Customer.create().customer.id token = TestHelper.generate_decoded_client_token({"customer_id": customer_id, "sepa_mandate_type": EuropeBankAccount.MandateType.Business}) authorization_fingerprint = json.loads(token)["authorizationFingerprint"] config = Configuration.instantiate() client_api = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) nonce = client_api.get_europe_bank_account_nonce({ "locale": "de-DE", "bic": "DEUTDEFF", "iban": "DE89370400440532013000", "accountHolderName": "Baron Von Holder", "billingAddress": {"region": "Hesse", "country_name": "Germany"} }) transaction = Transaction.sale({ "merchant_account_id": "fake_sepa_ma", "amount": "10.00", "payment_method_nonce": nonce }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == "EuropeBankAccountDetail" ) self.assertEquals(transaction.payment_instrument_type, PaymentInstrumentType.EuropeBankAccount) self.assertEquals(transaction.id, collection.first.id) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key 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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.contains("invalid") ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.starts_with("invalid") ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.ends_with("invalid") ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name != "Jane Shea" ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_using.in_list([Transaction.CreatedUsing.FullInformation, Transaction.CreatedUsing.Token]) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_using == Transaction.CreatedUsing.Token ]) self.assertEquals(0, collection.maximum_size) def test_advanced_search_multiple_value_node_allowed_values_created_using(self): try: collection = Transaction.search([ TransactionSearch.created_using == "noSuchCreatedUsing" ]) self.assertTrue(False) except AttributeError as error: self.assertEquals("Invalid argument(s) for created_using: noSuchCreatedUsing", str(error)) 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.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_customer_location == CreditCard.CustomerLocation.International ]) self.assertEquals(0, collection.maximum_size) def test_advanced_search_multiple_value_node_allowed_values_credit_card_customer_location(self): try: collection = Transaction.search([ TransactionSearch.credit_card_customer_location == "noSuchCreditCardCustomerLocation" ]) self.assertTrue(False) except AttributeError as error: self.assertEquals("Invalid argument(s) for credit_card_customer_location: noSuchCreditCardCustomerLocation", str(error)) 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.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.merchant_account_id == "bogus_merchant_account_id" ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == CreditCard.CardType.AmEx ]) self.assertEquals(0, collection.maximum_size) def test_advanced_search_multiple_value_node_allowed_values_credit_card_card_type(self): try: collection = Transaction.search([ TransactionSearch.credit_card_card_type == "noSuchCreditCardCardType" ]) self.assertTrue(False) except AttributeError as error: self.assertEquals("Invalid argument(s) for credit_card_card_type: noSuchCreditCardCardType", str(error)) 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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.status.in_list([Transaction.Status.Authorized, Transaction.Status.Settled]) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.status == Transaction.Status.Settled ]) self.assertEquals(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): try: collection = Transaction.search([ TransactionSearch.status.in_list(["settlement_confirmed", "settlement_declined"]) ]) except AttributeError as error: self.assertTrue(False) def test_advanced_search_multiple_value_node_allowed_values_status(self): try: collection = Transaction.search([ TransactionSearch.status == "noSuchStatus" ]) self.assertTrue(False) except AttributeError as error: self.assertEquals("Invalid argument(s) for status: noSuchStatus", str(error)) 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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.source.in_list([Transaction.Source.Api, Transaction.Source.ControlPanel]) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.source == Transaction.Source.ControlPanel ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.type.in_list([Transaction.Type.Sale, Transaction.Type.Credit]) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.type == Transaction.Type.Credit ]) self.assertEquals(0, collection.maximum_size) def test_advanced_search_multiple_value_node_allowed_values_type(self): try: collection = Transaction.search([ TransactionSearch.type == "noSuchType" ]) self.assertTrue(False) except AttributeError as error: self.assertEquals("Invalid argument(s) for type: noSuchType", str(error)) def test_advanced_search_multiple_value_node_type_with_refund(self): name = "Anabel Atkins%s" % 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.assertEquals(2, collection.maximum_size) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.type == Transaction.Type.Credit, TransactionSearch.refund == True ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(refund.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.type == Transaction.Type.Credit, TransactionSearch.refund == False ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(credit.id, collection.first.id) def test_advanced_search_range_node_amount(self): name = "Henrietta Livingston%s" % 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.assertEquals(1, collection.maximum_size) self.assertEquals(t_1800.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount <= "1250" ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(t_1000.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.between("1100", "1600") ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at <= now ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at <= future ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at >= now ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at >= future ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(now, future) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(past, future) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(future, future2) ]) self.assertEquals(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) future2 = transaction.created_at + timedelta(minutes=20) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at == past ]) self.assertEquals(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at == now ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at == future ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date <= disbursement_time ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date <= future ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date >= disbursement_time ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date >= future ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(disbursement_time, future) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(past, future) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(future, future2) ]) self.assertEquals(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) future2 = disbursement_time + timedelta(days=20) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date == past ]) self.assertEquals(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date == now ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date == future ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) def test_advanced_search_range_node_disputed_date_less_than_or_equal_to(self): transaction_id = "disputedtransaction" disputed_time = datetime(2014, 3, 1, 0, 0, 0) past = disputed_time - timedelta(minutes=10) future = disputed_time + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date <= past ]) self.assertEquals(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date <= disputed_time ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date <= future ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) def test_advanced_search_range_node_disputed_date_greater_than_or_equal_to(self): transaction_id = "2disputetransaction" disputed_time = datetime(2014, 3, 1, 0, 0, 0) past = disputed_time - timedelta(minutes=10) future = disputed_time + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date >= past ]) self.assertEquals(2, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date >= disputed_time ]) self.assertEquals(2, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date >= future ]) self.assertEquals(1, collection.maximum_size) def test_advanced_search_range_node_disputed_date_between(self): transaction_id = "disputedtransaction" disputed_time = datetime(2014, 3, 1, 0, 0, 0) past = disputed_time - timedelta(days=1) future = disputed_time + timedelta(days=1) future2 = disputed_time + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date.between(past, disputed_time) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date.between(disputed_time, future) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date.between(past, future) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date.between(future, future2) ]) self.assertEquals(0, collection.maximum_size) def test_advanced_search_range_node_disputed_date_is(self): transaction_id = "disputedtransaction" disputed_time = datetime(2014, 3, 1, 0, 0, 0) past = disputed_time - timedelta(days=10) now = disputed_time future = disputed_time + timedelta(days=10) future2 = disputed_time + timedelta(days=20) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date == past ]) self.assertEquals(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date == now ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date == future ]) self.assertEquals(0, collection.maximum_size) def test_advanced_search_range_node_disputed_date_with_dates(self): transaction_id = "disputedtransaction" disputed_date = date(2014, 3, 1) past = disputed_date - timedelta(days=1) future = disputed_date + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.dispute_date.between(past, future) ]) self.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(0, collection.maximum_size) collection = Transaction.search( TransactionSearch.authorization_expired_at.between(yesterday, tomorrow) ) self.assertTrue(collection.maximum_size > 0) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(future, future2) ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.failed_at.between(future, future2) ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.gateway_rejected_at.between(future, future2) ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.processor_declined_at.between(future, future2) ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.settled_at.between(future, future2) ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.submitted_for_settlement_at.between(future, future2) ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.voided_at.between(future, future2) ]) self.assertEquals(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.assertEquals(1, collection.maximum_size) self.assertEquals(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.assertEquals(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(past, future), TransactionSearch.voided_at.between(past, future) ]) self.assertEquals(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.assertEquals(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.assertEquals(status_code, 202) 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.assertEquals(1, collection.maximum_size) self.assertEquals(transaction.id, collection.first.id) def test_advanced_search_can_search_on_sepa_iban(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "altpay_merchant" Configuration.public_key = "altpay_merchant_public_key" Configuration.private_key = "altpay_merchant_private_key" customer_id = Customer.create().customer.id token = TestHelper.generate_decoded_client_token({"customer_id": customer_id, "sepa_mandate_type": EuropeBankAccount.MandateType.Business}) authorization_fingerprint = json.loads(token)["authorizationFingerprint"] config = Configuration.instantiate() client_api = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) nonce = client_api.get_europe_bank_account_nonce({ "locale": "de-DE", "bic": "DEUTDEFF", "iban": "DE89370400440532013000", "accountHolderName": "Baron Von Holder", "billingAddress": {"region": "Hesse", "country_name": "Germany"} }) result = Transaction.sale({ "merchant_account_id": "fake_sepa_ma", "amount": "10.00", "payment_method_nonce": nonce }) collection = Transaction.search([ TransactionSearch.europe_bank_account_iban == "DE89370400440532013000" ]) self.assertTrue(collection.maximum_size >= 1) ids = [transaction.id for transaction in collection.items] self.assertIn(result.transaction.id, ids) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key @raises(DownForMaintenanceError) def test_search_handles_a_search_timeout(self): Transaction.search([ TransactionSearch.amount.between("-1100", "1600") ]) braintree_python-3.23.0/tests/integration/test_transparent_redirect.py000066400000000000000000000172011262761311500265000ustar00rootroot00000000000000from 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.assertEquals(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEquals(Transaction.Type.Sale, transaction.type) self.assertEquals("411111", transaction.credit_card_details.bin) self.assertEquals("1111", transaction.credit_card_details.last_4) self.assertEquals("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.assertEquals(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEquals(Transaction.Type.Credit, transaction.type) self.assertEquals("411111", transaction.credit_card_details.bin) self.assertEquals("1111", transaction.credit_card_details.last_4) self.assertEquals("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.assertEquals("John", customer.first_name) self.assertEquals("Doe", customer.last_name) self.assertEquals("Doe Co", customer.company) self.assertEquals("john@doe.com", customer.email) self.assertEquals("312.555.2323", customer.phone) self.assertEquals("614.555.5656", customer.fax) self.assertEquals("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.assertEquals("Stan", customer.first_name) self.assertEquals("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.assertEquals("411111", credit_card.bin) self.assertEquals("1111", credit_card.last_4) self.assertEquals("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.assertEquals("12/2012", credit_card.expiration_date) braintree_python-3.23.0/tests/test_helper.py000066400000000000000000000303541262761311500212160ustar00rootroot00000000000000import os import random import re import unittest import sys if sys.version_info[0] == 2: from urllib import urlencode, quote_plus from httplib import HTTPConnection else: from urllib.parse import urlencode, quote_plus from http.client import HTTPConnection import warnings import json from braintree import * from braintree.exceptions import * from braintree.util import * from braintree.testing_gateway import * from datetime import date, datetime, timedelta from decimal import Decimal from nose.tools import raises from random import randint from contextlib import contextmanager from base64 import b64decode from braintree.test.nonces import Nonces Configuration.configure( Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) def showwarning(message, category, filename, lineno, file=None, line=None): 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" 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 } @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(list): return set(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"] }) status_code, nonce = client.get_paypal_nonce(paypal_account_details) return nonce @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", } ).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) 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.__http_do("GET", path) def post(self, path, params = None): return self.__http_do("POST", path, params) def put(self, path, params = None): return self.__http_do("PUT", path, params) def __http_do(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_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 get_europe_bank_account_nonce(self, europe_bank_account_params): params = {"sepa_mandate": europe_bank_account_params} url = "/merchants/%s/client_api/v1/sepa_mandates" % self.config.merchant_id if 'authorization_fingerprint' in self.options: params['authorizationFingerprint'] = self.options['authorization_fingerprint'] status_code, response = self.post(url, params) json_body = json.loads(response) mandate_reference_number = json_body["europeBankAccounts"][0]["sepaMandates"][0]["mandateReferenceNumber"] nonce = None if status_code == 201: nonce = json_body["europeBankAccounts"][0]["nonce"] return nonce def __headers(self): return { "Content-type": "application/json", "User-Agent": "Braintree Python " + version.Version, "X-ApiVersion": Configuration.api_version() } braintree_python-3.23.0/tests/unit/000077500000000000000000000000001262761311500173005ustar00rootroot00000000000000braintree_python-3.23.0/tests/unit/__init__.py000066400000000000000000000000001262761311500213770ustar00rootroot00000000000000braintree_python-3.23.0/tests/unit/test_address.py000066400000000000000000000036271262761311500223460ustar00rootroot00000000000000from tests.test_helper import * class TestAddress(unittest.TestCase): def test_create_raise_exception_with_bad_keys(self): try: Address.create({"customer_id": "12345", "bad_key": "value"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_create_raises_error_if_no_customer_id_given(self): try: Address.create({"country_name": "United States of America"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'customer_id must be provided'", str(e)) def test_create_raises_key_error_if_given_invalid_customer_id(self): try: Address.create({"customer_id": "!@#$%"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'customer_id contains invalid characters'", str(e)) def test_update_raise_exception_with_bad_keys(self): try: Address.update("customer_id", "address_id", {"bad_key": "value"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_finding_address_with_empty_customer_id_raises_not_found_exception(self): try: Address.find(" ", "address_id") self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) def test_finding_address_with_none_customer_id_raises_not_found_exception(self): try: Address.find(None, "address_id") self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) def test_finding_address_with_empty_address_id_raises_not_found_exception(self): try: Address.find("customer_id", " ") self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) braintree_python-3.23.0/tests/unit/test_address_details.py000066400000000000000000000011261262761311500240430ustar00rootroot00000000000000from 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 = "" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-3.23.0/tests/unit/test_business_details.py000066400000000000000000000014161262761311500242530ustar00rootroot00000000000000from tests.test_helper import * 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 = "} at \w+>" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-3.23.0/tests/unit/test_client_token.py000066400000000000000000000015731262761311500233750ustar00rootroot00000000000000import json from 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"]: try: client_token = ClientToken.generate({ "options": {option: True} }) self.assertTrue(False, "Should have raised an exception") except InvalidSignatureError as e: self.assertTrue(str(e).find(option)) 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.23.0/tests/unit/test_configuration.py000066400000000000000000000052371262761311500235670ustar00rootroot00000000000000from 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.assertTrue(False) 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_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): 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.assertTrue(isinstance(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.23.0/tests/unit/test_credit_card.py000066400000000000000000000114051262761311500231550ustar00rootroot00000000000000from tests.test_helper import * import datetime import braintree.test.venmo_sdk as venmo_sdk class TestCreditCard(unittest.TestCase): def test_create_raises_exception_with_bad_keys(self): try: CreditCard.create({"bad_key": "value"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_update_raises_exception_with_bad_keys(self): try: CreditCard.update("token", {"bad_key": "value"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_tr_data_for_create_raises_error_with_bad_keys(self): try: CreditCard.tr_data_for_create({"bad_key": "value"}, "http://example.com") self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_tr_data_for_update_raises_error_with_bad_keys(self): try: CreditCard.tr_data_for_update({"bad_key": "value"}, "http://example.com") self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_transparent_redirect_create_url(self): port = os.getenv("GATEWAY_PORT") or "3000" self.assertEquals( "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.assertEquals( "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", "venmo_sdk_session", "fail_on_duplicate_payment_method"]}, "customer_id" ] self.assertEquals(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", "venmo_sdk_session"]} ] self.assertEquals(expected, CreditCard.update_signature()) def test_finding_empty_id_raises_not_found_exception(self): try: CreditCard.find(" ") self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) def test_finding_none_raises_not_found_exception(self): try: CreditCard.find(None) self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) def test_multiple_verifications_sort(self): verification1 = {"created_at": datetime.datetime(2014, 11, 18, 23, 20, 20), "id":123} verification2 = {"created_at": datetime.datetime(2014, 11, 18, 23, 20, 21), "id":456} credit_card = CreditCard(Configuration.gateway(), {"verifications": [verification1, verification2]}) self.assertEquals(credit_card.verification.id, 456) braintree_python-3.23.0/tests/unit/test_credit_card_verification.py000066400000000000000000000012741262761311500257220ustar00rootroot00000000000000from tests.test_helper import * class TestCreditCardVerification(unittest.TestCase): def test_when_risk_data_is_not_included(self): verification = CreditCardVerification(None, {}) self.assertEquals(verification.risk_data, None) def test_finding_empty_id_raises_not_found_exception(self): try: CreditCardVerification.find(" ") self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) def test_finding_none_raises_not_found_exception(self): try: CreditCardVerification.find(None) self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) braintree_python-3.23.0/tests/unit/test_crypto.py000066400000000000000000000015721262761311500222360ustar00rootroot00000000000000from tests.test_helper import * class TestCrypto(unittest.TestCase): def test_sha1_hmac_hash(self): actual = Crypto.sha1_hmac_hash("secretKey", "hello world") self.assertEquals("d503d7a1a6adba1e6474e9ff2c4167f9dfdf4247", actual) def test_sha256_hmac_hash(self): actual = Crypto.sha256_hmac_hash("secret-key", "secret-message") self.assertEquals("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.23.0/tests/unit/test_customer.py000066400000000000000000000055601262761311500225600ustar00rootroot00000000000000from tests.test_helper import * class TestCustomer(unittest.TestCase): def test_create_raise_exception_with_bad_keys(self): try: Customer.create({"bad_key": "value"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_create_raise_exception_with_bad_nested_keys(self): try: Customer.create({"credit_card": {"bad_key": "value"}}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: credit_card[bad_key]'", str(e)) def test_update_raise_exception_with_bad_keys(self): try: Customer.update("id", {"bad_key": "value"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_update_raise_exception_with_bad_nested_keys(self): try: Customer.update("id", {"credit_card": {"bad_key": "value"}}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: credit_card[bad_key]'", str(e)) def test_tr_data_for_create_raises_error_with_bad_keys(self): try: Customer.tr_data_for_create({"bad_key": "value"}, "http://example.com") self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_tr_data_for_update_raises_error_with_bad_keys(self): try: Customer.tr_data_for_update({"bad_key": "value"}, "http://example.com") self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_finding_empty_id_raises_not_found_exception(self): try: Customer.find(" ") self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) def test_finding_none_raises_not_found_exception(self): try: Customer.find(None) self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) def test_initialize_sets_paypal_accounts(self): customer = Customer("gateway", { "paypal_accounts": [ {"token": "token1"}, {"token": "token2"} ] }) self.assertEquals(customer.paypal_accounts[0].token, "token1") self.assertEquals(customer.paypal_accounts[1].token, "token2") def test_initialize_sets_europe_bank_accounts(self): customer = Customer("gateway", { "europe_bank_accounts": [ {"token": "token1"}, {"token": "token2"} ] }) self.assertEquals(customer.europe_bank_accounts[0].token, "token1") self.assertEquals(customer.europe_bank_accounts[1].token, "token2") braintree_python-3.23.0/tests/unit/test_disbursement.py000066400000000000000000000020631262761311500234160ustar00rootroot00000000000000from tests.test_helper import * from datetime import date class TestDisbursement(unittest.TestCase): def test_constructor(self): 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 = Disbursement(None, attributes) self.assertEquals(disbursement.id, "123456") self.assertEquals(disbursement.amount, Decimal("100.00")) self.assertEquals(disbursement.transaction_ids, ["asdf", "qwer"]) self.assertEquals(disbursement.merchant_account.master_merchant_account.id, "master_merchant_account") braintree_python-3.23.0/tests/unit/test_disbursement_detail.py000066400000000000000000000021231262761311500247350ustar00rootroot00000000000000 from tests.test_helper import * from braintree.resource import Resource 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.assertEquals(False, disbursement_details.is_valid) braintree_python-3.23.0/tests/unit/test_dispute.py000066400000000000000000000026301262761311500223670ustar00rootroot00000000000000from tests.test_helper import * from datetime import date from braintree.dispute import Dispute class TestDispute(unittest.TestCase): def test_constructor(self): 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", } dispute = Dispute(attributes) self.assertEquals(dispute.id, "123456") self.assertEquals(dispute.amount, Decimal("100.00")) self.assertEquals(dispute.currency_iso_code, "USD") self.assertEquals(dispute.reason, Dispute.Reason.Fraud) self.assertEquals(dispute.status, Dispute.Status.Open) self.assertEquals(dispute.transaction_details.id, "transaction_id") self.assertEquals(dispute.transaction_details.amount, Decimal("100.00")) self.assertEquals(dispute.date_opened, date(2013, 4, 1)) self.assertEquals(dispute.date_won, date(2013, 4, 2)) self.assertEquals(dispute.kind, Dispute.Kind.Chargeback) braintree_python-3.23.0/tests/unit/test_environment.py000066400000000000000000000044071262761311500232620ustar00rootroot00000000000000from tests.test_helper import * class TestEnvironment(unittest.TestCase): def test_server_and_port_for_development(self): port = os.getenv("GATEWAY_PORT") or "3000" self.assertEquals("localhost:" + port, Environment.Development.server_and_port) def test_base_url(self): self.assertEquals("https://api.sandbox.braintreegateway.com:443", Environment.Sandbox.base_url) self.assertEquals("https://api.braintreegateway.com:443", Environment.Production.base_url) def test_server_and_port_for_sandbox(self): self.assertEquals("api.sandbox.braintreegateway.com:443", Environment.Sandbox.server_and_port) def test_server_and_port_for_production(self): self.assertEquals("api.braintreegateway.com:443", Environment.Production.server_and_port) def test_server_for_development(self): self.assertEquals("localhost", Environment.Development.server) def test_server_for_sandbox(self): self.assertEquals("api.sandbox.braintreegateway.com", Environment.Sandbox.server) def test_server_for_production(self): self.assertEquals("api.braintreegateway.com", Environment.Production.server) def test_port_for_development(self): port = os.getenv("GATEWAY_PORT") or "3000" port = int(port) self.assertEquals(port, Environment.Development.port) def test_port_for_sandbox(self): self.assertEquals(443, Environment.Sandbox.port) def test_port_for_production(self): self.assertEquals(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.assertEquals("http://", Environment.Development.protocol) def test_protocol_for_sandbox(self): self.assertEquals("https://", Environment.Sandbox.protocol) def test_protocol_for_production(self): self.assertEquals("https://", Environment.Production.protocol) def test_ssl_certificate_for_development(self): self.assertEquals(None, Environment.Development.ssl_certificate) braintree_python-3.23.0/tests/unit/test_error_result.py000066400000000000000000000031321262761311500234370ustar00rootroot00000000000000from 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.assertEquals("params", result.params) self.assertEquals(1, result.errors.size) self.assertEquals("something is invalid", result.errors.for_object("scope")[0].message) self.assertEquals("something", result.errors.for_object("scope")[0].attribute) self.assertEquals(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.23.0/tests/unit/test_errors.py000066400000000000000000000042361262761311500222320ustar00rootroot00000000000000from 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.assertEquals(1, errors.for_object("level1").size) self.assertEquals(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.assertEquals(0, errors.for_object("no_errors_here").size) self.assertEquals(0, len(errors.for_object("no_errors_here"))) def test_size_returns_number_of_errors_at_first_level_if_only_one_level_exists(self): hash = { "level1": {"errors": [{"code": "code1", "attribute": "attr", "message": "message"}]} } self.assertEqual(1, Errors(hash).size) self.assertEqual(1, len(Errors(hash))) def test_size_returns_number_of_errors_at_all_levels(self): 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(hash).size) self.assertEqual(3, len(Errors(hash))) def test_deep_errors_returns_all_errors(self): 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(hash).deep_errors self.assertEquals(["code1", "code2", "code3"], [error.code for error in errors]) braintree_python-3.23.0/tests/unit/test_europe_bank_account.py000066400000000000000000000004301262761311500247140ustar00rootroot00000000000000from tests.test_helper import * class TestEuropeBankAccount(unittest.TestCase): def test_mandate_type_constants(self): self.assertEquals("business", EuropeBankAccount.MandateType.Business) self.assertEquals("consumer", EuropeBankAccount.MandateType.Consumer) braintree_python-3.23.0/tests/unit/test_funding_details.py000066400000000000000000000011661262761311500240540ustar00rootroot00000000000000from tests.test_helper import * 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 = "" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-3.23.0/tests/unit/test_http.py000066400000000000000000000022271262761311500216730ustar00rootroot00000000000000import traceback from tests.test_helper import * from braintree.attribute_getter import AttributeGetter class TestHttp(unittest.TestCase): def test_raise_exception_from_status_for_upgrade_required(self): try: Http.raise_exception_from_status(426) self.assertTrue(False) except UpgradeRequiredError: pass 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, "a")._Http__http_do("a", "b") except Error as e: _, _, tb = sys.exc_info() self.assertEqual('raise_error', traceback.extract_tb(tb)[-1][2]) braintree_python-3.23.0/tests/unit/test_individual_details.py000066400000000000000000000014621262761311500245510ustar00rootroot00000000000000from tests.test_helper import * 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 = "} at \w+>" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-3.23.0/tests/unit/test_merchant_account.py000066400000000000000000000055611262761311500242350ustar00rootroot00000000000000from 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.assertEquals(merchant_account.status, "active") self.assertEquals(merchant_account.id, "sub_merchant_account") self.assertEquals(merchant_account.master_merchant_account.id, "master_merchant_account") self.assertEquals(merchant_account.master_merchant_account.status, "active") self.assertEquals(merchant_account.individual_details.first_name, "John") self.assertEquals(merchant_account.individual_details.last_name, "Doe") self.assertEquals(merchant_account.individual_details.email, "john.doe@example.com") self.assertEquals(merchant_account.individual_details.date_of_birth, "1970-01-01") self.assertEquals(merchant_account.individual_details.phone, "3125551234") self.assertEquals(merchant_account.individual_details.ssn_last_4, "6789") self.assertEquals(merchant_account.individual_details.address_details.street_address, "123 Fake St") self.assertEquals(merchant_account.individual_details.address_details.locality, "Chicago") self.assertEquals(merchant_account.individual_details.address_details.region, "IL") self.assertEquals(merchant_account.individual_details.address_details.postal_code, "60622") self.assertEquals(merchant_account.business_details.dba_name, "James's Bloggs") self.assertEquals(merchant_account.business_details.tax_id, "123456789") self.assertEquals(merchant_account.funding_details.account_number_last_4, "8798") self.assertEquals(merchant_account.funding_details.routing_number, "071000013") self.assertEquals(merchant_account.funding_details.descriptor, "Joes Bloggs MI") braintree_python-3.23.0/tests/unit/test_partner_merchant.py000066400000000000000000000015551262761311500242530ustar00rootroot00000000000000from 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.23.0/tests/unit/test_payment_method_gateway.py000066400000000000000000000105031262761311500254460ustar00rootroot00000000000000from tests.test_helper import * from braintree.payment_method_gateway import PaymentMethodGateway class TestPaymentMethodGateway(unittest.TestCase): def test_parse_response_returns_a_credit_card(self): payment_method_gateway = PaymentMethodGateway(BraintreeGateway(None)) credit_card = payment_method_gateway._parse_payment_method({ "credit_card": {"bin": "411111", "last_4": "1111"} }) self.assertEquals(credit_card.__class__, CreditCard) self.assertEquals(credit_card.bin, "411111") self.assertEquals(credit_card.last_4, "1111") def test_parse_response_returns_a_paypal_account(self): payment_method_gateway = PaymentMethodGateway(BraintreeGateway(None)) paypal_account = payment_method_gateway._parse_payment_method({ "paypal_account": {"token": "1234", "default": False} }) self.assertEquals(paypal_account.__class__, PayPalAccount) self.assertEquals(paypal_account.token, "1234") self.assertFalse(paypal_account.default) def test_parse_response_returns_an_unknown_payment_method(self): payment_method_gateway = PaymentMethodGateway(BraintreeGateway(None)) unknown_payment_method = payment_method_gateway._parse_payment_method({ "new_fancy_payment_method": { "token": "1234", "default": True, "other_fancy_thing": "is-shiny" } }) self.assertEquals(unknown_payment_method.__class__, UnknownPaymentMethod) self.assertEquals(unknown_payment_method.token, "1234") self.assertTrue(unknown_payment_method.default) 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", "token", { "billing_address": Address.create_signature()}, { "options": [ "fail_on_duplicate_payment_method", "make_default", "verification_merchant_account_id", "verify_card", ] } ] 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", "verify_card", "verification_merchant_account_id", "venmo_sdk_session" ] }, { "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)) with self.assertRaises(ValueError): payment_method_gateway.grant("", False) with self.assertRaises(ValueError): payment_method_gateway.grant("\t", False) with self.assertRaises(ValueError): payment_method_gateway.grant(None, False) 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) braintree_python-3.23.0/tests/unit/test_resource.py000066400000000000000000000045241262761311500225450ustar00rootroot00000000000000from 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) braintree_python-3.23.0/tests/unit/test_resource_collection.py000066400000000000000000000022141262761311500247520ustar00rootroot00000000000000from 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(query, ids): return [TestResourceCollection.TestResource.items[int(id)] for 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.assertEquals(TestResourceCollection.TestResource.items[index], item) new_items.append(item) index += 1 self.assertEquals(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) braintree_python-3.23.0/tests/unit/test_risk_data.py000066400000000000000000000004741262761311500226570ustar00rootroot00000000000000from tests.test_helper import * from braintree import * class TestRiskData(unittest.TestCase): def test_initialization_of_attributes(self): risk_data = RiskData({"id": "123", "decision": "Unknown"}) self.assertEquals(risk_data.id, "123") self.assertEquals(risk_data.decision, "Unknown") braintree_python-3.23.0/tests/unit/test_search.py000066400000000000000000000130651262761311500221630ustar00rootroot00000000000000from tests.test_helper import * class TestSearch(unittest.TestCase): def test_text_node_is(self): node = Search.TextNodeBuilder("name") self.assertEquals({"is": "value"}, (node == "value").to_param()) def test_text_node_is_not(self): node = Search.TextNodeBuilder("name") self.assertEquals({"is_not": "value"}, (node != "value").to_param()) def test_text_node_starts_with(self): node = Search.TextNodeBuilder("name") self.assertEquals({"starts_with": "value"}, (node.starts_with("value")).to_param()) def test_text_node_ends_with(self): node = Search.TextNodeBuilder("name") self.assertEquals({"ends_with": "value"}, (node.ends_with("value")).to_param()) def test_text_node_contains(self): node = Search.TextNodeBuilder("name") self.assertEquals({"contains": "value"}, (node.contains("value")).to_param()) def test_multiple_value_node_in_list(self): node = Search.MultipleValueNodeBuilder("name") self.assertEquals(["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.assertEquals(["value1", "value2"], (node.in_list("value1", "value2")).to_param()) def test_multiple_value_node_is(self): node = Search.MultipleValueNodeBuilder("name") self.assertEquals(["value1"], (node == "value1").to_param()) def test_multiple_value_node_with_value_in_whitelist(self): node = Search.MultipleValueNodeBuilder("name", ["okay"]) self.assertEquals(["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.assertEquals({"is": "value"}, (node == "value").to_param()) def test_multiple_value_or_text_node_is_not(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEquals({"is_not": "value"}, (node != "value").to_param()) def test_multiple_value_or_text_node_starts_with(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEquals({"starts_with": "value"}, (node.starts_with("value")).to_param()) def test_multiple_value_or_text_node_ends_with(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEquals({"ends_with": "value"}, (node.ends_with("value")).to_param()) def test_multiple_value_or_text_node_contains(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEquals({"contains": "value"}, (node.contains("value")).to_param()) def test_multiple_value_or_text_node_in_list(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEquals(["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.assertEquals(["value1", "value2"], (node.in_list("value1", "value2")).to_param()) def test_multiple_value_or_text_node_is(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEquals({"is": "value1"}, (node == "value1").to_param()) def test_multiple_value_or_text_node_with_value_in_whitelist(self): node = Search.MultipleValueOrTextNodeBuilder("name", ["okay"]) self.assertEquals(["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.assertEquals({"min": "value"}, (node >= "value").to_param()) def test_range_node_min_greater_than_or_equal_to(self): node = Search.RangeNodeBuilder("name") self.assertEquals({"min": "value"}, (node.greater_than_or_equal_to("value")).to_param()) def test_range_node_max_le(self): node = Search.RangeNodeBuilder("name") self.assertEquals({"max": "value"}, (node <= "value").to_param()) def test_range_node_max_less_than_or_equal_to(self): node = Search.RangeNodeBuilder("name") self.assertEquals({"max": "value"}, (node.less_than_or_equal_to("value")).to_param()) def test_range_node_between(self): node = Search.RangeNodeBuilder("name") self.assertEquals({"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.assertEquals({"is": "value"}, (node == "value").to_param()) def test_key_value_node_is_eq(self): node = Search.KeyValueNodeBuilder("name") self.assertEquals(True, (node == True).to_param()) def test_key_value_node_is_equal(self): node = Search.KeyValueNodeBuilder("name") self.assertEquals(True, (node.is_equal(True)).to_param()) def test_key_value_node_is_not_equal(self): node = Search.KeyValueNodeBuilder("name") self.assertEquals(False, (node.is_not_equal(True)).to_param()) def test_key_value_node_is_not_equal(self): node = Search.KeyValueNodeBuilder("name") self.assertEquals(False, (node != True).to_param()) braintree_python-3.23.0/tests/unit/test_setup.py000066400000000000000000000022411262761311500220500ustar00rootroot00000000000000from 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, filenames 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.assertEquals(sorted(packages_from_directories), sorted(packages_from_setup), mismatch_message) braintree_python-3.23.0/tests/unit/test_signature_service.py000066400000000000000000000007061262761311500244350ustar00rootroot00000000000000from 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.assertEquals("foo=bar_signed_with_fake_key|foo=bar", signed) braintree_python-3.23.0/tests/unit/test_subscription.py000066400000000000000000000014521262761311500234370ustar00rootroot00000000000000from tests.test_helper import * class TestSubscription(unittest.TestCase): def test_create_raises_exception_with_bad_keys(self): try: Subscription.create({"bad_key": "value"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_update_raises_exception_with_bad_keys(self): try: Subscription.update("id", {"bad_key": "value"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_finding_empty_id_raises_not_found_exception(self): try: Subscription.find(" ") self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) braintree_python-3.23.0/tests/unit/test_subscription_search.py000066400000000000000000000036221262761311500247650ustar00rootroot00000000000000from tests.test_helper import * class TestSubscriptionSearch(unittest.TestCase): def test_billing_cycles_remaining_is_a_range_node(self): self.assertEquals(Search.RangeNodeBuilder, type(SubscriptionSearch.billing_cycles_remaining)) def test_days_past_due_is_a_range_node(self): self.assertEquals(Search.RangeNodeBuilder, type(SubscriptionSearch.days_past_due)) def test_id_is_a_text_node(self): self.assertEquals(Search.TextNodeBuilder, type(SubscriptionSearch.id)) def test_merchant_account_id_is_a_multiple_value_node(self): self.assertEquals(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.merchant_account_id)) def test_plan_id_is_a_multiple_value_or_text_node(self): self.assertEquals(Search.MultipleValueOrTextNodeBuilder, type(SubscriptionSearch.plan_id)) def test_price_is_a_range_node(self): self.assertEquals(Search.RangeNodeBuilder, type(SubscriptionSearch.price)) def test_status_is_a_multiple_value_node(self): self.assertEquals(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.status)) def test_in_trial_period_is_multiple_value_node(self): self.assertEquals(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.assertEquals(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.ids)) braintree_python-3.23.0/tests/unit/test_successful_result.py000066400000000000000000000004671262761311500244750ustar00rootroot00000000000000from 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.23.0/tests/unit/test_three_d_secure_info.py000066400000000000000000000012351262761311500247050ustar00rootroot00000000000000from 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, }) self.assertEquals("Y", three_d_secure_info.enrolled) self.assertEquals("authenticate_successful", three_d_secure_info.status) self.assertEquals(True, three_d_secure_info.liability_shifted) self.assertEquals(True, three_d_secure_info.liability_shift_possible) braintree_python-3.23.0/tests/unit/test_transaction.py000066400000000000000000000103711262761311500232400ustar00rootroot00000000000000from tests.test_helper import * from datetime import datetime from datetime import date class TestTransaction(unittest.TestCase): def test_clone_transaction_raises_exception_with_bad_keys(self): try: Transaction.clone_transaction("an id", {"bad_key": "value"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_sale_raises_exception_with_bad_keys(self): try: Transaction.sale({"bad_key": "value"}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_sale_raises_exception_with_nested_bad_keys(self): try: Transaction.sale({"credit_card": {"bad_key": "value"}}) self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: credit_card[bad_key]'", str(e)) def test_tr_data_for_sale_raises_error_with_bad_keys(self): try: Transaction.tr_data_for_sale({"bad_key": "value"}, "http://example.com") self.assertTrue(False) except KeyError as e: self.assertEquals("'Invalid keys: bad_key'", str(e)) def test_finding_empty_id_raises_not_found_exception(self): try: Transaction.find(" ") self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) def test_finding_none_raises_not_found_exception(self): try: Transaction.find(None) self.assertTrue(False) except NotFoundError as e: self.assertTrue(True) 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.assertEquals(transaction.disbursement_details.settlement_amount, Decimal('27.00')) self.assertEquals(transaction.disbursement_details.settlement_currency_iso_code, 'USD') self.assertEquals(transaction.disbursement_details.settlement_currency_exchange_rate, Decimal('1')) self.assertEquals(transaction.disbursement_details.disbursement_date, date(2013, 4, 10)) self.assertEquals(transaction.disbursement_details.funds_held, False) self.assertEquals(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.assertEquals(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.assertEquals(transaction.is_disbursed, False) braintree_python-3.23.0/tests/unit/test_transparent_redirect.py000066400000000000000000000052601262761311500251360ustar00rootroot00000000000000from 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): hash, content = data.split("|", 1) self.assertEquals(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=4" in data) braintree_python-3.23.0/tests/unit/test_unknown_payment_method.py000066400000000000000000000005141262761311500255050ustar00rootroot00000000000000from tests.test_helper import * class TestUnknownPaymentMethod(unittest.TestCase): def test_image_url(self): unknown_payment_method = UnknownPaymentMethod("gateway", {"token": "TOKEN"}) self.assertEquals("https://assets.braintreegateway.com/payment_method_logo/unknown.png", unknown_payment_method.image_url()) braintree_python-3.23.0/tests/unit/test_validation_error_collection.py000066400000000000000000000117531262761311500264760ustar00rootroot00000000000000from tests.test_helper import * class TestValidationErrorCollection(unittest.TestCase): def test_it_builds_an_array_of_errors_given_an_array_of_hashes(self): hash = {"errors": [{"attribute": "some model attribute", "code": 1, "message": "bad juju"}]} errors = ValidationErrorCollection(hash) error = errors[0] self.assertEquals("some model attribute", error.attribute) self.assertEquals(1, error.code) self.assertEquals("bad juju", error.message) def test_for_object_provides_access_to_nested_attributes(self): hash = { "errors": [{"attribute": "some model attribute", "code": 1, "message": "bad juju"}], "nested": { "errors": [{"attribute": "number", "code": 2, "message": "badder juju"}] } } errors = ValidationErrorCollection(hash) error = errors.for_object("nested").on("number")[0] self.assertEquals("number", error.attribute) self.assertEquals(2, error.code) self.assertEquals("badder juju", error.message) def test_deep_size_non_nested(self): 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.assertEquals(3, ValidationErrorCollection(hash).deep_size) def test_deep_size_nested(self): hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}] } } self.assertEquals(2, ValidationErrorCollection(hash).deep_size) def test_deep_size_multiple_nestings(self): 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.assertEquals(4, ValidationErrorCollection(hash).deep_size) def test_len_multiple_nestings(self): 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(hash) self.assertEquals(1, len(validation_error_collection)) self.assertEquals(1, len(validation_error_collection.for_object("nested"))) self.assertEquals(2, len(validation_error_collection.for_object("nested").for_object("nested_again"))) def test_deep_errors(self): 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(hash) self.assertEquals([1, 2, 3, 4], [error.code for error in validation_error_collection.deep_errors]) def test_errors(self): 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(hash) self.assertEquals([1], [error.code for error in validation_error_collection.errors]) self.assertEquals([2], [error.code for error in validation_error_collection.for_object("nested").errors]) self.assertEquals([3,4], [error.code for error in validation_error_collection.for_object("nested").for_object("nested_again").errors]) braintree_python-3.23.0/tests/unit/test_webhooks.py000066400000000000000000000340771262761311500225450ustar00rootroot00000000000000from tests.test_helper import * from braintree.dispute import Dispute 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.assertEquals(WebhookNotification.Kind.SubscriptionWentPastDue, notification.kind) self.assertEquals("my_id", notification.subscription.id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) @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.assertEquals("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.assertEquals("signature does not match payload - one has been modified", str(e)) else: self.assertFalse("raises exception") def test_invalid_signature_when_contains_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.assertEquals("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.assertNotEquals("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.assertEquals(WebhookNotification.Kind.SubscriptionWentPastDue, notification.kind) self.assertEquals("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.assertEquals("integration_public_key|d9b899556c966b3f06945ec21311865d35df3ce4", response) def test_verify_raises_when_challenge_is_invalid(self): try: WebhookNotification.verify("bad challenge") except InvalidChallengeError as e: self.assertEquals("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.assertEquals(WebhookNotification.Kind.SubMerchantAccountApproved, notification.kind) self.assertEquals("my_id", notification.merchant_account.id) self.assertEquals(MerchantAccount.Status.Active, notification.merchant_account.status) self.assertEquals("master_ma_for_my_id", notification.merchant_account.master_merchant_account.id) self.assertEquals(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.assertEquals(WebhookNotification.Kind.SubMerchantAccountDeclined, notification.kind) self.assertEquals("my_id", notification.merchant_account.id) self.assertEquals(MerchantAccount.Status.Suspended, notification.merchant_account.status) self.assertEquals("master_ma_for_my_id", notification.merchant_account.master_merchant_account.id) self.assertEquals(MerchantAccount.Status.Suspended, notification.merchant_account.master_merchant_account.status) self.assertEquals("Credit score is too low", notification.message) self.assertEquals(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.assertEquals(WebhookNotification.Kind.TransactionDisbursed, notification.kind) self.assertEquals("my_id", notification.transaction.id) self.assertEquals(100, notification.transaction.amount) self.assertEquals(datetime(2013, 7, 9, 18, 23, 29), notification.transaction.disbursement_details.disbursement_date) 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.assertEquals(WebhookNotification.Kind.Disbursement, notification.kind) self.assertEquals("my_id", notification.disbursement.id) self.assertEquals(100, notification.disbursement.amount) self.assertEquals(None, notification.disbursement.exception_message) self.assertEquals(None, notification.disbursement.follow_up_action) self.assertEquals(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.assertEquals(WebhookNotification.Kind.DisbursementException, notification.kind) self.assertEquals("my_id", notification.disbursement.id) self.assertEquals(100, notification.disbursement.amount) self.assertEquals("bank_rejected", notification.disbursement.exception_message) self.assertEquals("update_funding_information", notification.disbursement.follow_up_action) self.assertEquals(date(2014, 2, 9), notification.disbursement.disbursement_date) def test_builds_notification_for_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.assertEquals(WebhookNotification.Kind.DisputeOpened, notification.kind) self.assertEquals("my_id", notification.dispute.id) self.assertEquals(Dispute.Status.Open, notification.dispute.status) self.assertEquals(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEquals(notification.dispute.date_opened, date(2014, 3, 28)) def test_builds_notification_for_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.assertEquals(WebhookNotification.Kind.DisputeLost, notification.kind) self.assertEquals("my_id", notification.dispute.id) self.assertEquals(Dispute.Status.Lost, notification.dispute.status) self.assertEquals(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEquals(notification.dispute.date_opened, date(2014, 3, 28)) def test_builds_notification_for_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.assertEquals(WebhookNotification.Kind.DisputeWon, notification.kind) self.assertEquals("my_id", notification.dispute.id) self.assertEquals(Dispute.Status.Won, notification.dispute.status) self.assertEquals(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEquals(notification.dispute.date_opened, date(2014, 3, 28)) self.assertEquals(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.assertEquals(WebhookNotification.Kind.PartnerMerchantConnected, notification.kind) self.assertEquals("abc123", notification.partner_merchant.partner_merchant_id) self.assertEquals("public_key", notification.partner_merchant.public_key) self.assertEquals("private_key", notification.partner_merchant.private_key) self.assertEquals("public_id", notification.partner_merchant.merchant_public_id) self.assertEquals("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.assertEquals(WebhookNotification.Kind.PartnerMerchantDisconnected, notification.kind) self.assertEquals("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.assertEquals(WebhookNotification.Kind.PartnerMerchantDeclined, notification.kind) self.assertEquals("abc123", notification.partner_merchant.partner_merchant_id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) 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.assertEquals(WebhookNotification.Kind.SubscriptionChargedSuccessfully, notification.kind) self.assertEquals("my_id", notification.subscription.id) self.assertTrue(len(notification.subscription.transactions) == 1) transaction = notification.subscription.transactions.pop() self.assertEquals("submitted_for_settlement", transaction.status) self.assertEquals(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.assertEquals(WebhookNotification.Kind.Check, notification.kind) braintree_python-3.23.0/tests/unit/test_xml_util.py000066400000000000000000000135331262761311500225530ustar00rootroot00000000000000from 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): dict = {"kva&lue", XmlUtil.xml_from_dict(dict)) def test_xml_from_dict_simple(self): dict = {"a": "b"} self.assertEqual(dict, self.__xml_and_back(dict)) def test_xml_from_dict_with_integer(self): dict = {"a": 1} self.assertEqual('1', XmlUtil.xml_from_dict(dict)) def test_xml_from_dict_with_long(self): dict = {"a": 12341234123412341234} self.assertEqual('12341234123412341234', XmlUtil.xml_from_dict(dict)) def test_xml_from_dict_with_boolean(self): dict = {"a": True} self.assertEqual(dict, self.__xml_and_back(dict)) def test_xml_from_dict_simple_xml_and_back_twice(self): dict = {"a": "b"} self.assertEqual(dict, self.__xml_and_back(self.__xml_and_back(dict))) def test_xml_from_dict_nested(self): dict = {"container": {"item": "val"}} self.assertEqual(dict, self.__xml_and_back(dict)) def test_xml_from_dict_with_array(self): dict = {"container": {"elements": ["val1", "val2", "val3"]}} self.assertEqual(dict, self.__xml_and_back(dict)) def test_xml_from_dict_with_array_of_hashes(self): dict = {"container": {"elements": [{"val": "val1"}, {"val": "val2"}, {"val": "val3"}]}} self.assertEqual(dict, self.__xml_and_back(dict)) def test_xml_from_dict_retains_underscores(self): dict = {"container": {"my_element": "val"}} self.assertEqual(dict, self.__xml_and_back(dict)) def test_xml_from_dict_escapes_special_chars(self): dict = {"container": {"element": "<&>'\""}} self.assertEqual(dict, self.__xml_and_back(dict)) def test_xml_from_dict_with_datetime(self): dict = {"a": datetime(2010, 1, 2, 3, 4, 5)} self.assertEqual(dict, self.__xml_and_back(dict)) def test_xml_from_dict_with_unicode_characters(self): dict = {"a": u"\u1f61hat?"} self.assertEqual('ὡhat?', XmlUtil.xml_from_dict(dict)) def test_xml_from_dict_with_dates_formats_as_datetime(self): dict = {"a": date(2010, 1, 2)} self.assertEqual('2010-01-02T00:00:00Z', XmlUtil.xml_from_dict(dict)) def __xml_and_back(self, dict): return XmlUtil.dict_from_xml(XmlUtil.xml_from_dict(dict)) braintree_python-3.23.0/tests/unit/util/000077500000000000000000000000001262761311500202555ustar00rootroot00000000000000braintree_python-3.23.0/tests/unit/util/__init__.py000066400000000000000000000000001262761311500223540ustar00rootroot00000000000000braintree_python-3.23.0/tests/unit/util/test_constants.py000066400000000000000000000004271262761311500237050ustar00rootroot00000000000000from tests.test_helper import * class TestConstants(unittest.TestCase): def test_get_all_constant_values_from_class(self): self.assertEquals(["Active", "Canceled", "Expired", "Past Due", "Pending"], Constants.get_all_constant_values_from_class(Subscription.Status))