pax_global_header00006660000000000000000000000064147102134350014512gustar00rootroot0000000000000052 comment=6aa90054128542b22d7b449b76fea52c4405c128 braintree_python-4.31.0/000077500000000000000000000000001471021343500151535ustar00rootroot00000000000000braintree_python-4.31.0/.github/000077500000000000000000000000001471021343500165135ustar00rootroot00000000000000braintree_python-4.31.0/.github/CODEOWNERS000066400000000000000000000000441471021343500201040ustar00rootroot00000000000000* @PayPal-Braintree/team-sdk-server braintree_python-4.31.0/.github/ISSUE_TEMPLATE.md000066400000000000000000000013261471021343500212220ustar00rootroot00000000000000 ### General information * SDK/Library version: * Environment: * Language, language version, and OS: ### Issue description braintree_python-4.31.0/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000013161471021343500223150ustar00rootroot00000000000000# Summary # Checklist - [ ] Added changelog entry - [ ] I alphabetized all attributes, parameters, and methods by name in any class file I changed - [ ] Ran unit tests (`python3 -m unittest discover tests/unit`) - [ ] I have linked the JIRA ticket in the summary section - [ ] I have reviewed the JIRA ticket to ensure all AC's are met - [ ] I understand that unless this is a Draft PR or has a DO NOT MERGE label, this PR is considered to be in a deploy ready state and can be deployed if merged to main braintree_python-4.31.0/.gitignore000066400000000000000000000000721471021343500171420ustar00rootroot00000000000000*.pyc /dist /docs/_build /tags MANIFEST build /venv .idea braintree_python-4.31.0/.pylintrc000066400000000000000000000162421471021343500170250ustar00rootroot00000000000000[MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Profiled execution. profile=no # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Pickle collected data for later comparisons. persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= [MESSAGES CONTROL] # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time. #enable= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). disable=C0111,C0103,C0301,E1101,E1103,R0903,R0904,W0401,W0614 [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html output-format=text # Include message's id in output include-ids=no # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells whether to display a full report or only the messages reports=yes # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Add a comment according to your evaluation note. This is used by the global # evaluation report (RP0004). comment=no [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). ignored-classes=SQLObject # When zope mode is activated, add a predefined set of Zope acquired attributes # to generated-members. zope=no # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E0201 when accessed. Python regular # expressions are accepted. generated-members=REQUEST,acl_users,aq_parent [BASIC] # Required attributes for module, separated by a comma required-attributes= # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter,apply,input # Regular expression which should only match correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression which should only match correct module level names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression which should only match correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Regular expression which should only match correct function names function-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct method names method-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct instance attribute names attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct variable names variable-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct list comprehension / # generator expression variable names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Regular expression which should only match functions or classes name which do # not require a docstring no-docstring-rgx=__.*__ [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the beginning of the name of dummy variables # (i.e. not used). dummy-variables-rgx=_|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= [FORMAT] # Maximum number of characters on a single line. max-line-length=80 # Maximum number of lines in a module max-module-lines=1000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' [DESIGN] # Maximum number of arguments for function / method max-args=5 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=15 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branchs=12 # Maximum number of statements in function / method body max-statements=50 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Minimum number of public methods for a class (see R0903). min-public-methods=2 # Maximum number of public methods for a class (see R0904). max-public-methods=20 [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=regsub,string,TERMIOS,Bastion,rexec # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= [CLASSES] # List of interface methods to ignore, separated by a comma. This is used for # instance to not check methods defines in Zope's Interface base class. ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception braintree_python-4.31.0/.readthedocs.yaml000066400000000000000000000001111471021343500203730ustar00rootroot00000000000000version: 2 python: install: - requirements: docs/requirements.txt braintree_python-4.31.0/ACKNOWLEDGEMENTS.md000066400000000000000000000002621471021343500200270ustar00rootroot00000000000000Acknowledgements ---------------- The Braintree SDK uses code from the following libraries: * [requests](https://github.com/kennethreitz/requests), Apache License, Version 2.0 braintree_python-4.31.0/CHANGELOG.md000066400000000000000000000766721471021343500170060ustar00rootroot00000000000000# Changelog ## 4.31.0 * Add `fail_on_duplicate_payment_method_for_customer` option to * `ClientToken` * `PaymentMethod` * `CreditCard` * Add `blik_aliases` to LocalPaymentCompleted webhook and LocalPaymentDetail * Deprecate `samsung_pay_card` * Updated expiring pinned vendor SSL certificates ## 4.30.0 * Add `payer_name`, `bic` and `iban_last_chars` to LocalPaymentCompleted webhook * Add `edit_paypal_vault_id` to PayPalAccount * Add `ani_first_name_response_code` and `ani_last_name_response_code` to CreditCardVerification * Add `shippingTaxAmount` to Transaction * Add `network_tokenization_attributes` parameter to `Transaction.sale` * Add validation error code `NetworkTokenizationAttributeCryptogramIsRequired` to `CreditCard` ## 4.29.0 * Add `foreign_retailer` to Transaction * Add `international_phone` to `Address` and `Customer` * Add `funding_source_description` to PayPalAccount * Add missing `AndroidPayCard` error code * Add `REFUND_FAILED` to `WebhookNotification.Kind` * Add `final_capture` to Transaction `submit_for_partial_settlement_signature` * Deprecate `paypal_tracking_id` in favor of `paypal_tracker_id` in `package_details` ## 4.28.0 * Add `domains` parameter support to `ClientToken.generate` ## 4.27.0 * Add `UnderReview` status to `Dispute` * Add `DisputeUnderReview` to `WebhookNotification.Kind` ## 4.26.0 * Remove usage of standard library deprecated `cgi` module. _Note: this will break integrations on versions of Python below 3.2. However, this is NOT a breaking change to this library, due to our current support of Python 3.5+._ * Add `PackageDetails` class. * Add `packages` to `Transaction` attributes. * Add `package_tracking` method to `TransactionGateway` to make request to add tracking information to transactions. * Add `process_debit_as_credit` to `credit_card` field in `options` field during Transaction create. * Deprecate `three_d_secure_token` in favor of `three_d_secure_authentication_id` * Add `upc_code`, `upc_type`, and `image_url` to `line_items` in `transaction` * Deprecate `venmo_sdk_session` and `venmo_sdk_payment_method_code` ## 4.25.0 * Add `PickupInStore` to `ShippingMethod` enum * Add `external_vault` and `risk_data` to `CreditCardVerification.create` request * Add `phone_number` in `CreditCard` * Add `debit_network` to `Transaction` field * Add `debit_network` to `TransactionSearch` Request * Add `DebitNetwork` enum to `CreditCard` ## 4.24.0 * Add `SubscriptionBillingSkipped` to `WebhookNotification.Kind` * Add `arrivalDate` and `ticketIssuerAddress` to `Transaction.sale` request and `industry` data support for Transaction.submitForSettlement * Add `date_of_birth` and `country_code` to IndustryData params * Add `MetaCheckoutCard`, `MetaCheckoutToken` payment methods * Add `MetaCheckoutCardDetails`, `MetaCheckoutTokenDetails` to `Transaction` * Add `verification_add_ons` to `PaymentMethod` create options for `ACH NetworkCheck` * Fix unittest compatibility with Python 3.12 (Thanks @mgorny) ## 4.23.0 * Deprecate `evidenceSubmittable` in Dispute * Add missing `escape` calls in `generator` for: * list * bool * integer * datetime ## 4.22.0 * Add `processing_overrides` to `Transaction.sale` options ## 4.21.0 * Add `evidence_submittable` to `Dispute` * Add `merchant_token_identifier` and `source_card_last4` to `ApplePayCard` * Add a check for empty month and year before generating `expiration_date` in: * `CrediCard` * `AndroidPayCard` * `ApplePayCard` * `SamsungPayCard` * `VisaCheckoutCard` * Add `retry_ids` and `retried_transaction_id` to Transaction object ## 4.20.0 * Add `merchant_advice_code` and `merchant_advice_code_text` to Transaction object * Allow vaulting of raw AndroidPayCards with billing address via Customer.create/update ## 4.19.0 * Add `intended_transaction_source` to `CreditCardVerification` * Add `three_d_secure_pass_thru` to `CreditCardVerification` * Add `payment_method_nonce` to `CreditCardVerification` * Add `three_d_secure_authentication_id` to `CreditCardVerification` * Add support for subscriptions in SEPA direct debit accounts ## 4.18.1 * Fixup issue where request sessions weren't including proxy settings (see [#5677](https://github.com/psf/requests/issues/5677) for details). ## 4.18.0 * Replace nose usage for tests with unittest (Thanks @arthurzam) * Remove mock dev dependency (Thanks @arthurzam) * Add `ExcessiveRetry` to `GatewayRejectionReason` * Add `pre_dispute_program` to `Dispute` and `DisputeSearch` * Add `AutoAccepted` status to `Dispute` * Add `DisputeAutoAccepted` to `WebhookNotification.Kind` * Deprecate `chargeback_protection_level` and add `protection_level` to `Dispute` and `DisputeSearch` * Add `shipping` object to `submit_for_settlement_signature` * Add `SEPADirectDebitAccount` payment method * Add `SEPADirectDebitAccount` to transaction object * Add `SEPA_DIRECT_DEBIT_ACCOUNT` to `PaymentInstrumentType` * Add `sepa_debit_paypal_v2_order_id` to `TransactionSearch` * Add `sepa_direct_debit_accounts` to `Customer` * Add SEPA Direct Debit specific error codes ## 4.17.1 * Prepare http request before setting url to resolve issue where dot segments get normalized ## 4.17.0 * Fix `DeprecationWarning` on invalid escape sequences (thanks @DavidCain) * Add validation for arguments in Address.delete, Address.find, and Address.update ## 4.16.0 * Add `LiabilityShift` class and `liability_shift` to RiskData * Add ExchangeRateQuote API * Add `ach_return_responses_created_at` and `reason_code` fields in TransactionSearch * Allow vaulting of raw ApplePayCards with billing address via Customer.create/update ## 4.15.2 * Add `retried` to `Transaction` ## 4.14.0 * Add `PaymentMethodCustomerDataUpdated` webhook ## 4.13.0 * Add plan create/update/find API endpoint * Add `TransactionReview` webhook notification * Fix typos (@timgates42) ## 4.12.0 * Add `localPaymentFunded` and `localPaymentExpired` webhooks ## 4.11.0 * Add `exchange_rate_quote_id` to `Transaction.sale` * Add validation error code `ExchangeRateQuoteIdIsTooLong` to `Transaction` * Add the following fields to `ApplePayCard` and `AndroidPayCard`: * `commercial` * `debit` * `durbin_regulated` * `healthcare` * `payroll` * `prepaid` * `product_id` * `country_of_issuance` * `issuing_bank` * Add error code `Transaction.TaxAmountIsRequiredForAibSwedish` for attribute `tax_amount` to handle validation for AIB:Domestic Transactions in Sweden ## 4.10.0 * Add `payment_reader_card_details` parameter to `Transaction.sale` * Add webhook sample for `GrantedPaymentMethodRevoked` * Add `chargeback_protection_level` to `DisputeSearch` * Add `skip_advanced_fraud_checking` to: * `PaymentMethod.create` and `PaymentMethod.update` * `CreditCard.create` and `CreditCard.update` ## 4.9.0 * Add `paypal_messages` to `Dispute` * Add `tax_identifiers` parameter to `Customer.create` and `Customer.update` ## 4.8.0 * Add `LocalPaymentReversed` webhook * Add `store_id` and `store_ids` to `Transaction.search` ## 4.7.0 * Add `merchant_account_id` to `Transaction.refund` * Add `Transaction.adjust_authorization` method to support for multiple authorizations for a single transaction ## 4.6.0 * Add `installments` to `Transaction` requests * Add `count` to `installments` * Deprecate `device_session_id` and `fraud_merchant_id` in `CreditCardGateway`, `CustomerGateway`, `PaymentMethodGateway`, and `TransactionGateway` classes * Add `sca_exemption` to Transaction.sale request ## 4.5.0 * Add `acquirer_reference_number` to `Transaction` * Deprecate `recurring` in Transaction sale requests ## 4.4.0 * Deprecate `masterpass_card` and `amex_checkout_card` payment methods * Fix issue where `transaction.credit` could not be called using a gateway object ## 4.3.0 * Add validation error code `Transaction.ProductSkuIsInvalid` * Add 'RiskThreshold' gateway rejection reason * Add `processed_with_network_token` to `Transaction` * Add `is_network_tokenized` to `CreditCard` ## 4.2.0 * Add `retrieval_reference_number` to `Transaction` * Add `network_transaction_id` to `CreditCardVerification` * Add `product_sku` to `Transaction` * Add `customer_device_id`, `customer_location_zip`, and `customer_tenure` to `RiskData` * Add `phone_number` and `shipping_method` to `Address` * Add validation error codes: * `Transaction.ShippingMethodIsInvalid` * `Transaction.ShippingPhoneNumberIsInvalid` * `Transaction.BillingPhoneNumberIsInvalid` * `RiskData.CustomerBrowserIsTooLong` * `RiskData.CustomerDeviceIdIsTooLong` * `RiskData.CustomerLocationZipInvalidCharacters` * `RiskData.CustomerLocationZipIsInvalid` * `RiskData.CustomerLocationZipIsTooLong` * `RiskData.CustomerTenureIsTooLong` ## 4.1.0 * Add `DisputeAccepted`, `DisputeDisputed`, and `DisputeExpired` webhook constants * Add `three_d_secure_pass_thru` to `CreditCard.create`, `CreditCard.update`, `PaymentMethod.create`, `PaymentMethod.update`, `Customer.create`, and `Customer.update`. * Add `Verification` validation errors for 3D Secure * Add `payment_method_token` to `CreditCardVerificationSearch` * Add `recurring_customer_consent` and `recurring_max_amount` to `authentication_insight_options` for `PaymentMethodNonce.create` * Add `FileIsEmpty` error code * Eliminates usage of mutable objects for function parameters. Resolves #113 Thank you @maneeshd! ## 4.0.0 * Split development and deployments requirements files out * Add `Authentication Insight` to payment method nonce create * Add ThreeDSecure test payment method nonces * Add test `AuthenticationId`s * Add `three_d_secure_authentication_id` to `three_d_secure_info` * Add `three_d_secure_authentication_id` support for transaction sale * Breaking Changes * Require Python 3.5+ * Remove deprecated Transparent Redirect * Remove deprecated iDeal payment method * Apple Pay register_domains returns an ApplePayOptions object * Remove `unrecognized` status from Transaction, Subscription, and CreditCardVerification * Remove `GrantedPaymentInstrumentUpdate` kind from Webhook * Remove Coinbase references * Add GatewayTimeoutError, RequestTimeoutError exceptions * Rename DownForMaintenanceError exception to ServiceUnavailableError * Transaction `line_items` only returns the line items for a transaction response object. Use TransactionLineItem `find_all` to search all line items on a transaction, given a transaction_id * Upgrade API version to retrieve declined refund transactions * Remove all deprecated parameters, errors, and methods ## 3.59.0 * Add `RefundAuthHardDeclined` and `RefundAuthSoftDeclined` to validation errors * Fix issue where managing Apple Pay domains would fail in Python 3.8+ * Add level 2 processing options `purchase_order_number`, `tax_amount`, and `tax_exempt` to `Transaction.submit_for_settlement` * Add level 3 processing options `discount_amount`, `shipping_amount`, `ships_from_postal_code`, `line_items` to `Transaction.submit_for_settlement` ## 3.58.0 * Add support for managing Apple Pay domains (thanks @ethier #117) * Fix error when running against Python 3.8 (thanks @felixonmars #114) * Add `ProcessorDoesNotSupportMotoForCardType` to validation errors * Add Graphql ID to `CreditCardVerification`, `Customer`, `Dispute`, and `Transaction` ## 3.57.1 * Set correct version for PyPi ## 3.57.0 * Forward `processor_comments` to `forwarded_comments` * Add Venmo 'TokenIssuance' gateway rejection reason * Add `AmountNotSupportedByProcessor` to validation error ## 3.56.0 * Add PayPalHere details * Add `networkResponseCode` and `networkResponseText` to transactions and verifications * Add `cavv`, `xid`, `ds_transaction_id`, `eci_flag`, and `three_d_secure_version`, to `three_d_secure_info` * Add `three_d_secure_info` to credit_card_verification * Add `GraphQLClient` to `BraintreeGateway` class ## 3.55.0 * Add `captureId` field to local_payment_details * Add `refundId` field to local_payment_details * Add `debugId` field to local_payment_details * Add `transactionFeeAmount` field to local_payment_details * Add `transactionFeeCurrencyIsoCode` field to local_payment_details * Add `refundFromTransactionFeeAmount` field to local_payment_details * Add `refundFromTransactionFeeCurrencyIsoCode` field to local_payment_details * Add `ds_transaction_id` and `three_d_secure_version` to 3DS pass thru fields * Add `payer_info` field to payment_method_nonce details * Add more specific timeout errors: (#105 thanks @bhargavrpatel) * Add `braintree.exceptions.http.timeout_error.ConnectTimeoutError` (child class of TimeoutError) * Add `braintree.exceptions.http.timeout_error.ReadTimeoutError` (child class of TimeoutError) * Add `room_tax` support for transaction sale * Add `no_show` support for transaction sale * Add `advanced_deposit` support for transaction sale * Add `fire_safe` support for transaction sale * Add `property_phone` support for transaction sale * Add `additional_charges` support for transaction sale * Add `PostalCodeIsRequiredForCardBrandAndProcessor` to validation errors * Fix issue where not found error could choke on `None` values (#109) ## 3.54.0 * Add `payment_method_nonce` field to `LocalPaymentCompleted` webhook * Add `transaction` field to `LocalPaymentCompleted` webhook * Add `LocalPaymentDetails` to transactions ## 3.53.0 * Add `refund_from_transaction_fee_amount` field to paypal_details * Add `refund_from_transaction_fee_currency_iso_code` field to paypal_details * Add `revoked_at` field to paypal_account * Add support for `PaymentMethodRevokedByCustomer` webhook ## 3.52.0 * Deprecate `GrantedPaymentInstrumentUpdate` and add `GrantorUpdatedGrantedPaymentMethod` and `RecipientUpdatedGrantedPaymentMethod` * Add account_type support for transaction sale, verification, and payment_method create/update ## 3.51.0 * Add Hiper card type support * Add Hipercard card type support * Add `bin` to `PaymentMethodNonceDetails` * Clarify support for Python versions 3.6.x and 3.7.x * Add Error indicating pdf uploads too long for dispute evidence. * Add `GrantedPaymentMethodRevoked` webhook response objects ## 3.50.0 * Add `fraud_service_provider` field to `risk_data` * Add `authorization_expires_at` to `Transaction` * Remove invalid transaction tests * Allow PayPal payment ID and payer ID to be passed during transaction create * Add `travel_flight` support to industry-specific data * Add `processor_response_type` to `Transaction`, `AuthorizationAdjustment`, and `CreditCardVerification`. ## 3.49.0 * Add new field `network_transaction_id` in transaction response. * Add `external_vault` option to transaction sale. * Add `LocalPaymentCompleted` webhook. * Add `processor_response_type` to `Transaction`, `AuthorizationAdjustment`, and `CreditCardVerification`. ## 3.48.0 * Add ID to Transaction in SubscriptionChargedSuccessfully test webhook (#99, thanks @bjackson) * Fix dispute results in transactions not showing the correct status sometimes * Add Elo card type support ## 3.47.0 * Add processor respone code and processor response text to authorization adjustments subfield in transaction response. * Add support for Samsung Pay ## 3.46.0 * Allow payee ID to be passed in options params for transaction create * Add `merchant_id` alias to ConnectedMerchantStatusTransitioned and ConnectedMerchantPayPalStatusChanged Auth webhooks ## 3.45.0 * Add support for US Bank Account verifications API ## 3.44.0 * Add Dispute error ValidEvidenceRequiredToFinalize ## 3.43.0 * Add `oauth_access_revocation` to `WebhookNotification`s * Add support for `customer_id`, `disbursement_date` and `history_event_effective_date` in DisputeSearch * Remove `sepa_mandate_type` and `sepa_mandate_acceptance_location` params from `ClientToken` * Add support for VCR compelling evidence dispute representment ## 3.42.0 * Add support for `association_filter_id` in `Customer#find` ## 3.41.0 * Deprecated `LineItem/DiscountAmountMustBeGreaterThanZero` error in favor of `DiscountAmountCannotBeNegative` * Deprecated `LineItem/UnitTaxAmountMustBeGreaterThanZero` error in favor of `UnitTaxAmountCannotBeNegative` * Add support for `tax_amount` field on transaction `line_items` * Add support for `source_merchant_id` on webhooks * Add `find_all` static method to `TransactionLineItem` class * Add support for `profile_id` in Transaction#create options for VenmoAccounts ## 3.40.0 * Add level 3 fields to Transactions: * discount_amount * shipping_amount * ships_from_postal_code * Add support for transaction line items * Add support for tagged evidence in DisputeGateway#add_text_evidence (Beta release) * Update https certificate bundle ## 3.39.1 * Fix spec to expect PayPal transactions to move to settling rather than settled * Fix AchMandate.acceptedAt attribute parsing * Fix regression for `http_strategy.http_do` ## 3.39.0 * Add support for upgrading a PayPal future payment refresh token to a billing agreement * Fix braintree.Dispute.search to take a list of search criteria * Add logic to remove deprecation warnings for encodestring and decodestring when used with python 3 (#92) * Fix spec to expect PayPal transaction to settle immediately after successful capture * Add GrantedPaymentInstrumentUpdate webhook support * Add ability to create a transaction from a shared nonce * Add `options` -> `paypal` -> `shipping` for creating & updating customers as well as creating payment methods * Do not convert to Decimal if amount is None in AuthorizationAdjustement (#70) * Add `device_data_captured` field to `risk_data` * Add `bin_data` to `payment_method_nonce` ## 3.38.0 * Add iDEAL webhook support * Add AuthorizationAdjustment class and `authorization_adjustments` to Transaction * Coinbase is no longer a supported payment method. `PaymentMethodNoLongerSupported` will be returned for Coinbase operations * Add facilitated details to Transaction if present * Add `submit_for_settlement` option to `Subscription.retry_charge` * Add `options` -> `paypal` -> `description` for creating and updating subscriptions * Add Braintree.Dispute.find * Add braintree.Dispute.accept * Add braintree.Dispute.add_file_evidence * Add braintree.Dispute.add_text_evidence * Add braintree.Dispute.finalize * Add braintree.Dispute.find * Add braintree.Dispute.remove_evidence * Add braintree.Dispute.search * Add braintree.DocumentUpload ## 3.37.2 * Fix a bug where a null value for `amount` in `CreditCardVerification` would result in a `ValueError` * Add docstrings for AttributeGetter and Search. Thanks @sharma7n! * Add support for additional PayPal options when vaulting a PayPal Order ## 3.37.1 * Add gzip support * Fix a bug in CreditCardVerification where `amount` and `currency_iso_code` were always expected ## 3.37.0 * Fix a regression where `util/datetime_parser.py` was missing * Add support for Visa Checkout * Improve setup.py * Verification response includes amount and currency iso code * Add support for payee_email with paypal intent=order * Add support for skip_avs & skip_cvs ## 3.36.0 * Add ConnectedMerchantStatusTransitioned and ConnectedMerchantPayPalStatusChanged Auth webhooks ## 3.35.0 * Add LICENSE metadata. Thanks graingert. * Allow custom verification amount on payment method updates. * Fix a bug where `merchant_account.all` would attempt to fetch too many pages of merchant accounts ## 3.34.0 * Stop sending account_description field from us bank accounts * Add functionality to list all merchant accounts for a merchant with `merchant_account.all` ## 3.33.0 * Add option `skip_advanced_fraud_check` for transaction flows ## 3.32.0 * Update UsBank tests to use legal routing numbers * Allow setting a custom verification amount in `PaymentMethod` options * Allow setting processor specific fields for transactions and verifications ## 3.31.0 * Fix `UsBankAccount` support for `Customer`s * Added handling for unicode parameters. (Thanks @mgalgs) * Raise `ConfigurationError` for empty string credentials * Update `Grant` api to support options dictionary ## 3.30.0 * Add 'UsBankAccount' payment method ## 3.29.2 * Update links in docstrings * Remove Python 3.x-incompatible branch check * Remove references to SubMerchantAccount API ## 3.29.1 * Improve error handling around server timeouts ## 3.29.0 * Allow 'default_payment_method' option in Customer * Allow 'transaction_source' option in Transaction Sale ## 3.28.0 * Expose resource collection ids * Add order id to refund * Enable 3DS pass thru ## 3.27.0 * Add method of revoking OAuth access tokens ## 3.26.1 * Correct issue with setup.py ## 3.26.0 * Add Transaction `update_details` * Support for Too Many Requests response codes * Add SubMerchantAccount object with associate objects * Allow more parameters to be sent on SubMerchantAccount create * Add SubMerchantAccount update * Handle validation errors for SubMerchantAccount create / update ## 3.25.0 * Add AccountUpdaterDailyReport webhook parsing ## 3.24.0 * Add Verification#create * Add options to `submit_for_settlement` transaction flows * Update https certificate bundle * Support environment settings with strings ## 3.23.0 * Add better defaults to client token generation when using an access token by consolidating client token defaults into ClientTokenGateway * Add PaymentMethodGateway#revoke ## 3.22.0 * Add VenmoAccount * Add support for Set Transaction Context supplementary data. ## 3.21.0 * Add transaction to subscription successfully charged webhook * Add new ProcessorDoesNotSupportAuths error * Add support for partial settlement transactions * Add constants for dispute kind * Preserve backtrace when not wrapping HTTP exceptions * Add date_opened and date_won to dispute webhooks * Add support for searching transactions from oauth app * Support AMEX express checkout ## 3.20.0 * add source\_description to android pay and apple pay * add new android pay test nonces * add support for amex rewards transactions * add billing\_agreement\_id to paypalaccount ## 3.19.0 * Add new test payment method nonces * Allow passing description on PayPal transactions ## 3.18.0 * Fix oauth authentication * Fix python 3 syntax ## 3.17.0 * Add oauth support ## 3.16.0 * Add support for Android Pay ## 3.15.0 * Validate webhook challenge payload ## 3.14.0 * Add 3DS server side fields ## 3.13.0 * Add attribute to customer * Add coinbase constant * Add European test nonce ## 3.12.0 * Add support for new SEPA workflow ## 3.11.1 * Fix test failures in Python 3.3+ ## 3.11.0 * Accept additional params in PaymentMethod.create() ## 3.10.0 * Add 3D Secure transaction fields * Add ability to create nonce from vaulted payment methods ## 3.9.0 * Support Coinbase accounts * Surface Apple Pay payment instrument name in responses * Expose subscription status events * Support SEPA bank accounts for customer * Improve documentation ## 3.8.0 * Add error code constants * Allow PayPal parameters to be sent in options.paypal ## 3.7.0 * Add risk_data to Transaction and Verification with Kount decision and id * Add verification_amount an option when creating a credit card * Add TravelCruise industry type to Transaction * Add room_rate to Lodging industry type * Add CreditCard#verification as the latest verification on that credit card * Add ApplePay support to all endpoints that may return ApplePayCard objects * Align WebhookTesting with other client libraries ## 3.6.0 * Allow descriptor to be passed in Funding Details options params for Merchant Account create and update. ## 3.5.0 * Add additional_processor_response to transaction ## 3.4.1 * Allow payee_email to be passed in options params for Transaction create ## 3.4.0 * Added paypal specific fields to transaction calls * Added SettlementPending, SettlementDeclined transaction statuses ## 3.3.0 * Add Descriptor url support * Fix client token version type ## 3.2.0 * Support credit card options and billing address in PaymentMethod.create * Add PaymentMethod.update * Add associated subscriptions to PayPalAccount * Test refactoring and cleanup ## 3.1.1 * Add support for v.zero SDKs ## 3.0.0 * Drop Python 2.5 support * Remove use_unsafe_ssl option * Remove httplib strategy and pycurl strategy * Add Python 3.3+ support ## 2.29.1 * Make webhook parsing more robust with newlines * Add messages to InvalidSignature exceptions ## 2.29.0 * Include Dispute information on Transaction * Search for Transactions disputed on a certain date ## 2.28.0 * Disbursement Webhooks ## 2.27.0 * Fix using instantiated Configuration objects without first calling Configuration.configure * Accept billing_address_id on transaction create * Expose current_billing_cycle on addons and discounts ## 2.26.0 * Merchant account find API ## 2.25.0 * Merchant account update API * Merchant account create API v2 ## 2.24.1 * Update configuration URLs ## 2.24.0 * Add partnership support * Add partner configuration ## 2.23.1 * Add configuration option for custom HTTP strategies ## 2.23.0 * Adds hold_in_escrow method * Add error codes for verification not supported error * Add company_name and tax_id to merchant account create * Adds cancel_release methods * Adds release_from_escrow functionality * Adds owner_phone to merchant account signature. * Adds merchant account phone error code. ## 2.22.0 * Adds device data to transactions, customers, and credit cards. ## 2.21.0 * Adds disbursement details to transactions. * Adds image_url to transactions. ## 2.20.0 * Support requests >= 1.0 * Add new validation errors and rename old ones ## 2.19.0 * Adds channel field to transactions. ## 2.18.0 * Add additional card types for card type indicators ## 2.17.0 * Adds verification search ## 2.16.0 * Additional card information, such as prepaid, debit, commercial, Durbin regulated, healthcare, and payroll, are returned on credit card responses * Allows transactions to be specified as recurring ## 2.15.0 * Adds prepaid attribute to credit cards (possible values of: Yes, No, Unknown) ## 2.14.2 * Add settling transaction status to transaction search ## 2.14.1 * Adds new package braintree.util.http_stategy to setup.py ## 2.14.0 * Removes relative imports for python 3.0 (thanks [MichaelBlume](https://github.com/MichaelBlume)) * Adds webhook gateways for parsing, verifying, and testing incoming notifications * Allow specifying the http strategy to use (PycURL, httplib, requests) ## 2.13.0 * Adds search for duplicate credit cards given a payment method token * Adds flag to fail saving credit card to vault if card is duplicate ## 2.12.3 * Exposes plan_id on transactions ## 2.12.2 * Added error code for invalid purchase order number * Fixed zip_safe=False error when building (GitHub issue #17) ## 2.12.1 * Added error message for merchant accounts that do not support refunds ## 2.12.0 * Added ability to retrieve all Plans, AddOns, and Discounts * Added Transaction cloning ## 2.11.0 * Added SettlementBatchSummary ## 2.10.1 * Enabled gzip encoding for HTTP requests * Fixed handling of long integers when generating xml (thanks [glencoates](https://github.com/glencoates)) * Added new error code ## 2.10.0 * Added subscription_details to Transaction * Added flag to store in vault only when a transaction is successful * Added new error code ## 2.9.1 * Added improvements to unicode handling. ## 2.9.0 * Added a new transaction state, AuthorizationExpired. * Enabled searching by authorization_expired_at. ## 2.8.0 * Added next_billing_date and transaction_id to subscription search * Added address_country_name to customer search * Added new error codes ## 2.7.0 * Added Customer search * Added dynamic descriptors to Subscriptions and Transactions * Added level 2 fields to Transactions: * tax_amount * tax_exempt * purchase_order_number ## 2.6.1 * Added billing_address_id to allowed parameters for credit cards create and update * Allow searching on subscriptions that are currently in a trial period using in_trial_period ## 2.6.0 * Added ability to perform multiple partial refunds on Transactions * Deprecated Transaction refund_id in favor of refund_ids * Added revert_subscription_on_proration_failure flag to Subscription update that specifies how a Subscription should react to a failed proration charge * Deprecated Subscription next_bill_amount in favor of next_billing_period_amount * Added pycurl dependency in place of M2Crypto for better cross-platform compatibility * Added new fields to Subscription: * balance * paid_through_date * next_billing_period_amount ## 2.5.0 * Added AddOns/Discounts * Enhanced Subscription search * Enhanced Transaction search * Added constants for CreditCardVerification statuses * Added Expired and Pending statuses to Subscription * Allowed prorate_charges to be specified on Subscription update * Allowed argument lists and literal lists when searching for Subscriptions and Transactions * Added AddOn/Discount details to Transactions that were created from a Subscription * All Braintree exceptions now inherit from BraintreeError superclass * Removed 13 digit Visa Sandbox Credit Card number and replaced it with a 16 digit Visa * Made gateway operations threadsafe when using multiple configurations * Added new fields to Subscription: * billing_day_of_month * days_past_due * first_billing_date * never_expires * number_of_billing_cycles ## 2.4.1 * Added support for M2Crypto version 0.20.1, which is the default for Ubuntu Lucid (thanks [foresto](https://github.com/foresto)) ## 2.4.0 * Added unified message to ErrorResult * Added ability to specify country using country_name, country_code_alpha2, country_code_alpha3, or country_code_numeric (see [ISO_3166-1](https://en.wikipedia.org/wiki/ISO_3166-1)) * Renamed Subscription retryCharge to retry_charge * Added gateway_rejection_reason to Transaction and Verification * Allow searching with date objects (in addition to datetime) * When creating a Subscription, return failed transaction on the ErrorResult if the initial transaction is not successful ## 2.3.0 * Added unified TransparentRedirect url and confirm methods and deprecated old methods * Added methods to CreditCard to allow searching on expiring and expired credit cards * Allow credit card verification against a specified merchant account * Added all method on Customer to retrieve all customers * Added ability to update a customer, credit card, and billing address in one request * Allow updating the payment method token on a subscription * Added methods to navigate between a Transaction and its refund (in both directions) ## 2.2.1 * Use isinstance instead of type to cater to inheritance (thanks [danielgtaylor](https://github.com/danielgtaylor)) ## 2.2.0 * Prevent race condition when pulling back collection results -- search results represent the state of the data at the time the query was run * Rename ResourceCollection's approximate_size to maximum_size because items that no longer match the query will not be returned in the result set * Correctly handle HTTP error 426 (Upgrade Required) -- the error code is returned when your client library version is no longer compatible with the gateway ## 2.1.0 * Added transaction advanced search * Added ability to partially refund transactions * Added ability to manually retry past-due subscriptions * Added new transaction error codes * Allow merchant account to be specified when creating transactions * Allow creating a transaction with a vault customer and new credit card * Allow existing billing address to be updated when updating credit card ## 2.0.0 * Updated is_success on transaction results to return false on declined transactions * Search results now return a generator and will automatically paginate data * Allow passing cardholder_name when creating transactions ## 1.2.0 * Renamed ValidationErrorCollection#all to deep_errors and made it a property * Added the ability to make a credit card the default card for a customer * Updated Quick Start in README.md to show a workflow with error checking ## 1.1.0 * Added subscription search * Return associated subscriptions when finding credit cards * Raise down for maintenance error instead of forged query string error on 503 responses * Updated SSL CA file ## 1.0.0 * Initial release braintree_python-4.31.0/Dockerfile000066400000000000000000000003751471021343500171520ustar00rootroot00000000000000FROM debian:bullseye RUN apt-get update RUN apt-get -y install python3 rake RUN apt-get -y install python3-pip RUN pip3 install --upgrade pip RUN pip3 install --upgrade setuptools RUN echo 'alias python=python3' >> ~/.bashrc WORKDIR /braintree-python braintree_python-4.31.0/Jenkinsfile000066400000000000000000000023051471021343500173370ustar00rootroot00000000000000#!groovy def FAILED_STAGE pipeline { agent none environment { REPO_NAME = "braintree-python" SLACK_CHANNEL = "#auto-team-sdk-builds" } stages { stage("Audit") { parallel { // Runs a static code analysis scan and posts results to the PayPal Polaris server stage("Polaris") { agent { node { label "" customWorkspace "workspace/${REPO_NAME}" } } steps { polarisAudit() } post { failure { script { FAILED_STAGE = env.STAGE_NAME } } } } // Runs a software composition analysis scan and posts results to the PayPal Black Duck server stage("Black Duck") { agent { node { label "" customWorkspace "workspace/${REPO_NAME}" } } steps { blackduckAudit(debug: "true") } post { failure { script { FAILED_STAGE = env.STAGE_NAME } } } } } } } } braintree_python-4.31.0/LICENSE000066400000000000000000000021211471021343500161540ustar00rootroot00000000000000(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-4.31.0/MANIFEST.in000066400000000000000000000000301471021343500167020ustar00rootroot00000000000000include braintree/ssl/* braintree_python-4.31.0/Makefile000066400000000000000000000003561471021343500166170ustar00rootroot00000000000000.PHONY: console build console: build docker run -it -v="$(PWD):/braintree-python" --net="host" braintree-python /bin/bash -l -c "pip3 install -r dev_requirements.txt;pip3 install pylint;bash" build: docker build -t braintree-python . braintree_python-4.31.0/README.md000066400000000000000000000077151471021343500164440ustar00rootroot00000000000000# Braintree Python library The Braintree Python library provides integration access to the Braintree Gateway. ## TLS 1.2 required > **The Payment Card Industry (PCI) Council has [mandated](https://blog.pcisecuritystandards.org/migrating-from-ssl-and-early-tls) that early versions of TLS be retired from service. All organizations that handle credit card information are required to comply with this standard. As part of this obligation, Braintree has updated its services to require TLS 1.2 for all HTTPS connections. Braintrees require HTTP/1.1 for all connections. Please see our [technical documentation](https://github.com/paypal/tls-update) for more information.** ## Dependencies * [requests](http://docs.python-requests.org/en/latest/) The Braintree Python SDK is tested against Python versions 3.5.3 and 3.12.0. _The Python core development community has released [End-of-Life branches](https://devguide.python.org/devcycle/#end-of-life-branches) for Python versions 2.7 - 3.4, and are no longer receiving [security updates](https://devguide.python.org/#branchstatus). As a result, Braintree no longer supports these versions of Python._ ## Versions Braintree employs a deprecation policy for our SDKs. For more information on the statuses of an SDK check our [developer docs](https://developer.paypal.com/braintree/docs/reference/general/server-sdk-deprecation-policy). | Major version number | Status | Released | Deprecated | Unsupported | | -------------------- | ------ | -------- | ---------- | ----------- | | 4.x.x | Active | March 2020 | TBA | TBA | | 3.x.x | Inactive | June 2014 | March 2022 | March 2023 | ## Documentation * [Official documentation](https://developer.paypal.com/braintree/docs/start/hello-server/python) Updating from an Inactive, Deprecated, or Unsupported version of this SDK? Check our [Migration Guide](https://developer.paypal.com/braintree/docs/reference/general/server-sdk-migration-guide/python) for tips. ## Quick Start Example ```python import braintree gateway = braintree.BraintreeGateway( braintree.Configuration( environment=braintree.Environment.Sandbox, merchant_id="your_merchant_id", public_key="your_public_key", private_key="your_private_key", ) ) result = gateway.transaction.sale({ "amount": "1000.00", "payment_method_nonce": nonce_from_the_client, "options": { "submit_for_settlement": True } }) if result.is_success: print("success!: " + result.transaction.id) elif result.transaction: print("Error processing transaction:") print(" code: " + result.transaction.processor_response_code) print(" text: " + result.transaction.processor_response_text) else: for error in result.errors.deep_errors: print("attribute: " + error.attribute) print(" code: " + error.code) print(" message: " + error.message) ``` ## Developing 1. Create a [virtualenv](https://virtualenv.pypa.io/) called `venv`: ``` virtualenv venv ``` 2. Start the virtualenv: ``` source venv/bin/activate ``` 3. Install dependencies: ``` pip3 install -r dev_requirements.txt ``` ## Developing (Docker) The `Makefile` and `Dockerfile` will build an image containing the dependencies and drop you to a terminal where you can run tests. ``` make ``` ## Testing Our friends at [Venmo](https://venmo.com) have [an open source library](https://github.com/venmo/btnamespace) designed to simplify testing of applications using this library. If you wish to run the tests, make sure you are set up for development (see instructions above). The unit specs can be run by anyone on any system, but the integration specs are meant to be run against a local development server of our gateway code. These integration specs are not meant for public consumption and will likely fail if run on your system. To run unit tests use rake (`rake test:unit`) or unittest (`python3 -m unittest discover tests/unit`). ## License See the [LICENSE](LICENSE) file for more info. braintree_python-4.31.0/Rakefile000066400000000000000000000040151471021343500166200ustar00rootroot00000000000000task :default => :test task :test => ["test:all"] namespace :test do # Usage: # rake test:unit # rake test:unit[test_file] # rake test:unit[test_file,test_class,test_method] desc "run unit tests" task :unit, [:file_name, :class_name, :test_name] do |task, args| if args.file_name.nil? sh "python3 -m unittest discover tests/unit" elsif args.class_name.nil? sh "python3 -m unittest tests/unit/#{args.file_name}.py" else sh "python3 -m unittest tests.unit.#{args.file_name}.#{args.class_name}.#{args.test_name}" end end # Usage: # rake test:integration # rake test:integration[test_file] # rake test:integration[test_file,test_class,test_method] desc "run integration tests" task :integration, [:file_name, :class_name, :test_name] do |task, args| if args.file_name.nil? sh "python3 -m unittest discover tests/integration" elsif args.class_name.nil? sh "python3 -m unittest tests/integration/#{args.file_name}.py" else sh "python3 -m unittest tests.integration.#{args.file_name}.#{args.class_name}.#{args.test_name}" end end task :all => [:unit, :integration] end task :clean do rm_rf "build" rm_rf "dist" rm_f "MANIFEST" end namespace :pypi do desc "Upload a new version to PyPI" task :upload => :clean do sh "python3 setup.py sdist bdist_wheel" sh "twine upload dist/*" end end namespace :lint do # We are only checking linting errors (for now), # so we use --disable to skip refactor(R), convention(C), and warning(W) messages desc "Evaluate test code quality using pylintrc file" task :tests do puts `pylint --disable=R,C,W tests --rcfile=.pylintrc --disable=R0801 --disable=W0232` end desc "Evaluate app code quality using pylintrc file" task :code do puts `pylint --disable=R,C,W braintree --rcfile=.pylintrc` end desc "Evaluate library code quality using pylintrc file" task :all do puts `pylint --disable=R,C,W braintree tests --rcfile=.pylintrc` end end task :lint => "lint:all" braintree_python-4.31.0/braintree/000077500000000000000000000000001471021343500171265ustar00rootroot00000000000000braintree_python-4.31.0/braintree/__init__.py000066400000000000000000000113531471021343500212420ustar00rootroot00000000000000from braintree.ach_mandate import AchMandate from braintree.add_on import AddOn from braintree.add_on_gateway import AddOnGateway from braintree.address import Address from braintree.address_gateway import AddressGateway from braintree.amex_express_checkout_card import AmexExpressCheckoutCard from braintree.android_pay_card import AndroidPayCard from braintree.apple_pay_card import ApplePayCard from braintree.apple_pay_gateway import ApplePayGateway from braintree.blik_alias import BlikAlias from braintree.braintree_gateway import BraintreeGateway from braintree.client_token import ClientToken from braintree.configuration import Configuration from braintree.connected_merchant_paypal_status_changed import ConnectedMerchantPayPalStatusChanged from braintree.connected_merchant_status_transitioned import ConnectedMerchantStatusTransitioned from braintree.credentials_parser import CredentialsParser from braintree.credit_card import CreditCard from braintree.credit_card_gateway import CreditCardGateway from braintree.credit_card_verification import CreditCardVerification from braintree.credit_card_verification_search import CreditCardVerificationSearch from braintree.customer import Customer from braintree.customer_gateway import CustomerGateway from braintree.customer_search import CustomerSearch from braintree.descriptor import Descriptor from braintree.disbursement import Disbursement from braintree.discount import Discount from braintree.discount_gateway import DiscountGateway from braintree.dispute import Dispute from braintree.dispute_search import DisputeSearch from braintree.document_upload import DocumentUpload from braintree.document_upload_gateway import DocumentUploadGateway from braintree.enriched_customer_data import EnrichedCustomerData from braintree.environment import Environment from braintree.error_codes import ErrorCodes from braintree.error_result import ErrorResult from braintree.errors import Errors from braintree.europe_bank_account import EuropeBankAccount from braintree.liability_shift import LiabilityShift from braintree.local_payment_completed import LocalPaymentCompleted from braintree.local_payment_reversed import LocalPaymentReversed from braintree.merchant import Merchant from braintree.merchant_account import MerchantAccount from braintree.merchant_account_gateway import MerchantAccountGateway from braintree.oauth_access_revocation import OAuthAccessRevocation from braintree.partner_merchant import PartnerMerchant from braintree.payment_instrument_type import PaymentInstrumentType from braintree.payment_method import PaymentMethod from braintree.payment_method_customer_data_updated_metadata import PaymentMethodCustomerDataUpdatedMetadata from braintree.payment_method_nonce import PaymentMethodNonce from braintree.payment_method_parser import parse_payment_method from braintree.paypal_account import PayPalAccount from braintree.plan import Plan from braintree.plan_gateway import PlanGateway from braintree.processor_response_types import ProcessorResponseTypes from braintree.resource_collection import ResourceCollection from braintree.risk_data import RiskData from braintree.samsung_pay_card import SamsungPayCard from braintree.search import Search from braintree.sepa_direct_debit_account import SepaDirectDebitAccount from braintree.settlement_batch_summary import SettlementBatchSummary from braintree.signature_service import SignatureService from braintree.status_event import StatusEvent from braintree.subscription import Subscription from braintree.subscription_gateway import SubscriptionGateway from braintree.subscription_search import SubscriptionSearch from braintree.subscription_status_event import SubscriptionStatusEvent from braintree.successful_result import SuccessfulResult from braintree.testing_gateway import TestingGateway from braintree.three_d_secure_info import ThreeDSecureInfo from braintree.transaction import Transaction from braintree.transaction_amounts import TransactionAmounts from braintree.transaction_details import TransactionDetails from braintree.transaction_gateway import TransactionGateway from braintree.transaction_line_item import TransactionLineItem from braintree.transaction_search import TransactionSearch from braintree.unknown_payment_method import UnknownPaymentMethod from braintree.us_bank_account import UsBankAccount from braintree.validation_error_collection import ValidationErrorCollection from braintree.venmo_account import VenmoAccount from braintree.venmo_profile_data import VenmoProfileData from braintree.version import Version from braintree.webhook_notification import WebhookNotification from braintree.webhook_notification_gateway import WebhookNotificationGateway from braintree.webhook_testing import WebhookTesting from braintree.webhook_testing_gateway import WebhookTestingGateway braintree_python-4.31.0/braintree/account_updater_daily_report.py000066400000000000000000000011111471021343500254270ustar00rootroot00000000000000from braintree.configuration import Configuration from braintree.resource import Resource class AccountUpdaterDailyReport(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "report_url" in attributes: self.report_url = attributes.pop("report_url") if "report_date" in attributes: self.report_date = attributes.pop("report_date") def __repr__(self): detail_list = ["report_url", "report_date"] return super(AccountUpdaterDailyReport, self).__repr__(detail_list) braintree_python-4.31.0/braintree/ach_mandate.py000066400000000000000000000003631471021343500217260ustar00rootroot00000000000000import braintree from braintree.util.datetime_parser import parse_datetime from braintree.resource import Resource class AchMandate(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-4.31.0/braintree/add_on.py000066400000000000000000000003231471021343500207220ustar00rootroot00000000000000from braintree.configuration import Configuration from braintree.modification import Modification class AddOn(Modification): @staticmethod def all(): return Configuration.gateway().add_on.all() braintree_python-4.31.0/braintree/add_on_gateway.py000066400000000000000000000010021471021343500224360ustar00rootroot00000000000000import 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-4.31.0/braintree/address.py000066400000000000000000000112761471021343500211340ustar00rootroot00000000000000from 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({ "company": "Braintree", "country_name": "United States of America", "customer_id": customer.id, "extended_address": "Apartment 1", "first_name": "John", "international_phone": { "country_code": "1", "national_number": "3121234567" }, "last_name": "Doe", "locality": "Chicago", "phone_number": "312-123-4567", "postal_code": "60606", "region": "IL", "street_address": "111 First Street" }) print(result.customer.first_name) print(result.customer.last_name) """ def __repr__(self): detail_list = [ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "customer_id", "extended_address", "first_name", "international_phone", "last_name", "locality", "phone_number", "postal_code", "region", "shipping_method", "street_address" ] return super(Address, self).__repr__(detail_list) # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class ShippingMethod(object): """ Constants representing shipping methods for shipping addresses. Available types are: * braintree.Address.ShippingMethod.SameDay * braintree.Address.ShippingMethod.NextDay * braintree.Address.ShippingMethod.Priority * braintree.Address.ShippingMethod.Ground * braintree.Address.ShippingMethod.Electronic * braintree.Address.ShippingMethod.ShipToStore * braintree.Address.ShippingMethod.PickupInStore """ SameDay = "same_day" NextDay = "next_day" Priority = "priority" Ground = "ground" Electronic = "electronic" ShipToStore = "ship_to_store" PickupInStore = "pickup_in_store" @staticmethod def create(params=None): """ Create an Address. A customer_id is required:: customer = braintree.Customer.create().customer result = braintree.Address.create({ "customer_id": customer.id, "first_name": "John", ... }) """ if params is None: params = {} 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=None): """ 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" }) """ if params is None: params = {} 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", {"international_phone": ["country_code", "national_number"]}, "last_name", "locality", "phone_number", "postal_code", "region", "street_address"] @staticmethod def update_signature(): return Address.create_signature() braintree_python-4.31.0/braintree/address_gateway.py000066400000000000000000000062701471021343500226530ustar00rootroot00000000000000import 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 __validate_chars_in_args(self, customer_id, address_id): if not re.search(r"\A[0-9A-Za-z_-]+\Z", customer_id): raise KeyError("customer_id contains invalid characters") if not re.search(r"\A[0-9A-Za-z]+\Z", address_id): raise KeyError("address_id contains invalid characters") def create(self, params=None): if params is None: params = {} Resource.verify_keys(params, Address.create_signature()) if "customer_id" not in params: raise KeyError("customer_id must be provided") if not re.search(r"\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.__validate_chars_in_args(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: # NEXT_MAJOR_VERSION return KeyError instead of NotFoundError, it's a more helpful error message to the developer that way if customer_id is None or customer_id.strip() == "" or address_id is None or address_id.strip() == "": raise NotFoundError() self.__validate_chars_in_args(customer_id, address_id) 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=None): if params is None: params = {} Resource.verify_keys(params, Address.update_signature()) self.__validate_chars_in_args(customer_id, address_id) 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-4.31.0/braintree/amex_express_checkout_card.py000066400000000000000000000012271471021343500250630ustar00rootroot00000000000000import braintree from braintree.resource import Resource from warnings import warn class AmexExpressCheckoutCard(Resource): """ A class representing Braintree Amex Express Checkout card objects. Deprecated """ def __init__(self, gateway, attributes): warn("AmexExpressCheckoutCard is deprecated") 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-4.31.0/braintree/android_pay_card.py000066400000000000000000000056631471021343500227740ustar00rootroot00000000000000import braintree from braintree.resource import Resource # NEXT_MAJOR_VERSION - rename to GooglePayCard 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): if not self.expiration_month or not self.expiration_year: return None 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 @staticmethod def signature(): options = ["make_default"] signature = [ "customer_id", "cardholder_name", "cryptogram", "google_transaction_id", "expiration_month", "expiration_year", "number", "token", "eci_indicator", { "options": options }, { "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", "phone_number" ] } ] return signature @staticmethod def card_signature(): options = ["make_default"] signature = [ "customer_id", "cardholder_name", "google_transaction_id", "expiration_month", "expiration_year", "number", "token", { "options": options }, { "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", "phone_number" ] } ] return signature @staticmethod def network_token_signature(): return AndroidPayCard.signature() braintree_python-4.31.0/braintree/apple_pay_card.py000066400000000000000000000040341471021343500224440ustar00rootroot00000000000000import 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): if not self.expiration_month or not self.expiration_year: return None return self.expiration_month + "/" + self.expiration_year @staticmethod def signature(): options = ["make_default"] signature = [ "customer_id", "cardholder_name", "expiration_month", "expiration_year", "number", "cryptogram", "eci_indicator", "token", { "options": options }, { "billing_address": [ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "first_name", "last_name", "locality", "postal_code", "phone_number", "region", "street_address" ] } ] return signature braintree_python-4.31.0/braintree/apple_pay_gateway.py000066400000000000000000000024141471021343500231740ustar00rootroot00000000000000from html import escape from braintree.apple_pay_options import ApplePayOptions from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult from braintree.exceptions.unexpected_error import UnexpectedError class ApplePayGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def register_domain(self, domain): response = self.config.http().post(self.config.base_merchant_path() + "/processing/apple_pay/validate_domains", {'url': domain}) if "response" in response and response["response"]["success"]: return SuccessfulResult() elif response["api_error_response"]: return ErrorResult(self.gateway, response["api_error_response"]) def unregister_domain(self, domain): self.config.http().delete(self.config.base_merchant_path() + "/processing/apple_pay/unregister_domain?url=" + escape(domain)) return SuccessfulResult() def registered_domains(self): response = self.config.http().get(self.config.base_merchant_path() + "/processing/apple_pay/registered_domains") if "response" in response: response = ApplePayOptions(response.pop("response")) return response.domains braintree_python-4.31.0/braintree/apple_pay_options.py000066400000000000000000000001511471021343500232220ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class ApplePayOptions(AttributeGetter): pass braintree_python-4.31.0/braintree/attribute_getter.py000066400000000000000000000021161471021343500230550ustar00rootroot00000000000000class AttributeGetter(object): """ Helper class for objects that define their attributes from dictionaries passed in during instantiation. Example: a = AttributeGetter({'foo': 'bar', 'baz': 5}) a.foo >> 'bar' a.baz >> 5 Typically inherited by subclasses instead of directly instantiated. """ def __init__(self, attributes=None): if attributes is None: attributes = {} self._setattrs = [] for key, val in attributes.items(): setattr(self, key, val) self._setattrs.append(key) if key == "global_id": setattr(self, "graphql_id", val) self._setattrs.append("graphql_id") 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-4.31.0/braintree/authorization_adjustment.py000066400000000000000000000005001471021343500246310ustar00rootroot00000000000000from decimal import Decimal from braintree.attribute_getter import AttributeGetter class AuthorizationAdjustment(AttributeGetter): def __init__(self, attributes): AttributeGetter.__init__(self, attributes) if getattr(self, "amount", None) is not None: self.amount = Decimal(self.amount) braintree_python-4.31.0/braintree/bin_data.py000066400000000000000000000001411471021343500212350ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class BinData(AttributeGetter): pass braintree_python-4.31.0/braintree/blik_alias.py000066400000000000000000000005671471021343500216020ustar00rootroot00000000000000import braintree from braintree.resource import Resource class BlikAlias(Resource): """ A class representing a BlikAlias. For more information on BlikAliases, see https://developer.paypal.com/braintree/docs/guides/local-payment-methods/blik-one-click """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-4.31.0/braintree/braintree_gateway.py000066400000000000000000000076651471021343500232120ustar00rootroot00000000000000from braintree.add_on_gateway import AddOnGateway from braintree.address_gateway import AddressGateway from braintree.apple_pay_gateway import ApplePayGateway from braintree.client_token_gateway import ClientTokenGateway from braintree.configuration import Configuration from braintree.credit_card_gateway import CreditCardGateway from braintree.credit_card_verification_gateway import CreditCardVerificationGateway from braintree.customer_gateway import CustomerGateway from braintree.discount_gateway import DiscountGateway from braintree.dispute_gateway import DisputeGateway from braintree.document_upload_gateway import DocumentUploadGateway from braintree.exchange_rate_quote_gateway import ExchangeRateQuoteGateway from braintree.merchant_account_gateway import MerchantAccountGateway from braintree.merchant_gateway import MerchantGateway from braintree.oauth_gateway import OAuthGateway from braintree.payment_method_gateway import PaymentMethodGateway from braintree.payment_method_nonce_gateway import PaymentMethodNonceGateway from braintree.paypal_account_gateway import PayPalAccountGateway from braintree.sepa_direct_debit_account_gateway import SepaDirectDebitAccountGateway from braintree.plan_gateway import PlanGateway from braintree.settlement_batch_summary_gateway import SettlementBatchSummaryGateway from braintree.subscription_gateway import SubscriptionGateway from braintree.testing_gateway import TestingGateway from braintree.transaction_gateway import TransactionGateway from braintree.transaction_line_item_gateway import TransactionLineItemGateway from braintree.us_bank_account_gateway import UsBankAccountGateway from braintree.us_bank_account_verification_gateway import UsBankAccountVerificationGateway from braintree.webhook_notification_gateway import WebhookNotificationGateway from braintree.webhook_testing_gateway import WebhookTestingGateway 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.apple_pay = ApplePayGateway(self) self.client_token = ClientTokenGateway(self) self.credit_card = CreditCardGateway(self) self.customer = CustomerGateway(self) self.discount = DiscountGateway(self) self.dispute = DisputeGateway(self) self.document_upload = DocumentUploadGateway(self) self.exchange_rate_quote = ExchangeRateQuoteGateway(self) self.graphql_client = self.config.graphql_client() self.merchant = MerchantGateway(self) self.merchant_account = MerchantAccountGateway(self) self.oauth = OAuthGateway(self) self.payment_method = PaymentMethodGateway(self) self.payment_method_nonce = PaymentMethodNonceGateway(self) self.paypal_account = PayPalAccountGateway(self) self.plan = PlanGateway(self) self.sepa_direct_debit_account = SepaDirectDebitAccountGateway(self) self.settlement_batch_summary = SettlementBatchSummaryGateway(self) self.subscription = SubscriptionGateway(self) self.testing = TestingGateway(self) self.transaction = TransactionGateway(self) self.transaction_line_item = TransactionLineItemGateway(self) self.us_bank_account = UsBankAccountGateway(self) self.us_bank_account_verification = UsBankAccountVerificationGateway(self) self.verification = CreditCardVerificationGateway(self) self.webhook_notification = WebhookNotificationGateway(self) self.webhook_testing = WebhookTestingGateway(self) braintree_python-4.31.0/braintree/client_token.py000066400000000000000000000015511471021343500221600ustar00rootroot00000000000000import 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=None, gateway=None): if params is None: params = {} if gateway is None: gateway = Configuration.gateway().client_token return gateway.generate(params) @staticmethod def generate_signature(): return [ "customer_id", "merchant_account_id", "proxy_merchant_id", "version", {"domains": ["__any_key__"]}, {"options": ["fail_on_duplicate_payment_method", "fail_on_duplicate_payment_method_for_customer", "make_default", "verify_card"]} ] braintree_python-4.31.0/braintree/client_token_gateway.py000066400000000000000000000022561471021343500237040ustar00rootroot00000000000000import 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=None): if params is None: params = {} if "options" in params and "customer_id" not in params: for option in ["fail_on_duplicate_payment_method", "fail_on_duplicate_payment_method_for_customer", "make_default", "verify_card"]: 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-4.31.0/braintree/configuration.py000066400000000000000000000117751471021343500223620ustar00rootroot00000000000000import braintree from braintree.credentials_parser import CredentialsParser from braintree.environment import Environment from braintree.exceptions.configuration_error import ConfigurationError from braintree.util.graphql_client import GraphQLClient class Configuration(object): """ A class representing the configuration of your Braintree account. You must call configure before any other Braintree operations. :: braintree.Configuration.configure( braintree.Environment.Sandbox, "your_merchant_id", "your_public_key", "your_private_key" ) """ @staticmethod def configure(environment, merchant_id, public_key, private_key, **kwargs): Configuration.environment = Environment.parse_environment(environment) Configuration.merchant_id = merchant_id Configuration.public_key = public_key Configuration.private_key = private_key Configuration.default_http_strategy = kwargs.get("http_strategy", None) Configuration.timeout = kwargs.get("timeout", 60) Configuration.wrap_http_exceptions = kwargs.get("wrap_http_exceptions", False) @staticmethod def for_partner(environment, partner_id, public_key, private_key, **kwargs): return Configuration( environment=environment, merchant_id=partner_id, public_key=public_key, private_key=private_key, http_strategy=kwargs.get("http_strategy", None), timeout=kwargs.get("timeout", 60), wrap_http_exceptions=kwargs.get("wrap_http_exceptions", False) ) @staticmethod def gateway(): return braintree.braintree_gateway.BraintreeGateway(config=Configuration.instantiate()) @staticmethod def instantiate(): return Configuration( environment=Configuration.environment, merchant_id=Configuration.merchant_id, public_key=Configuration.public_key, private_key=Configuration.private_key, http_strategy=Configuration.default_http_strategy, timeout=Configuration.timeout, wrap_http_exceptions=Configuration.wrap_http_exceptions ) @staticmethod def api_version(): return "6" @staticmethod def graphql_api_version(): return "2018-09-10" def __init__(self, environment=None, merchant_id=None, public_key=None, private_key=None, client_id=None, client_secret=None, access_token=None, *args, **kwargs): if len(args) == 2: public_key, private_key = args parser = CredentialsParser(client_id=client_id, client_secret=client_secret, access_token=access_token) if parser.access_token is not None: parser.parse_access_token() self.environment = parser.environment self.merchant_id = parser.merchant_id elif parser.client_id is not None or parser.client_secret is not None: parser.parse_client_credentials() self.environment = parser.environment self.merchant_id = merchant_id else: self.environment = Environment.parse_environment(environment) if merchant_id == "": raise ConfigurationError("Missing merchant_id") else: self.merchant_id = merchant_id if public_key == "": raise ConfigurationError("Missing public_key") else: self.public_key = public_key if private_key == "": raise ConfigurationError("Missing private_key") else: self.private_key = private_key self.client_id = parser.client_id self.client_secret = parser.client_secret self.access_token = parser.access_token self.timeout = kwargs.get("timeout", 60) self.wrap_http_exceptions = kwargs.get("wrap_http_exceptions", False) http_strategy = kwargs.get("http_strategy", None) if http_strategy: self._http_strategy = http_strategy(self, self.environment) else: self._http_strategy = self.http() def base_merchant_path(self): return "/merchants/" + self.merchant_id def base_url(self): return self.environment.protocol + self.environment.server_and_port def graphql_base_url(self): return self.environment.protocol + self.environment.graphql_server_and_port + "/graphql" def http(self): return braintree.util.http.Http(self) def graphql_client(self): return GraphQLClient(self) def http_strategy(self): return self._http_strategy def has_client_credentials(self): return self.client_secret is not None and self.client_id is not None def assert_has_client_credentials(self): if not self.has_client_credentials(): raise ConfigurationError("client_id and client_secret are required") def has_access_token(self): return self.access_token is not None braintree_python-4.31.0/braintree/connected_merchant_paypal_status_changed.py000066400000000000000000000004231471021343500277440ustar00rootroot00000000000000from braintree.resource import Resource class ConnectedMerchantPayPalStatusChanged(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) @property def merchant_id(self): return self.merchant_public_id braintree_python-4.31.0/braintree/connected_merchant_status_transitioned.py000066400000000000000000000004221471021343500275070ustar00rootroot00000000000000from braintree.resource import Resource class ConnectedMerchantStatusTransitioned(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) @property def merchant_id(self): return self.merchant_public_id braintree_python-4.31.0/braintree/credentials_parser.py000066400000000000000000000037521471021343500233600ustar00rootroot00000000000000import os import sys import braintree from braintree.exceptions.configuration_error import ConfigurationError from braintree.environment import Environment class CredentialsParser(object): def __init__(self, client_id=None, client_secret=None, access_token=None): self.client_id = client_id self.client_secret = client_secret self.access_token = access_token def parse_client_credentials(self): if self.client_id is None and self.client_secret is not None: raise ConfigurationError("Missing client_id when constructing BraintreeGateway") if self.client_secret is None and self.client_id is not None: raise ConfigurationError("Missing client_secret when constructing BraintreeGateway") if not self.client_id.startswith("client_id"): raise ConfigurationError("Value passed for client_id is not a client_id") if not self.client_secret.startswith("client_secret"): raise ConfigurationError("Value passed for client_secret is not a client_secret") client_id_environment = self.get_environment(self.client_id) client_secret_environment = self.get_environment(self.client_secret) if client_id_environment is client_secret_environment: self.environment = client_id_environment else: raise ConfigurationError(" ".join([ "Mismatched credential environments: client_id environment is:", str(client_id_environment), "and client_secret environment is:", str(client_secret_environment) ])) def parse_access_token(self): self.environment = self.get_environment(self.access_token) self.merchant_id = self.get_merchant_id(self.access_token) def get_environment(self, credential): parts = credential.split("$") return Environment.All.get(parts[1]) def get_merchant_id(self, credential): parts = credential.split("$") return parts[2] braintree_python-4.31.0/braintree/credit_card.py000066400000000000000000000253331471021343500217510ustar00rootroot00000000000000import braintree import warnings from braintree.resource import Resource from braintree.address import Address from braintree.configuration import Configuration from braintree.credit_card_verification import CreditCardVerification from enum import Enum 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" "phone_number": "312-123-4567" }, "options": { "verify_card": True, "verification_amount": "2.00" } }) print(result.credit_card.token) print(result.credit_card.masked_number) For more information on CreditCards, see https://developer.paypal.com/braintree/docs/reference/request/credit-card/create/python """ class CardType(object): """ Contants representing the type of the credit card. Available types are: * Braintree.CreditCard.AmEx * Braintree.CreditCard.CarteBlanche * Braintree.CreditCard.ChinaUnionPay * Braintree.CreditCard.DinersClubInternational * Braintree.CreditCard.Discover * Braintree.CreditCard.Electron * Braintree.CreditCard.Elo * Braintree.CreditCard.Hiper * Braintree.CreditCard.Hipercard * Braintree.CreditCard.JCB * Braintree.CreditCard.Laser * Braintree.CreditCard.UK_Maestro * Braintree.CreditCard.Maestro * Braintree.CreditCard.MasterCard * Braintree.CreditCard.Solo * Braintree.CreditCard.Switch * Braintree.CreditCard.Visa * Braintree.CreditCard.Unknown """ AmEx = "American Express" CarteBlanche = "Carte Blanche" ChinaUnionPay = "China UnionPay" DinersClubInternational = "Diners Club" Discover = "Discover" Electron = "Electron" Elo = "Elo" Hiper = "Hiper" Hipercard = "Hipercard" JCB = "JCB" Laser = "Laser" UK_Maestro = "UK Maestro" Maestro = "Maestro" MasterCard = "MasterCard" Solo = "Solo" Switch = "Switch" Visa = "Visa" Unknown = "Unknown" class CustomerLocation(object): """ Contants representing the issuer location of the credit card. Available locations are: * braintree.CreditCard.CustomerLocation.International * braintree.CreditCard.CustomerLocation.US """ International = "international" US = "us" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ 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" class DebitNetwork(Enum): """ Constants representing the debit networks used for processing a pinless debit transaction * braintree.CreditCard.DebitNetwork.Accel * braintree.CreditCard.DebitNetwork.Maestro * braintree.CreditCard.DebitNetwork.Nyce * braintree.CreditCard.DebitNetwork.Pulse * braintree.CreditCard.DebitNetwork.Star * braintree.CreditCard.DebitNetwork.Star_Access """ Accel = "ACCEL" Maestro= "MAESTRO" Nyce = "NYCE" Pulse = "PULSE" Star = "STAR" Star_Access = "STAR_ACCESS" Commercial = DurbinRegulated = Debit = Healthcare = \ CountryOfIssuance = IssuingBank = Payroll = Prepaid = ProductId = CardTypeIndicator @staticmethod def create(params=None): """ Create a CreditCard. A number and expiration_date are required. :: result = braintree.CreditCard.create({ "number": "4111111111111111", "expiration_date": "12/2012" }) """ if params is None: params = {} return Configuration.gateway().credit_card.create(params) @staticmethod def update(credit_card_token, params=None): """ 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" }) """ if params is None: params = {} 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 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", "phone_number" ] options = [ "fail_on_duplicate_payment_method", "fail_on_duplicate_payment_method_for_customer", "make_default", "skip_advanced_fraud_checking", "venmo_sdk_session", # NEXT_MJOR_VERSION remove venmo_sdk_session "verification_account_type", "verification_amount", "verification_merchant_account_id", "verify_card", { "adyen":[ "overwrite_brand", "selected_brand" ] } ] three_d_secure_pass_thru = [ "cavv", "ds_transaction_id", "eci_flag", "three_d_secure_version", "xid" ] signature = [ "billing_address_id", "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", "number", "token", "venmo_sdk_payment_method_code", # NEXT_MJOR_VERSION remove venmo_sdk_payment_method_code "device_data", "payment_method_nonce", "device_session_id", "fraud_merchant_id", # NEXT_MAJOR_VERSION remove device_session_id and fraud_merchant_id { "billing_address": billing_address_params }, { "options": options }, { "three_d_secure_pass_thru": three_d_secure_pass_thru } ] if type == "create": signature.append("customer_id") elif type == "update": billing_address_params.append({"options": ["update_existing"]}) elif type == "update_via_customer": options.append("update_existing_token") billing_address_params.append({"options": ["update_existing"]}) else: raise AttributeError return signature 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): if not self.expiration_month or not self.expiration_year: return None return self.expiration_month + "/" + self.expiration_year @property def masked_number(self): """ Returns the masked number of the CreditCard. """ bin = self.bin_extended if hasattr(self, "bin_extended") else self.bin mask_length = 16 - len(bin) - len(self.last_4) mask = "*" * mask_length return bin + mask + self.last_4 braintree_python-4.31.0/braintree/credit_card_gateway.py000066400000000000000000000125771471021343500235000ustar00rootroot00000000000000import braintree import warnings 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 class CreditCardGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create(self, params=None): if params is None: params = {} Resource.verify_keys(params, CreditCard.create_signature()) self.__check_for_deprecated_attributes(params) return self._post("/payment_methods", {"credit_card": params}) def delete(self, credit_card_token): self.config.http().delete(self.config.base_merchant_path() + "/payment_methods/credit_card/" + credit_card_token) return SuccessfulResult() def expired(self): response = self.config.http().post(self.config.base_merchant_path() + "/payment_methods/all/expired_ids") return ResourceCollection(None, response, self.__fetch_expired) def expiring_between(self, start_date, end_date): formatted_start_date = start_date.strftime("%m%Y") formatted_end_date = end_date.strftime("%m%Y") query = "start=%s&end=%s" % (formatted_start_date, formatted_end_date) response = self.config.http().post(self.config.base_merchant_path() + "/payment_methods/all/expiring_ids?" + query) return ResourceCollection(query, response, self.__fetch_existing_between) def find(self, credit_card_token): try: if credit_card_token is None or credit_card_token.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_methods/credit_card/" + credit_card_token) return CreditCard(self.gateway, response["credit_card"]) except NotFoundError: raise NotFoundError("payment method with token " + repr(credit_card_token) + " not found") def forward(self, credit_card_token, receiving_merchant_id): raise NotFoundError("This method of forwarding payment methods is no longer supported. Please consider the Grant API for similar functionality.") def from_nonce(self, nonce): try: if nonce is None or nonce.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_methods/from_nonce/" + nonce) return CreditCard(self.gateway, response["credit_card"]) except NotFoundError: raise NotFoundError("payment method with nonce " + repr(nonce) + " locked, consumed or not found") def update(self, credit_card_token, params=None): if params is None: params = {} Resource.verify_keys(params, CreditCard.update_signature()) self.__check_for_deprecated_attributes(params) 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=None): if params is None: 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"]) # NEXT_MAJOR_VERSION remove these checks when the attributes are removed def __check_for_deprecated_attributes(self, params): if "device_session_id" in params.keys(): warnings.warn("device_session_id is deprecated, use device_data parameter instead", DeprecationWarning) if "fraud_merchant_id" in params.keys(): warnings.warn("fraud_merchant_id is deprecated, use device_data parameter instead", DeprecationWarning) if "venmo_sdk_payment_method_code" in params.keys() or "venmo_sdk_session" in params.keys(): warnings.warn("The Venmo SDK integration is Unsupported. Please update your integration to use Pay with Venmo instead.", DeprecationWarning) braintree_python-4.31.0/braintree/credit_card_verification.py000066400000000000000000000104561471021343500245130ustar00rootroot00000000000000from decimal import Decimal from braintree.attribute_getter import AttributeGetter from braintree.configuration import Configuration from braintree.risk_data import RiskData from braintree.three_d_secure_info import ThreeDSecureInfo from braintree.resource import Resource class CreditCardVerification(AttributeGetter): # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ 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.Verified """ Failed = "failed" GatewayRejected = "gateway_rejected" ProcessorDeclined = "processor_declined" Verified = "verified" def __init__(self, gateway, attributes): AttributeGetter.__init__(self, attributes) if "amount" in attributes and getattr(self, "amount", None): self.amount = Decimal(self.amount) else: self.amount = None if "currency_iso_code" not in attributes: self.currency_iso_code = None if "processor_response_code" not in attributes: self.processor_response_code = None if "processor_response_text" not in attributes: self.processor_response_text = None if "network_response_code" not in attributes: self.network_response_code = None if "network_response_text" not in attributes: self.network_response_text = None if "risk_data" in attributes: self.risk_data = RiskData(attributes["risk_data"]) else: self.risk_data = None if "three_d_secure_info" in attributes and not attributes["three_d_secure_info"] is None: self.three_d_secure_info = ThreeDSecureInfo(attributes["three_d_secure_info"]) else: self.three_d_secure_info = None @staticmethod def find(verification_id): return Configuration.gateway().verification.find(verification_id) @staticmethod def search(*query): return Configuration.gateway().verification.search(*query) @staticmethod def create(params): Resource.verify_keys(params, CreditCardVerification.create_signature()) return Configuration.gateway().verification.create(params) @staticmethod def create_signature(): billing_address_params = [ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "first_name", "last_name", "locality", "postal_code", "region", "street_address" ] credit_card_params = [ "number", "cvv", "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", {"billing_address": billing_address_params} ] external_vault_params = [ "previous_network_transaction_id", "status" ] options_params = [ "account_type", "amount", "merchant_account_id" ] risk_data_params = [ "customer_browser", "customer_ip" ] three_d_secure_pass_thru_params = [ "eci_flag", "cavv", "xid", "authentication_response", "directory_response", "cavv_algorithm", "ds_transaction_id", "three_d_secure_version" ] return [ {"credit_card": credit_card_params}, {"external_vault": external_vault_params}, "intended_transaction_source", {"options": options_params}, "payment_method_nonce", {"risk_data": risk_data_params}, "three_d_secure_authentication_id", {"three_d_secure_pass_thru": three_d_secure_pass_thru_params}] def __eq__(self, other): if not isinstance(other, CreditCardVerification): return False return self.id == other.id braintree_python-4.31.0/braintree/credit_card_verification_gateway.py000066400000000000000000000060041471021343500262260ustar00rootroot00000000000000from braintree.credit_card_verification import CreditCardVerification from braintree.credit_card_verification_search import CreditCardVerificationSearch from braintree.exceptions.not_found_error import NotFoundError from braintree.ids_search import IdsSearch from braintree.resource_collection import ResourceCollection from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult class CreditCardVerificationGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def find(self, verification_id): try: if verification_id is None or verification_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/verifications/" + verification_id) return CreditCardVerification(self.gateway, response["verification"]) except NotFoundError: raise NotFoundError("Verification with id " + repr(verification_id) + " not found") def __criteria(self, query): criteria = {} for term in query: if criteria.get(term.name): criteria[term.name] = dict(list(criteria[term.name].items()) + list(term.to_param().items())) else: criteria[term.name] = term.to_param() return criteria def __fetch(self, query, ids): criteria = self.__criteria(query) criteria["ids"] = CreditCardVerificationSearch.ids.in_list(ids).to_param() response = self.config.http().post(self.config.base_merchant_path() + "/verifications/advanced_search", {"search": criteria}) return [CreditCardVerification(self.gateway, item) for item in ResourceCollection._extract_as_array(response["credit_card_verifications"], "verification")] def search(self, *query): if isinstance(query[0], list): query = query[0] response = self.config.http().post(self.config.base_merchant_path() + "/verifications/advanced_search_ids", {"search": self.__criteria(query)}) return ResourceCollection(query, response, self.__fetch) def __fetch_verifications(self, query, verification_ids): criteria = {} criteria["ids"] = IdsSearch.ids.in_list(verification_ids).to_param() response = self.config.http().post(self.config.base_merchant_path() + "/verifications/advanced_search", {"search": criteria}) return [CreditCardVerification(self.gateway, item) for item in ResourceCollection._extract_as_array(response["credit_card_verifications"], "verification")] def create(self, params): response = self.config.http().post(self.config.base_merchant_path() + "/verifications", {"verification": params}) if "verification" in response: return SuccessfulResult({"verification": CreditCardVerification(self.gateway, response["verification"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) braintree_python-4.31.0/braintree/credit_card_verification_search.py000066400000000000000000000025031471021343500260320ustar00rootroot00000000000000from 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") payment_method_token = Search.TextNodeBuilder("payment_method_token") braintree_python-4.31.0/braintree/customer.py000066400000000000000000000260731471021343500213510ustar00rootroot00000000000000import 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.sepa_direct_debit_account import SepaDirectDebitAccount from braintree.europe_bank_account import EuropeBankAccount from braintree.us_bank_account import UsBankAccount from braintree.venmo_account import VenmoAccount from braintree.visa_checkout_card import VisaCheckoutCard from braintree.masterpass_card import MasterpassCard from braintree.address import Address from braintree.configuration import Configuration from braintree.ids_search import IdsSearch from braintree.exceptions.not_found_error import NotFoundError from braintree.resource_collection import ResourceCollection # NEXT_MAJOR_VERSION remove SamsungPayCard from braintree.samsung_pay_card import SamsungPayCard class Customer(Resource): """ A class representing a customer. An example of creating an customer with all available fields:: result = braintree.Customer.create({ "company": "Some company", "credit_card": { "billing_address": { "company": "Braintree", "country_name": "United States of America", "extended_address": "Unit 1", "first_name": "John", "international_phone": { "country_code": "1", "national_number": "3121234567" }, "last_name": "Doe", "locality": "Chicago", "phone_number": "312-123-4567", "postal_code": "60606", "region": "IL", "street_address": "111 First Street" }, "cardholder_name": "John Doe", "cvv": "123", "expiration_date": "12/2012", "number": "4111111111111111", "options": { "verification_amount": "2.00", "verify_card": True }, "token": "my_token" }, "custom_fields": { "my_key": "some value" }, "email": "john.doe@example.com", "fax": "123-555-1212", "first_name": "John", "id": "my_customer_id", "international_phone": { "country_code": "1", "national_number": "3121234567" }, "last_name": "Doe", "phone": "123-555-1221", "website": "http://www.example.com" }) print(result.customer.id) print(result.customer.first_name) For more information on Customers, see https://developer.paypal.com/braintree/docs/reference/request/customer/create/python """ def __repr__(self): detail_list = [ "company", "created_at", "email", "fax", "first_name", "graphql_id", "id", "international_phone", "last_name", "merchant_id", "phone", "updated_at", "website" ] return super(Customer, self).__repr__(detail_list) @staticmethod def all(): """ Return a collection of all customers. """ return Configuration.gateway().customer.all() @staticmethod def create(params=None): """ Create a Customer No field is required:: result = braintree.Customer.create({ "company": "Some company", "first_name": "John" }) """ if params is None: params = {} return Configuration.gateway().customer.create(params) @staticmethod def delete(customer_id): """ Delete a customer Given a customer_id:: result = braintree.Customer.delete("my_customer_id") """ return Configuration.gateway().customer.delete(customer_id) @staticmethod def find(customer_id, association_filter_id=None): """ Find an customer, given a customer_id. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided customer_id is not found. :: customer = braintree.Customer.find("my_customer_id") """ return Configuration.gateway().customer.find(customer_id, association_filter_id) @staticmethod def search(*query): return Configuration.gateway().customer.search(*query) @staticmethod def update(customer_id, params=None): """ Update an existing Customer By customer_id. The params are similar to create:: result = braintree.Customer.update("my_customer_id", { "last_name": "Smith" }) """ if params is None: params = {} return Configuration.gateway().customer.update(customer_id, params) @staticmethod def create_signature(): return [ "company", "email", "fax", "first_name", "id", {"international_phone": ["country_code", "national_number"]}, "last_name", "phone", "website", "device_data", "payment_method_nonce", "device_session_id", "fraud_merchant_id", # NEXT_MAJOR_VERSION remove device_session_id and fraud_merchant_id {"risk_data": ["customer_browser", "customer_device_id", "customer_ip", "customer_location_zip", "customer_tenure"]}, {"credit_card": CreditCard.create_signature()}, {"apple_pay_card": ApplePayCard.signature()}, {"android_pay_card": AndroidPayCard.card_signature()}, {"android_pay_network_token": AndroidPayCard.network_token_signature()}, {"custom_fields": ["__any_key__"]}, {"three_d_secure_pass_thru": [ "cavv", "ds_transaction_id", "eci_flag", "three_d_secure_version", "xid", ]}, {"tax_identifiers": ["country_code", "identifier"]}, {"options": [{"paypal": [ "payee_email", "order_id", "custom_field", "description", "amount", { "shipping": Address.create_signature() } ]}]}, ] @staticmethod def update_signature(): return [ "company", "email", "fax", "first_name", "id", {"international_phone": ["country_code", "national_number"]}, "last_name", "phone", "website", "device_data", "device_session_id", "fraud_merchant_id", "payment_method_nonce", "default_payment_method_token", {"credit_card": CreditCard.signature("update_via_customer")}, {"apple_pay_card": ApplePayCard.signature()}, {"android_pay_card": AndroidPayCard.card_signature()}, {"android_pay_network_token": AndroidPayCard.network_token_signature()}, {"three_d_secure_pass_thru": [ "cavv", "ds_transaction_id", "eci_flag", "three_d_secure_version", "xid", ]}, {"custom_fields": ["__any_key__"]}, {"tax_identifiers": ["country_code", "identifier"]}, {"options": [{"paypal": [ "payee_email", "order_id", "custom_field", "description", "amount", { "shipping": Address.create_signature() } ]}]}, ] def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.payment_methods = [] if "credit_cards" in attributes: self.credit_cards = [CreditCard(gateway, credit_card) for credit_card in self.credit_cards] self.payment_methods += self.credit_cards if "addresses" in attributes: self.addresses = [Address(gateway, address) for address in self.addresses] if "paypal_accounts" in attributes: self.paypal_accounts = [PayPalAccount(gateway, paypal_account) for paypal_account in self.paypal_accounts] self.payment_methods += self.paypal_accounts if "apple_pay_cards" in attributes: self.apple_pay_cards = [ApplePayCard(gateway, apple_pay_card) for apple_pay_card in self.apple_pay_cards] self.payment_methods += self.apple_pay_cards if "android_pay_cards" in attributes: self.android_pay_cards = [AndroidPayCard(gateway, android_pay_card) for android_pay_card in self.android_pay_cards] self.payment_methods += self.android_pay_cards # NEXT_MAJOR_VERSION remove deprecated amex express checkout 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 "venmo_accounts" in attributes: self.venmo_accounts = [VenmoAccount(gateway, venmo_account) for venmo_account in self.venmo_accounts] self.payment_methods += self.venmo_accounts if "sepa_debit_accounts" in attributes: self.sepa_direct_debit_accounts = [SepaDirectDebitAccount(gateway, sepa_direct_debit_account) for sepa_direct_debit_account in self.sepa_debit_accounts] self.payment_methods += self.sepa_direct_debit_accounts if "us_bank_accounts" in attributes: self.us_bank_accounts = [UsBankAccount(gateway, us_bank_account) for us_bank_account in self.us_bank_accounts] self.payment_methods += self.us_bank_accounts if "visa_checkout_cards" in attributes: self.visa_checkout_cards = [VisaCheckoutCard(gateway, visa_checkout_card) for visa_checkout_card in self.visa_checkout_cards] self.payment_methods += self.visa_checkout_cards # NEXT_MAJOR_VERSION remove deprecated masterpass if "masterpass_cards" in attributes: self.masterpass_cards = [MasterpassCard(gateway, masterpass_card) for masterpass_card in self.masterpass_cards] self.payment_methods += self.masterpass_cards # NEXT_MAJOR_VERSION remove all deprecated SamsungPayCard if "samsung_pay_cards" in attributes: self.samsung_pay_cards = [SamsungPayCard(gateway, samsung_pay_card) for samsung_pay_card in self.samsung_pay_cards] self.payment_methods += self.samsung_pay_cards braintree_python-4.31.0/braintree/customer_gateway.py000066400000000000000000000103411471021343500230610ustar00rootroot00000000000000import braintree import warnings 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 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 create(self, params=None): if params is None: params = {} Resource.verify_keys(params, Customer.create_signature()) self.__check_for_deprecated_attributes(params) return self._post("/customers", {"customer": params}) def delete(self, customer_id): self.config.http().delete(self.config.base_merchant_path() + "/customers/" + customer_id) return SuccessfulResult() def find(self, customer_id, association_filter_id=None): try: if customer_id is None or customer_id.strip() == "": raise NotFoundError() query_params = "" if association_filter_id: query_params = "?association_filter_id=" + association_filter_id response = self.config.http().get(self.config.base_merchant_path() + "/customers/" + customer_id + query_params) return Customer(self.gateway, response["customer"]) except NotFoundError: raise NotFoundError("customer with id " + repr(customer_id) + " not found") def search(self, *query): if isinstance(query[0], list): query = query[0] response = self.config.http().post(self.config.base_merchant_path() + "/customers/advanced_search_ids", {"search": self.__criteria(query)}) return ResourceCollection(query, response, self.__fetch) def update(self, customer_id, params=None): if params is None: params = {} Resource.verify_keys(params, Customer.update_signature()) self.__check_for_deprecated_attributes(params) 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=None): if params is None: 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 def __check_for_deprecated_attributes(self, params): if "device_session_id" in params.keys(): warnings.warn("device_session_id is deprecated, use device_data parameter instead", DeprecationWarning) if "fraud_merchant_id" in params.keys(): warnings.warn("fraud_merchant_id is deprecated, use device_data parameter instead", DeprecationWarning) braintree_python-4.31.0/braintree/customer_search.py000066400000000000000000000041421471021343500226670ustar00rootroot00000000000000from 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-4.31.0/braintree/descriptor.py000066400000000000000000000002471471021343500216610ustar00rootroot00000000000000from braintree.resource import Resource class Descriptor(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-4.31.0/braintree/disbursement.py000066400000000000000000000020511471021343500222020ustar00rootroot00000000000000from decimal import Decimal from braintree.resource import Resource from braintree.transaction_search import TransactionSearch from braintree.merchant_account import MerchantAccount class Disbursement(Resource): class Type(object): """ """ Credit = "credit" Debit = "debit" def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.amount = Decimal(self.amount) self.merchant_account = MerchantAccount(gateway, attributes["merchant_account"]) def __repr__(self): detail_list = ["amount", "disbursement_date", "exception_message", "follow_up_action", "id", "success", "retry"] return super(Disbursement, self).__repr__(detail_list) def transactions(self): return self.gateway.transaction.search([TransactionSearch.ids.in_list(self.transaction_ids)]) def is_credit(self): return self.disbursement_type == Disbursement.Type.Credit def is_debit(self): return self.disbursement_type == Disbursement.Type.Debit braintree_python-4.31.0/braintree/disbursement_detail.py000066400000000000000000000011541471021343500235270ustar00rootroot00000000000000from decimal import Decimal from braintree.attribute_getter import AttributeGetter class DisbursementDetail(AttributeGetter): def __init__(self, attributes): AttributeGetter.__init__(self, attributes) if getattr(self, "settlement_amount", None) is not None: self.settlement_amount = Decimal(self.settlement_amount) if getattr(self, "settlement_currency_exchange_rate", None) 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-4.31.0/braintree/discount.py000066400000000000000000000003321471021343500213260ustar00rootroot00000000000000from braintree.modification import Modification from braintree.configuration import Configuration class Discount(Modification): @staticmethod def all(): return Configuration.gateway().discount.all() braintree_python-4.31.0/braintree/discount_gateway.py000066400000000000000000000010311471021343500230440ustar00rootroot00000000000000import 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-4.31.0/braintree/dispute.py000066400000000000000000000235061471021343500211630ustar00rootroot00000000000000import warnings from decimal import Decimal from braintree.attribute_getter import AttributeGetter from braintree.transaction_details import TransactionDetails from braintree.dispute_details import DisputeEvidence, DisputeStatusHistory, DisputePayPalMessage from braintree.configuration import Configuration class Dispute(AttributeGetter): # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class Status(object): """ Constants representing dispute statuses. Available types are: * braintree.Dispute.Status.Accepted * braintree.Dispute.Status.AutoAccepted * braintree.Dispute.Status.Disputed * braintree.Dispute.Status.Expired * braintree.Dispute.Status.Lost * braintree.Dispute.Status.Open * braintree.Dispute.Status.UnderReview * braintree.Dispute.Status.Won """ Accepted = "accepted" AutoAccepted = "auto_accepted" Disputed = "disputed" Expired = "expired" Lost = "lost" Open = "open" UnderReview = "under_review" Won = "won" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ 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" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ 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" # NEXT_MAJOR_VERSION Remove this enum class ChargebackProtectionLevel(object): """ Constants representing dispute ChargebackProtectionLevel. Available types are: * braintree.Dispute.ChargebackProtectionLevel.EFFORTLESS * braintree.Dispute.ChargebackProtectionLevel.STANDARD * braintree.Dispute.ChargebackProtectionLevel.NOT_PROTECTED """ warnings.warn("Use ProtectionLevel enum instead", DeprecationWarning) Effortless = "effortless" Standard = "standard" NotProtected = "not_protected" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class PreDisputeProgram(object): """ Constants representing dispute pre-dispute programs. Available types are: * braintree.Dispute.PreDisputeProgram.NONE * braintree.Dispute.PreDisputeProgram.VisaRdr """ NONE = "none" VisaRdr = "visa_rdr" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class ProtectionLevel(object): """ Constants representing dispute ProtectionLevel. Available types are: * braintree.Dispute.ProtectionLevel.EffortlessCBP * braintree.Dispute.ProtectionLevel.StandardCBP * braintree.Dispute.ProtectionLevel.NoProtection """ EffortlessCBP = "Effortless Chargeback Protection tool" StandardCBP = "Chargeback Protection tool" NoProtection = "No Protection" @staticmethod def accept(id): """ Accept a dispute, given a dispute_id. This will raise a :class:`NotFoundError ` if the provided dispute_id is not found. :: result = braintree.Dispute.accept("my_dispute_id") """ return Configuration.gateway().dispute.accept(id) @staticmethod def add_file_evidence(dispute_id, document_upload_id): """ Adds file evidence to a dispute, given a dispute_id and a document_upload_id. This will raise a :class:`NotFoundError ` if the provided dispute_id is not found. :: document = braintree.DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": open("/path/to/evidence.pdf", "rb") }) result = braintree.Dispute.add_file_evidence("my_dispute_id", document.id) """ return Configuration.gateway().dispute.add_file_evidence(dispute_id, document_upload_id) @staticmethod def add_text_evidence(id, content_or_request): """ Adds text evidence to a dispute, given a dispute_id. This will raise a :class:`NotFoundError ` if the provided dispute_id is not found. :: result = braintree.Dispute.add_text_evidence("my_dispute_id", "my_evidence") or result = braintree.Dispute.add_text_evidence("my_dispute_id", { "content": "UPS", "tag": "CARRIER_NAME", "sequence_number": "1" }) """ return Configuration.gateway().dispute.add_text_evidence(id, content_or_request) @staticmethod def finalize(id): """ Finalize a dispute, given a dispute_id. This will raise a :class:`NotFoundError ` if the provided dispute_id is not found. :: result = braintree.Dispute.finalize("my_dispute_id") """ return Configuration.gateway().dispute.finalize(id) @staticmethod def find(id): """ Find an dispute, given a dispute_id. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided dispute_id is not found. :: dispute = braintree.Dispute.find("my_dispute_id") """ return Configuration.gateway().dispute.find(id) @staticmethod def remove_evidence(id, evidence_id): """ Remove evidence on a dispute. This will raise a :class:`NotFoundError ` if the provided dispute_id or evidence_id is not found. :: result = braintree.Dispute.remove_evidence("my_dispute_id", "my_evidence_id") """ return Configuration.gateway().dispute.remove_evidence(id, evidence_id) @staticmethod def search(*query): """ Searches for disputes, given a DisputeSearch query. collection = braintree.Dispute.search([ braintree.DisputeSearch.id == "the_dispute_id" ]) for dispute in collection.items: print dispute.id """ return Configuration.gateway().dispute.search(*query) def __init__(self, attributes): if "chargeback_protection_level" in attributes: warnings.warn("Use protection_level attribute instead", DeprecationWarning) AttributeGetter.__init__(self, attributes) if "amount" in attributes and getattr(self, "amount", None) is not None: self.amount = Decimal(self.amount) if "amount_disputed" in attributes and getattr(self, "amount_disputed", None) is not None: self.amount_disputed = Decimal(self.amount_disputed) if "amount_won" in attributes and getattr(self, "amount_won", None) is not None: self.amount_won = Decimal(self.amount_won) if "chargeback_protection_level" in attributes and getattr(self, "chargeback_protection_level", None) in [self.ChargebackProtectionLevel.Effortless, self.ChargebackProtectionLevel.Standard]: self.protection_level = eval("self.ProtectionLevel.{0}CBP".format(self.chargeback_protection_level.capitalize())) else: self.protection_level = self.ProtectionLevel.NoProtection if "transaction" in attributes: self.transaction_details = TransactionDetails(attributes.pop("transaction")) self.transaction = self.transaction_details if "evidence" in attributes and getattr(self, "evidence", None) is not None: self.evidence = [DisputeEvidence(evidence) for evidence in self.evidence] if "paypal_messages" in attributes and getattr(self, "paypal_messages", None) is not None: self.paypal_messages = [DisputePayPalMessage(paypal_message) for paypal_message in self.paypal_messages] if "status_history" in attributes and getattr(self, "status_history", None) is not None: self.status_history = [DisputeStatusHistory(status_history) for status_history in self.status_history] if "processor_comments" in attributes and self.processor_comments is not None: self.forwarded_comments = self.processor_comments braintree_python-4.31.0/braintree/dispute_details/000077500000000000000000000000001471021343500223105ustar00rootroot00000000000000braintree_python-4.31.0/braintree/dispute_details/__init__.py000066400000000000000000000003231471021343500244170ustar00rootroot00000000000000from braintree.dispute_details.evidence import DisputeEvidence from braintree.dispute_details.paypal_message import DisputePayPalMessage from braintree.dispute_details.status_history import DisputeStatusHistory braintree_python-4.31.0/braintree/dispute_details/evidence.py000066400000000000000000000003561471021343500244500ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class DisputeEvidence(AttributeGetter): def __init__(self, attributes): attributes["tag"] = attributes.get("category") AttributeGetter.__init__(self, attributes) braintree_python-4.31.0/braintree/dispute_details/paypal_message.py000066400000000000000000000002741471021343500256570ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class DisputePayPalMessage(AttributeGetter): def __init__(self, attributes): AttributeGetter.__init__(self, attributes) braintree_python-4.31.0/braintree/dispute_details/status_history.py000066400000000000000000000002741471021343500257710ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class DisputeStatusHistory(AttributeGetter): def __init__(self, attributes): AttributeGetter.__init__(self, attributes) braintree_python-4.31.0/braintree/dispute_gateway.py000066400000000000000000000155631471021343500227100ustar00rootroot00000000000000import braintree import re import warnings from braintree.dispute import Dispute from braintree.dispute_details import DisputeEvidence from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult from braintree.exceptions.not_found_error import NotFoundError from braintree.paginated_result import PaginatedResult from braintree.paginated_collection import PaginatedCollection from braintree.resource_collection import ResourceCollection class DisputeGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def accept(self, dispute_id): try: if dispute_id is None or dispute_id.strip() == "": raise NotFoundError() response = self.config.http().put(self.config.base_merchant_path() + "/disputes/" + dispute_id + "/accept") if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: return SuccessfulResult() except NotFoundError: raise NotFoundError("dispute with id " + repr(dispute_id) + " not found") def add_file_evidence(self, dispute_id, document_upload_id_or_request): request = document_upload_id_or_request if isinstance(document_upload_id_or_request, dict) else { "document_id": document_upload_id_or_request } try: if dispute_id is None or dispute_id.strip() == "": raise NotFoundError() if request.get("category") is not None and not isinstance(request["category"], str): raise ValueError("category must be a string") if request.get("document_id") is None or request["document_id"].strip() == "": raise ValueError("document_id cannot be blank") response = self.config.http().post(self.config.base_merchant_path() + "/disputes/" + dispute_id + "/evidence", { "evidence": { "document_upload_id": request.get("document_id"), "category": request.get("category") } }) if "evidence" in response: return SuccessfulResult({ "evidence": DisputeEvidence(response["evidence"]) }) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) except NotFoundError: raise NotFoundError("dispute with id " + repr(dispute_id) + " not found") def add_text_evidence(self, dispute_id, content_or_request): request = content_or_request if isinstance(content_or_request, dict) else { "content": content_or_request } if dispute_id is None or dispute_id.strip() == "": raise NotFoundError("dispute_id cannot be blank") if request.get("content") is None or request["content"].strip() == "": raise ValueError("content cannot be blank") try: if request.get("sequence_number") is not None: request["sequence_number"] = int(request["sequence_number"]) except ValueError: raise ValueError("sequence_number must be an integer") if request.get("category") is not None and not isinstance(request.get("category"), str): raise ValueError("category must be a string") try: response = self.config.http().post(self.config.base_merchant_path() + "/disputes/" + dispute_id + "/evidence", { "evidence": { "comments": request.get("content"), "category": request.get("category"), "sequence_number": request.get("sequence_number") } }) if "evidence" in response: return SuccessfulResult({ "evidence": DisputeEvidence(response["evidence"]) }) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) except NotFoundError: raise NotFoundError("Dispute with ID " + repr(dispute_id) + " not found") def finalize(self, dispute_id): try: if dispute_id is None or dispute_id.strip() == "": raise NotFoundError() response = self.config.http().put(self.config.base_merchant_path() + "/disputes/" + dispute_id + "/finalize") if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: return SuccessfulResult() except NotFoundError: raise NotFoundError("dispute with id " + repr(dispute_id) + " not found") def find(self, dispute_id): try: if dispute_id is None or dispute_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/disputes/" + dispute_id) return Dispute(response["dispute"]) except NotFoundError: raise NotFoundError("dispute with id " + repr(dispute_id) + " not found") def remove_evidence(self, dispute_id, evidence_id): try: if dispute_id is None or dispute_id.strip() == "": raise NotFoundError() if evidence_id is None or evidence_id.strip() == "": raise NotFoundError() response = self.config.http().delete(self.config.base_merchant_path() + "/disputes/" + dispute_id + "/evidence/" + evidence_id) if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: return SuccessfulResult() except NotFoundError: raise NotFoundError("evidence with id " + repr(evidence_id) + " for dispute with id " + repr(dispute_id) + " not found") def search(self, *query): if isinstance(query[0], list): query = query[0] self.search_criteria = self.__criteria(query) pc = PaginatedCollection(self.__fetch_disputes) return SuccessfulResult({"disputes": pc}) def __fetch_disputes(self, page): response = self.config.http().post(self.config.base_merchant_path() + "/disputes/advanced_search?page=" + str(page), {"search": self.search_criteria}) body = response["disputes"] disputes = [Dispute(item) for item in ResourceCollection._extract_as_array(response["disputes"], "dispute")] return PaginatedResult(body["total_items"], body["page_size"], disputes) def __criteria(self, query): criteria = {} for term in query: if criteria.get(term.name): criteria[term.name] = dict(list(criteria[term.name].items()) + list(term.to_param().items())) else: criteria[term.name] = term.to_param() return criteria braintree_python-4.31.0/braintree/dispute_search.py000066400000000000000000000034301471021343500225020ustar00rootroot00000000000000from braintree.search import Search class DisputeSearch: amount_disputed = Search.RangeNodeBuilder("amount_disputed") amount_won = Search.RangeNodeBuilder("amount_won") case_number = Search.TextNodeBuilder("case_number") # NEXT_MAJOR_VERSION Remove this attribute # DEPRECATED The chargeback_protection_level attribute is deprecated in favor of protection_level chargeback_protection_level = Search.MultipleValueNodeBuilder("chargeback_protection_level") protection_level = Search.MultipleValueNodeBuilder("protection_level") customer_id = Search.TextNodeBuilder("customer_id") disbursement_date = Search.RangeNodeBuilder("disbursement_date") effective_date = Search.RangeNodeBuilder("effective_date") id = Search.TextNodeBuilder("id") kind = Search.MultipleValueNodeBuilder("kind") merchant_account_id = Search.MultipleValueNodeBuilder("merchant_account_id") pre_dispute_program = Search.MultipleValueNodeBuilder("pre_dispute_program") reason = Search.MultipleValueNodeBuilder("reason") reason_code = Search.MultipleValueNodeBuilder("reason_code") received_date = Search.RangeNodeBuilder("received_date") reference_number = Search.TextNodeBuilder("reference_number") reply_by_date = Search.RangeNodeBuilder("reply_by_date") status = Search.MultipleValueNodeBuilder("status") transaction_id = Search.TextNodeBuilder("transaction_id") transaction_source = Search.MultipleValueNodeBuilder("transaction_source") braintree_python-4.31.0/braintree/document_upload.py000066400000000000000000000026701471021343500226670ustar00rootroot00000000000000import mimetypes from braintree.successful_result import SuccessfulResult from braintree.resource import Resource from braintree.configuration import Configuration class DocumentUpload(Resource): """ A class representing a DocumentUpload. An example of creating a document upload with all available fields: result = braintree.DocumentUpload.create( { "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": open("path/to/file", "rb"), } ) For more information on DocumentUploads, see https://developer.paypal.com/braintree/docs/reference/request/document-upload/create """ class Kind(object): EvidenceDocument = "evidence_document" @staticmethod def create(params=None): """ Create a DocumentUpload File and Kind are required: result = braintree.DocumentUpload.create( { "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": open("path/to/file", "rb"), } ) """ if params is None: params = {} return Configuration.gateway().document_upload.create(params) @staticmethod def create_signature(): return [ "kind", "file", ] def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-4.31.0/braintree/document_upload_gateway.py000066400000000000000000000026751471021343500244150ustar00rootroot00000000000000import braintree import mimetypes from braintree.document_upload import DocumentUpload from braintree.error_result import ErrorResult from braintree.resource import Resource from braintree.successful_result import SuccessfulResult class DocumentUploadGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create(self, params=None): if params is None: params = {} Resource.verify_keys(params, DocumentUpload.create_signature()) if "file" in params and not hasattr(params["file"], "read"): raise ValueError("file must be a file handle") response = self.config.http().post_multipart(self.config.base_merchant_path() + "/document_uploads", *self.__payload(params)) if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: return SuccessfulResult({"document_upload": DocumentUpload(self, response["document_upload"])}) def __file_name(self, file): return file.name.split("/")[-1] def __content_type(self, file): return mimetypes.guess_type(file.name)[0] def __payload(self, params): file = params.pop("file", None) files = { "file": (self.__file_name(file), file, self.__content_type(file)) } params["document_upload[kind]"] = params["kind"] return (files, params) braintree_python-4.31.0/braintree/enriched_customer_data.py000066400000000000000000000006211471021343500241720ustar00rootroot00000000000000from braintree.resource import Resource from braintree.venmo_profile_data import VenmoProfileData class EnrichedCustomerData(Resource): """ A class representing Braintree EnrichedCustomerData object. """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.profile_data = VenmoProfileData(gateway, attributes.pop("profile_data")) braintree_python-4.31.0/braintree/environment.py000066400000000000000000000062201471021343500220440ustar00rootroot00000000000000import os import inspect from braintree.exceptions.configuration_error import ConfigurationError class Environment(object): """ A class representing which environment the client library is using. Pass in one of the following values as the first argument to :class:`braintree.Configuration.configure() ` :: braintree.Environment.Sandbox braintree.Environment.Production """ def __init__(self, name, server, port, auth_url, is_ssl, ssl_certificate, graphql_server="", graphql_port=""): self.__name__ = name self.__server = server self.__port = port self.is_ssl = is_ssl self.ssl_certificate = ssl_certificate self.__auth_url = auth_url self.__graphql_server = graphql_server self.__graphql_port = graphql_port @property def base_url(self): return "%s%s:%s" % (self.protocol, self.server, self.port) @property def port(self): return int(self.__port) @property def auth_url(self): return self.__auth_url @property def protocol(self): return self.__port == "443" and "https://" or "http://" @property def server(self): return self.__server @property def server_and_port(self): return self.__server + ":" + self.__port @property def graphql_server(self): return self.__graphql_server @property def graphql_port(self): return self.__graphql_port @property def graphql_server_and_port(self): return self.__graphql_server + ":" + self.__graphql_port @staticmethod def parse_environment(environment): if isinstance(environment, Environment) or environment is None: return environment try: return Environment.All[environment] except KeyError as e: raise ConfigurationError("Unable to process supplied environment") @staticmethod def braintree_root(): return os.path.dirname(inspect.getfile(Environment)) def __str__(self): return self.__name__ Environment.Development = Environment("development", "localhost", os.getenv("GATEWAY_PORT") or "3000", "http://auth.venmo.dev:9292", False, None, "graphql.bt.local", "8080") Environment.QA = Environment("qa", "gateway.qa.braintreepayments.com", "443", "http://auth.qa.venmo.com", True, Environment.braintree_root() + "/ssl/api_braintreegateway_com.ca.crt", "payments-qa.dev.braintree-api.com", "443") Environment.Sandbox = Environment("sandbox", "api.sandbox.braintreegateway.com", "443", "https://auth.sandbox.venmo.com", True, Environment.braintree_root() + "/ssl/api_braintreegateway_com.ca.crt", "payments.sandbox.braintree-api.com", "443") Environment.Production = Environment("production", "api.braintreegateway.com", "443", "https://auth.venmo.com", True, Environment.braintree_root() + "/ssl/api_braintreegateway_com.ca.crt", "payments.braintree-api.com", "443") Environment.All = { "development": Environment.Development, "integration": Environment.Development, "qa": Environment.QA, "sandbox": Environment.Sandbox, "production": Environment.Production } braintree_python-4.31.0/braintree/error_codes.py000066400000000000000000001045171471021343500220160ustar00rootroot00000000000000class 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" ExtendedAddressIsInvalid = "91823" ExtendedAddressIsTooLong = "81804" FirstNameIsInvalid = "91819" FirstNameIsTooLong = "81805" InconsistentCountry = "91815" IsInvalid = "91828" LastNameIsInvalid = "91820" LastNameIsTooLong = "81806" LocalityIsInvalid = "91824" LocalityIsTooLong = "81807" PostalCodeInvalidCharacters = "81813" PostalCodeIsInvalid = "91826" PostalCodeIsRequired = "81808" PostalCodeIsRequiredForCardBrandAndProcessor = "81828" PostalCodeIsTooLong = "81809" RegionIsInvalid = "91825" RegionIsTooLong = "81810" StateIsInvalidForSellerProtection = "81827" StreetAddressIsInvalid = "91822" StreetAddressIsRequired = "81811" StreetAddressIsTooLong = "81812" TooManyAddressesPerCustomer = "91818" class AndroidPay(object): AndroidPayCardsAreNotAccepted = "83708" 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" CustomerIdIsInvalid = "93528" BillingAddressFormatIsInvalid = "93529" class AuthorizationFingerprint(object): MissingFingerprint = "93201" InvalidFormat = "93202" SignatureRevoked = "93203" InvalidCreatedAt = "93204" InvalidPublicKey = "93205" InvalidSignature = "93206" OptionsNotAllowedWithoutCustomer = "93207" class ClientToken(object): CustomerDoesNotExist = "92804" FailOnDuplicatePaymentMethodRequiresCustomerId = "92803" FailOnDuplicatePaymentMethodForCustomerRequiresCustomerId = "92805" InvalidDomainFormat = "92011" MakeDefaultRequiresCustomerId = "92801" MerchantAccountDoesNotExist = "92807" ProxyMerchantDoesNotExist = "92805" TooManyDomains = "92810" UnsupportedVersion = "92806" VerifyCardRequiresCustomerId = "92802" 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" DuplicateCardExistsForCustomer = "81763" ExpirationDateConflict = "91708" ExpirationDateIsInvalid = "81710" ExpirationDateIsRequired = "81709" ExpirationDateYearIsInvalid = "81711" ExpirationMonthIsInvalid = "81712" ExpirationYearIsInvalid = "81713" InvalidParamsForCreditCardUpdate = "91745" InvalidVenmoSDKPaymentMethodCode = "91727" # NEXT_MJOR_VERSION remove this code LimitExceededforDuplicatePaymentMethodCheckForCustomer = "81764" NetworkTokenizationAttributeCryptogramIsRequired = "81762" NumberHasInvalidLength = NumberLengthIsInvalid = "81716" NumberIsInvalid = "81715" NumberIsProhibited = "81750" NumberIsRequired = "81714" NumberMustBeTestNumber = "81717" PaymentMethodConflict = "81725" PaymentMethodIsNotACreditCard = "91738" PaymentMethodNonceCardTypeIsNotAccepted = "91734" PaymentMethodNonceCardTypeIsNotAccepted = "91734" PaymentMethodNonceConsumed = "91731" PaymentMethodNonceConsumed = "91731" PaymentMethodNonceLocked = "91733" PaymentMethodNonceLocked = "91733" PaymentMethodNonceUnknown = "91732" PaymentMethodNonceUnknown = "91732" PostalCodeVerificationFailed = "81737" TokenInvalid = TokenFormatIsInvalid = "91718" TokenIsInUse = "91719" TokenIsNotAllowed = "91721" TokenIsRequired = "91722" TokenIsTooLong = "91720" VenmoSDKPaymentMethodCodeCardTypeIsNotAccepted = "91726" # NEXT_MJOR_VERSION remove this code VerificationNotSupportedOnThisMerchantAccount = "91730" VerificationAccountTypeIsInvald = "91757" VerificationAccountTypeNotSupported = "91758" class Options(object): UpdateExistingTokenIsInvalid = "91723" UpdateExistingTokenNotAllowed = "91729" VerificationAmountCannotBeNegative = "91739" VerificationAmountFormatIsInvalid = "91740" VerificationAmountIsTooLarge = "91752" VerificationAmountNotSupportedByProcessor = "91741" VerificationMerchantAccountIdIsInvalid = "91728" VerificationMerchantAccountIsForbidden = "91743" VerificationMerchantAccountIsSuspended = "91742" VerificationMerchantAccountCannotBeSubMerchantAccount = "91755" class Customer(object): CompanyIsTooLong = "81601" CustomFieldIsInvalid = "91602" CustomFieldIsTooLong = "81603" EmailIsInvalid = EmailFormatIsInvalid = "81604" EmailIsRequired = "81606" EmailIsTooLong = "81605" FaxIsTooLong = "81607" FirstNameIsTooLong = "81608" IdIsInUse = "91609" IdIsInvalid = "91610" IdIsNotAllowed = "91611" IdIsRequired = "91613" IdIsTooLong = "91612" LastNameIsTooLong = "81613" PhoneIsTooLong = "81614" VaultedPaymentInstrumentNonceBelongsToDifferentCustomer = "91617" WebsiteIsInvalid = WebsiteFormatIsInvalid = "81616" WebsiteIsTooLong = "81615" class Descriptor(object): DynamicDescriptorsDisabled = "92203" InternationalNameFormatIsInvalid = "92204" InternationalPhoneFormatIsInvalid = "92205" NameFormatIsInvalid = "92201" PhoneFormatIsInvalid = "92202" UrlFormatIsInvalid = "92206" class Dispute(object): CanOnlyAddEvidenceToOpenDispute = "95701" CanOnlyRemoveEvidenceFromOpenDispute = "95702" CanOnlyAddEvidenceDocumentToDispute = "95703" CanOnlyAcceptOpenDispute = "95704" CanOnlyFinalizeOpenDispute = "95705" CanOnlyCreateEvidenceWithValidCategory = "95706" EvidenceContentDateInvalid = "95707" EvidenceContentTooLong = "95708" EvidenceContentARNTooLong = "95709" EvidenceContentPhoneTooLong = "95710" EvidenceCategoryTextOnly = "95711" EvidenceCategoryDocumentOnly = "95712" EvidenceCategoryNotForReasonCode = "95713" EvidenceCategoryDuplicate = "95714" EvidenceContentEmailInvalid = "95715" DigitalGoodsMissingEvidence = "95720" DigitalGoodsMissingDownloadDate = "95721" NonDisputedPriorTransactionEvidenceMissingARN = "95722" NonDisputedPriorTransactionEvidenceMissingDate = "95723" RecurringTransactionEvidenceMissingDate = "95724" RecurringTransactionEvidenceMissingARN = "95725" ValidEvidenceRequiredToFinalize = "95726" class DocumentUpload(object): KindIsInvalid = "84901" FileIsTooLarge = "84902" FileTypeIsInvalid = "84903" FileIsMalformedOrEncrypted = "84904" FileIsTooLong = "84905" FileIsEmpty = "84906" class Merchant(object): CountryCannotBeBlank = "83603" CountryCodeAlpha2IsInvalid = "93607" CountryCodeAlpha2IsNotAccepted = "93606" CountryCodeAlpha3IsInvalid = "93605" CountryCodeAlpha3IsNotAccepted = "93604" CountryCodeNumericIsInvalid = "93609" CountryCodeNumericIsNotAccepted = "93608" CountryNameIsInvalid = "93611" CountryNameIsNotAccepted = "93610" CurrenciesAreInvalid = "93614" EmailFormatIsInvalid = "93602" EmailIsRequired = "83601" InconsistentCountry = "93612" PaymentMethodsAreInvalid = "93613" PaymentMethodsAreNotAllowed = "93615" MerchantAccountExistsForCurrency = "93616" CurrencyIsRequired = "93617" CurrencyIsInvalid = "93618" NoMerchantAccounts = "93619" MerchantAccountExistsForId = "93620" class MerchantAccount(object): IdFormatIsInvalid = "82603" IdIsInUse = "82604" IdIsNotAllowed = "82605" IdIsTooLong = "82602" MasterMerchantAccountIdIsInvalid = "82607" MasterMerchantAccountIdIsRequired = "82606" MasterMerchantAccountMustBeActive = "82608" TosAcceptedIsRequired = "82610" CannotBeUpdated = "82674" IdCannotBeUpdated = "82675" MasterMerchantAccountIdCannotBeUpdated = "82676" Declined = "82626" DeclinedMasterCardMatch = "82622" DeclinedOFAC = "82621" DeclinedFailedKYC = "82623" DeclinedSsnInvalid = "82624" DeclinedSsnMatchesDeceased = "82625" class ApplicantDetails(object): AccountNumberIsRequired = "82614" CompanyNameIsInvalid = "82631" CompanyNameIsRequiredWithTaxId = "82633" DateOfBirthIsRequired = "82612" Declined = "82626" # Keep for backwards compatibility DeclinedMasterCardMatch = "82622" # Keep for backwards compatibility DeclinedOFAC = "82621" # Keep for backwards compatibility DeclinedFailedKYC = "82623" # Keep for backwards compatibility DeclinedSsnInvalid = "82624" # Keep for backwards compatibility DeclinedSsnMatchesDeceased = "82625" # Keep for backwards compatibility EmailAddressIsInvalid = "82616" FirstNameIsInvalid = "82627" FirstNameIsRequired = "82609" LastNameIsInvalid = "82628" LastNameIsRequired = "82611" PhoneIsInvalid = "82636" RoutingNumberIsInvalid = "82635" RoutingNumberIsRequired = "82613" SsnIsInvalid = "82615" TaxIdIsInvalid = "82632" TaxIdIsRequiredWithCompanyName = "82634" DateOfBirthIsInvalid = "82663" EmailAddressIsRequired = "82665" AccountNumberIsInvalid = "82670" TaxIdMustBeBlank = "82673" class Address(object): LocalityIsRequired = "82618" PostalCodeIsInvalid = "82630" PostalCodeIsRequired = "82619" RegionIsRequired = "82620" StreetAddressIsInvalid = "82629" StreetAddressIsRequired = "82617" RegionIsInvalid = "82664" class Individual(object): FirstNameIsRequired = "82637" LastNameIsRequired = "82638" DateOfBirthIsRequired = "82639" SsnIsInvalid = "82642" EmailAddressIsInvalid = "82643" FirstNameIsInvalid = "82644" LastNameIsInvalid = "82645" PhoneIsInvalid = "82656" DateOfBirthIsInvalid = "82666" EmailAddressIsRequired = "82667" class Address(object): StreetAddressIsRequired = "82657" LocalityIsRequired = "82658" PostalCodeIsRequired = "82659" RegionIsRequired = "82660" StreetAddressIsInvalid = "82661" PostalCodeIsInvalid = "82662" RegionIsInvalid = "82668" class Business(object): DbaNameIsInvalid = "82646" LegalNameIsInvalid = "82677" LegalNameIsRequiredWithTaxId = "82669" TaxIdIsInvalid = "82647" TaxIdIsRequiredWithLegalName = "82648" TaxIdMustBeBlank = "82672" class Address(object): StreetAddressIsInvalid = "82685" PostalCodeIsInvalid = "82686" RegionIsInvalid = "82684" class Funding(object): RoutingNumberIsRequired = "82640" AccountNumberIsRequired = "82641" RoutingNumberIsInvalid = "82649" AccountNumberIsInvalid = "82671" DestinationIsInvalid = "82679" DestinationIsRequired = "82678" EmailAddressIsInvalid = "82681" EmailAddressIsRequired = "82680" MobilePhoneIsInvalid = "82683" MobilePhoneIsRequired = "82682" class OAuth(object): InvalidGrant = "93801" InvalidCredentials = "93802" InvalidScope = "93803" InvalidRequest = "93804" UnsupportedGrantType = "93805" class Verification(object): ThreeDSecureAuthenticationIdIsInvalid = "942196" ThreeDSecureAuthenticationIdDoesntMatchNonceThreeDSecureAuthentication = "942198" ThreeDSecureTransactionPaymentMethodDoesntMatchThreeDSecureAuthenticationPaymentMethod = "942197" ThreeDSecureAuthenticationIdWithThreeDSecurePassThruIsInvalid = "942199" ThreeDSecureAuthenticationFailed = "94271" ThreeDSecureTokenIsInvalid = "94268" ThreeDSecureVerificationDataDoesntMatchVerify = "94270" MerchantAccountDoesNotSupport3DSecure = "942169" MerchantAcountDoesNotMatch3DSecureMerchantAccount = "94284" AmountDoesNotMatch3DSecureAmount = "94285" class ThreeDSecurePassThru(object): EciFlagIsRequired = "942113" EciFlagIsInvalid = "942114" CavvIsRequired = "942116" ThreeDSecureVersionIsRequired = "942117" ThreeDSecureVersionIsInvalid = "942119" AuthenticationResponseIsInvalid = "942120" DirectoryResponseIsInvalid = "942121" CavvAlgorithmIsInvalid = "942122" class Options(object): AmountCannotBeNegative = "94201" AmountFormatIsInvalid = "94202" AmountIsTooLarge = "94207" AmountNotSupportedByProcessor = "94203" MerchantAccountIdIsInvalid = "94204" MerchantAccountIsSuspended = "94205" MerchantAccountIsForbidden = "94206" MerchantAccountCannotBeSubMerchantAccount = "94208" AccountTypeIsInvalid = "942184" AccountTypeNotSupported = "942185" class PaymentMethod(object): CannotForwardPaymentMethodType = "93106" PaymentMethodParamsAreRequired = "93101" NonceIsInvalid = "93102" NonceIsRequired = "93103" CustomerIdIsRequired = "93104" CustomerIdIsInvalid = "93105" PaymentMethodNonceConsumed = "93107" PaymentMethodNonceUnknown = "93108" PaymentMethodNonceLocked = "93109" PaymentMethodNoLongerSupported = "93117" AuthExpired = "92911" CannotHaveFundingSourceWithoutAccessToken = "92912" InvalidFundingSourceSelection = "92913" CannotUpdatePayPalAccountUsingPaymentMethodNonce = "92914" class Options(object): UsBankAccountVerificationMethodIsInvalid = "93121" class PayPalAccount(object): CannotHaveBothAccessTokenAndConsentCode = "82903" CannotVaultOneTimeUsePayPalAccount = "82902" ConsentCodeOrAccessTokenIsRequired = "82901" CustomerIdIsRequiredForVaulting = "82905" InvalidParamsForPayPalAccountUpdate = "92915" PayPalAccountsAreNotAccepted = "82904" PayPalCommunicationError = "92910" PaymentMethodNonceConsumed = "92907" PaymentMethodNonceLocked = "92909" PaymentMethodNonceUnknown = "92908" TokenIsInUse = "92906" class SettlementBatchSummary(object): CustomFieldIsInvalid = "82303" SettlementDateIsInvalid = "82302" SettlementDateIsRequired = "82301" class SEPAMandate(object): TypeIsRequired = "93304" IBANInvalidCharacter = "83305" BICInvalidCharacter = "83306" BICLengthIsInvalid = "83307" BICUnsupportedCountry = "83308" IBANUnsupportedCountry = "83309" IBANInvalidFormat = "83310" BillingAddressConflict = "93311" BillingAddressIdIsInvalid = "93312" TypeIsInvalid = "93313" class EuropeBankAccount(object): BICIsRequired = "83302" IBANIsRequired = "83303" AccountHolderNameIsRequired = "83301" class SepaDirectDebitAccount(object): SepaDebitAccountPaymentMethodMandateTypeIsNotSupported = "87115" SepaDebitAccountPaymentMethodCustomerIdIsInvalid = "87116" SepaDebitAccountPaymentMethodCustomerIdIsRequired = "87117" 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): AdjustmentAmountMustBeGreaterThanZero = "95605" AmountCannotBeNegative = "81501" AmountDoesNotMatch3DSecureAmount = "91585" AmountIsInvalid = AmountFormatIsInvalid = "81503" AmountIsRequired = "81502" AmountIsTooLarge = "81528" AmountMustBeGreaterThanZero = "81531" AmountNotSupportedByProcessor = "815193" BillingAddressConflict = "91530" BillingPhoneNumberIsInvalid = "915206" CannotBeVoided = "91504" CannotCancelRelease = "91562" CannotCloneCredit = "91543" CannotCloneMarketplaceTransaction = "915137" CannotCloneTransactionWithPayPalAccount = "91573" CannotCloneTransactionWithVaultCreditCard = "91540" CannotCloneUnsuccessfulTransaction = "91542" CannotCloneVoiceAuthorizations = "91541" CannotHoldInEscrow = "91560" CannotPartiallyRefundEscrowedTransaction = "91563" CannotRefundCredit = "91505" CannotRefundSettlingTransaction = "91574" CannotRefundUnlessSettled = "91506" CannotRefundWithPendingMerchantAccount = "91559" CannotRefundWithSuspendedMerchantAccount = "91538" CannotReleaseFromEscrow = "91561" CannotSimulateTransactionSettlement = "91575" CannotSubmitForPartialSettlement = "915103" CannotSubmitForSettlement = "91507" CannotUpdateTransactionDetailsNotSubmittedForSettlement = "915129" ChannelIsTooLong = "91550" ChannelIsTooLong = "91550" CreditCardIsRequired = "91508" CustomFieldIsInvalid = "91526" CustomFieldIsTooLong = "81527" CustomerDefaultPaymentMethodCardTypeIsNotAccepted = "81509" CustomerDoesNotHaveCreditCard = "91511" CustomerIdIsInvalid = "91510" DiscountAmountCannotBeNegative = "915160" DiscountAmountFormatIsInvalid = "915159" DiscountAmountIsTooLarge = "915161" ExchangeRateQuoteIdIsTooLong = "915229" FailedAuthAdjustmentAllowRetry = "95603" FailedAuthAdjustmentHardDecline = "95602" FinalAuthSubmitForSettlementForDifferentAmount = "95601" HasAlreadyBeenRefunded = "91512" LineItemsExpected = "915158" MerchantAccountDoesNotMatch3DSecureMerchantAccount = "91584" MerchantAccountDoesNotSupportMOTO = "91558" MerchantAccountDoesNotSupportRefunds = "91547" MerchantAccountIdDoesNotMatchSubscription = "915180" MerchantAccountIdIsInvalid = "91513" MerchantAccountIsSuspended = "91514" NoNetAmountToPerformAuthAdjustment = "95606" OrderIdIsTooLong = "91501" PayPalAuthExpired = "91579" PayPalNotEnabled = "91576" PayPalVaultRecordMissingData = "91583" PaymentInstrumentNotSupportedByMerchantAccount = "91577" PaymentInstrumentTypeIsNotAccepted = "915101" PaymentInstrumentWithExternalVaultIsInvalid = "915176" PaymentMethodConflict = "91515" PaymentMethodConflictWithVenmoSDK = "91549" # NEXT_MJOR_VERSION remove this code PaymentMethodDoesNotBelongToCustomer = "91516" PaymentMethodDoesNotBelongToSubscription = "91527" PaymentMethodNonceCardTypeIsNotAccepted = "91567" PaymentMethodNonceConsumed = "91564" PaymentMethodNonceHasNoValidPaymentInstrumentType = "91569" PaymentMethodNonceLocked = "91566" PaymentMethodNonceUnknown = "91565" PaymentMethodTokenCardTypeIsNotAccepted = "91517" PaymentMethodTokenIsInvalid = "91518" ProcessorAuthorizationCodeCannotBeSet = "91519" ProcessorAuthorizationCodeIsInvalid = "81520" ProcessorDoesNotSupportAuths = "915104" ProcessorDoesNotSupportAuthAdjustment = "915222" ProcessorDoesNotSupportCredits = "91546" ProcessorDoesNotSupportIncrementalAuth = "915220" ProcessorDoesNotSupportMotoForCardType = "915195" ProcessorDoesNotSupportPartialAuthReversal = "915221" ProcessorDoesNotSupportPartialSettlement = "915102" ProcessorDoesNotSupportUpdatingDescriptor = "915108" ProcessorDoesNotSupportUpdatingOrderId = "915107" ProcessorDoesNotSupportUpdatingTransactionDetails = "915130" ProcessorDoesNotSupportVoiceAuthorizations = "91545" ProductSkuIsInvalid = "915202" PurchaseOrderNumberIsInvalid = "91548" PurchaseOrderNumberIsTooLong = "91537" RefundAmountIsTooLarge = "91521" RefundAuthHardDeclined = "915200" RefundAuthSoftDeclined = "915201" ScaExemptionInvalid = "915213" ServiceFeeAmountCannotBeNegative = "91554" ServiceFeeAmountFormatIsInvalid = "91555" ServiceFeeAmountIsTooLarge = "91556" ServiceFeeAmountNotAllowedOnMasterMerchantAccount = "91557" ServiceFeeIsNotAllowedOnCredits = "91552" ServiceFeeNotAcceptedForPayPal = "91578" SettlementAmountIsLessThanServiceFeeAmount = "91551" SettlementAmountIsTooLarge = "91522" ShippingAddressDoesntMatchCustomer = "91581" ShippingAmountCannotBeNegative = "915163" ShippingAmountFormatIsInvalid = "915162" ShippingAmountIsTooLarge = "915164" ShippingMethodIsInvalid = "915203" ShippingPhoneNumberIsInvalid = "915204" ShipsFromPostalCodeInvalidCharacters = "915167" ShipsFromPostalCodeIsInvalid = "915166" ShipsFromPostalCodeIsTooLong = "915165" SubMerchantAccountRequiresServiceFeeAmount = "91553" SubscriptionDoesNotBelongToCustomer = "91529" SubscriptionIdIsInvalid = "91528" SubscriptionStatusMustBePastDue = "91531" TaxAmountCannotBeNegative = "81534" TaxAmountFormatIsInvalid = "81535" TaxAmountIsRequiredForAibSwedish = "815224" TaxAmountIsTooLarge = "81536" ThreeDSecureAuthenticationFailed = "81571" ThreeDSecureAuthenticationIdDoesntMatchNonceThreeDSecureAuthentication = "915198" ThreeDSecureAuthenticationIdIsInvalid = "915196" ThreeDSecureAuthenticationIdWithThreeDSecurePassThruIsInvalid = "915199" ThreeDSecureAuthenticationResponseIsInvalid = "915120" ThreeDSecureCavvAlgorithmIsInvalid = "915122" ThreeDSecureCavvIsRequired = "915116" ThreeDSecureDirectoryResponseIsInvalid = "915121" ThreeDSecureEciFlagIsInvalid = "915114" ThreeDSecureEciFlagIsRequired = "915113" ThreeDSecureMerchantAccountDoesNotSupportCardType = "915131" ThreeDSecureTokenIsInvalid = "91568" ThreeDSecureTransactionDataDoesntMatchVerify = "91570" ThreeDSecureTransactionPaymentMethodDoesntMatchThreeDSecureAuthenticationPaymentMethod = "915197" ThreeDSecureXidIsRequired = "915115" TooManyLineItems = "915157" TransactionIsNotEligibleForAdjustment = "915219" TransactionMustBeInStateAuthorized = "915218" TransactionSourceIsInvalid = "915133" TypeIsInvalid = "91523" TypeIsRequired = "91524" UnsupportedVoiceAuthorization = "91539" UsBankAccountNonceMustBePlaidVerified = "915171" UsBankAccountNotVerified = "915172" class ExternalVault(object): StatusIsInvalid = "915175" StatusWithPreviousNetworkTransactionIdIsInvalid = "915177" # NEXT_MAJOR_VERSION remove this validation error as it is no longer returned by the gateway CardTypeIsInvalid = "915178" PreviousNetworkTransactionIdIsInvalid = "915179" class Options(object): SubmitForSettlementIsRequiredForCloning = "91544" SubmitForSettlementIsRequiredForPayPalUnilateral = "91582" UseBillingForShippingDisabled = "91572" VaultIsDisabled = "91525" class PayPal(object): CustomFieldTooLong = "91580" class CreditCard(object): AccountTypeIsInvalid = "915184" AccountTypeNotSupported = "915185" AccountTypeDebitDoesNotSupportAuths = "915186" class Industry(object): IndustryTypeIsInvalid = "93401" class Lodging(object): EmptyData = "93402" FolioNumberIsInvalid = "93403" CheckInDateIsInvalid = "93404" CheckOutDateIsInvalid = "93405" CheckOutDateMustFollowCheckInDate = "93406" UnknownDataField = "93407" RoomRateMustBeGreaterThanZero = "93433" RoomRateFormatIsInvalid = "93434" RoomRateIsTooLarge = "93435" RoomTaxMustBeGreaterThanZero = "93436" RoomTaxFormatIsInvalid = "93437" RoomTaxIsTooLarge = "93438" NoShowIndicatorIsInvalid = "93439" AdvancedDepositIndicatorIsInvalid = "93440" FireSafetyIndicatorIsInvalid = "93441" PropertyPhoneIsInvalid = "93442" class TravelCruise(object): EmptyData = "93408" UnknownDataField = "93409" TravelPackageIsInvalid = "93410" DepartureDateIsInvalid = "93411" LodgingCheckInDateIsInvalid = "93412" LodgingCheckOutDateIsInvalid = "93413" class TravelFlight(object): EmptyData = "93414" UnknownDataField = "93415" CustomerCodeIsTooLong = "93416" FareAmountCannotBeNegative = "93417" FareAmountFormatIsInvalid = "93418" FareAmountIsTooLarge = "93419" FeeAmountCannotBeNegative = "93420" FeeAmountFormatIsInvalid = "93421" FeeAmountIsTooLarge = "93422" IssuedDateFormatIsInvalid = "93423" IssuingCarrierCodeIsTooLong = "93424" PassengerMiddleInitialIsTooLong = "93425" RestrictedTicketIsRequired = "93426" TaxAmountCannotBeNegative = "93427" TaxAmountFormatIsInvalid = "93428" TaxAmountIsTooLarge = "93429" TicketNumberIsTooLong = "93430" LegsExpected = "93431" TooManyLegs = "93432" class Leg(object): class TravelFlight(object): ArrivalAirportCodeIsTooLong = "96301" ArrivalTimeFormatIsInvalid = "96302" CarrierCodeIsTooLong = "96303" ConjunctionTicketIsTooLong = "96304" CouponNumberIsTooLong = "96305" DepartureAirportCodeIsTooLong = "96306" DepartureTimeFormatIsInvalid = "96307" ExchangeTicketIsTooLong = "96308" FareAmountCannotBeNegative = "96309" FareAmountFormatIsInvalid = "96310" FareAmountIsTooLarge = "96311" FareBasisCodeIsTooLong = "96312" FeeAmountCannotBeNegative = "96313" FeeAmountFormatIsInvalid = "96314" FeeAmountIsTooLarge = "96315" ServiceClassIsTooLong = "96316" TaxAmountCannotBeNegative = "96317" TaxAmountFormatIsInvalid = "96318" TaxAmountIsTooLarge = "96319" TicketNumberIsTooLong = "96320" class AdditionalCharge(object): KindIsInvalid = "96601" KindMustBeUnique = "96602" AmountMustBeGreaterThanZero = "96603" AmountFormatIsInvalid = "96604" AmountIsTooLarge = "96605" AmountIsRequired = "96606" class LineItem(object): CommodityCodeIsTooLong = "95801" DescriptionIsTooLong = "95803" DiscountAmountCannotBeNegative = "95806" DiscountAmountFormatIsInvalid = "95804" DiscountAmountIsTooLarge = "95805" KindIsInvalid = "95807" KindIsRequired = "95808" NameIsRequired = "95822" NameIsTooLong = "95823" ProductCodeIsTooLong = "95809" QuantityFormatIsInvalid = "95810" QuantityIsRequired = "95811" QuantityIsTooLarge = "95812" TaxAmountCannotBeNegative = "95829" TaxAmountFormatIsInvalid = "95827" TaxAmountIsTooLarge = "95828" TotalAmountFormatIsInvalid = "95813" TotalAmountIsRequired = "95814" TotalAmountIsTooLarge = "95815" TotalAmountMustBeGreaterThanZero = "95816" UPCCodeIsMissing = "95830" UPCCodeIsTooLong = "95831" UPCTypeIsInvalid = "95833" UPCTypeIsMissing = "95832" UnitAmountFormatIsInvalid = "95817" UnitAmountIsRequired = "95818" UnitAmountIsTooLarge = "95819" UnitAmountMustBeGreaterThanZero = "95820" UnitOfMeasureIsTooLarge = "95821" UnitTaxAmountCannotBeNegative = "95826" UnitTaxAmountFormatIsInvalid = "95824" UnitTaxAmountIsTooLarge = "95825" class UsBankAccountVerification(object): NotConfirmable = "96101" MustBeMicroTransfersVerification = "96102" AmountsDoNotMatch = "96103" TooManyConfirmationAttempts = "96104" UnableToConfirmDepositAmounts = "96105" InvalidDepositAmounts = "96106" class RiskData(object): # NEXT_MAJOR_VERSION Remove CustomerBrowserIsTooLong code as it is no longer used CustomerBrowserIsTooLong = "94701" CustomerDeviceIdIsTooLong = "94702" CustomerLocationZipInvalidCharacters = "94703" CustomerLocationZipIsInvalid = "94704" CustomerLocationZipIsTooLong = "94705" CustomerTenureIsTooLong = "94706" braintree_python-4.31.0/braintree/error_result.py000066400000000000000000000051101471021343500222240ustar00rootroot00000000000000import 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 "plan" in attributes: self.plan = braintree.plan.Plan(gateway, attributes["plan"]) else: self.plan = 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-4.31.0/braintree/errors.py000066400000000000000000000007121471021343500210140ustar00rootroot00000000000000from 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-4.31.0/braintree/europe_bank_account.py000066400000000000000000000015331471021343500235100ustar00rootroot00000000000000import braintree from braintree.resource import Resource from braintree.configuration import Configuration #NEXT_MAJOR_VERSION this was specific to iDEAL integrations and can be removed 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-4.31.0/braintree/exceptions/000077500000000000000000000000001471021343500213075ustar00rootroot00000000000000braintree_python-4.31.0/braintree/exceptions/__init__.py000066400000000000000000000020551471021343500234220ustar00rootroot00000000000000from braintree.exceptions.authentication_error import AuthenticationError from braintree.exceptions.authorization_error import AuthorizationError from braintree.exceptions.configuration_error import ConfigurationError from braintree.exceptions.gateway_timeout_error import GatewayTimeoutError 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.request_timeout_error import RequestTimeoutError from braintree.exceptions.server_error import ServerError from braintree.exceptions.service_unavailable_error import ServiceUnavailableError from braintree.exceptions.test_operation_performed_in_production_error import TestOperationPerformedInProductionError from braintree.exceptions.too_many_requests_error import TooManyRequestsError from braintree.exceptions.unexpected_error import UnexpectedError from braintree.exceptions.upgrade_required_error import UpgradeRequiredError braintree_python-4.31.0/braintree/exceptions/authentication_error.py000066400000000000000000000006271471021343500261160ustar00rootroot00000000000000from 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://developer.paypal.com/braintree/docs/reference/general/exceptions/python#authentication-error """ pass braintree_python-4.31.0/braintree/exceptions/authorization_error.py000066400000000000000000000005101471021343500257660ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class AuthorizationError(BraintreeError): """ Raised when the user does not have permission to complete the requested operation. See https://developer.paypal.com/braintree/docs/reference/general/exceptions/python#authorization-error """ pass braintree_python-4.31.0/braintree/exceptions/braintree_error.py000066400000000000000000000000521471021343500250420ustar00rootroot00000000000000class BraintreeError(Exception): pass braintree_python-4.31.0/braintree/exceptions/configuration_error.py000066400000000000000000000001671471021343500257450ustar00rootroot00000000000000from braintree.exceptions.unexpected_error import UnexpectedError class ConfigurationError(UnexpectedError): pass braintree_python-4.31.0/braintree/exceptions/gateway_timeout_error.py000066400000000000000000000002701471021343500263000ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class GatewayTimeoutError(BraintreeError): """ Raised when a gateway response timeout occurs. """ pass braintree_python-4.31.0/braintree/exceptions/http/000077500000000000000000000000001471021343500222665ustar00rootroot00000000000000braintree_python-4.31.0/braintree/exceptions/http/__init__.py000066400000000000000000000003321471021343500243750ustar00rootroot00000000000000from 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-4.31.0/braintree/exceptions/http/connection_error.py000066400000000000000000000001641471021343500262110ustar00rootroot00000000000000from braintree.exceptions.unexpected_error import UnexpectedError class ConnectionError(UnexpectedError): pass braintree_python-4.31.0/braintree/exceptions/http/invalid_response_error.py000066400000000000000000000001711471021343500274140ustar00rootroot00000000000000from braintree.exceptions.unexpected_error import UnexpectedError class InvalidResponseError(UnexpectedError): pass braintree_python-4.31.0/braintree/exceptions/http/timeout_error.py000066400000000000000000000003261471021343500255400ustar00rootroot00000000000000from braintree.exceptions.unexpected_error import UnexpectedError class TimeoutError(UnexpectedError): pass class ConnectTimeoutError(TimeoutError): pass class ReadTimeoutError(TimeoutError): pass braintree_python-4.31.0/braintree/exceptions/invalid_challenge_error.py000066400000000000000000000001671471021343500265260ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class InvalidChallengeError(BraintreeError): pass braintree_python-4.31.0/braintree/exceptions/invalid_signature_error.py000066400000000000000000000001671471021343500266050ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class InvalidSignatureError(BraintreeError): pass braintree_python-4.31.0/braintree/exceptions/not_found_error.py000066400000000000000000000005051471021343500250650ustar00rootroot00000000000000from 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://developer.paypal.com/braintree/docs/reference/general/exceptions/python#not-found-error """ pass braintree_python-4.31.0/braintree/exceptions/request_timeout_error.py000066400000000000000000000002661471021343500263340ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class RequestTimeoutError(BraintreeError): """ Raised when a client request timeout occurs. """ pass braintree_python-4.31.0/braintree/exceptions/server_error.py000066400000000000000000000005051471021343500244000ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class ServerError(BraintreeError): """ Raised when the gateway raises an error. Please contact support at support@getbraintree.com. See https://developer.paypal.com/braintree/docs/reference/general/exceptions/python#server-error """ pass braintree_python-4.31.0/braintree/exceptions/service_unavailable_error.py000066400000000000000000000002651471021343500271000ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class ServiceUnavailableError(BraintreeError): """ Raised when the gateway is unavailable. """ pass braintree_python-4.31.0/braintree/exceptions/test_operation_performed_in_production_error.py000066400000000000000000000003721471021343500331320ustar00rootroot00000000000000from 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-4.31.0/braintree/exceptions/too_many_requests_error.py000066400000000000000000000003041471021343500266470ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class TooManyRequestsError(BraintreeError): """ Raised when the rate limit request threshold is exceeded. """ pass braintree_python-4.31.0/braintree/exceptions/unexpected_error.py000066400000000000000000000002461471021343500252400ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class UnexpectedError(BraintreeError): """ Raised for unknown or unexpected errors. """ pass braintree_python-4.31.0/braintree/exceptions/upgrade_required_error.py000066400000000000000000000004521471021343500264220ustar00rootroot00000000000000from braintree.exceptions.braintree_error import BraintreeError class UpgradeRequiredError(BraintreeError): """ Raised for unsupported client library versions. See https://developer.paypal.com/braintree/docs/reference/general/exceptions/python#upgrade-required-error """ pass braintree_python-4.31.0/braintree/exchange_rate_quote.py000066400000000000000000000003511471021343500235110ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter from braintree.montary_amount import MontaryAmount class ExchangeRateQuote(AttributeGetter): def __init__(self,attributes): AttributeGetter.__init__(self,attributes)braintree_python-4.31.0/braintree/exchange_rate_quote_gateway.py000066400000000000000000000032161471021343500252350ustar00rootroot00000000000000from braintree.exchange_rate_quote_payload import ExchangeRateQuotePayload from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult class ExchangeRateQuoteGateway(object): def __init__(self, gateway, graphql_client = None): self.gateway = gateway self.config = gateway.config self.graphql_client = None if graphql_client is None else graphql_client def generate(self, request): definition = """ mutation ($exchangeRateQuoteRequest: GenerateExchangeRateQuoteInput!) { generateExchangeRateQuote(input: $exchangeRateQuoteRequest) { quotes { id baseAmount {value, currencyCode} quoteAmount {value, currencyCode} exchangeRate tradeRate expiresAt refreshesAt } } }""" param = request.to_graphql_variables() graphql_client = self.graphql_client if self.graphql_client is not None else self.gateway.graphql_client response = graphql_client.query(definition, param) if "data" in response and "generateExchangeRateQuote" in response["data"]: result = response["data"]["generateExchangeRateQuote"] self.exchange_rate_quote_payload = ExchangeRateQuotePayload(result) return SuccessfulResult({"exchange_rate_quote_payload": self.exchange_rate_quote_payload}) elif "errors" in response: error_codes = response["errors"][0] error_codes["errors"] = dict() return ErrorResult(self.gateway, error_codes)braintree_python-4.31.0/braintree/exchange_rate_quote_input.py000066400000000000000000000014351471021343500247340ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class ExchangeRateQuoteInput(AttributeGetter): def __init__(self,parent,attributes): self.parent = parent AttributeGetter.__init__(self,attributes) def done(self): return self.parent def to_graphql_variables(self): variables = dict() variables["baseCurrency"] = self.base_currency if getattr(self,"base_currency",None) is not None else None variables["quoteCurrency"] = self.quote_currency if getattr(self,"quote_currency",None) is not None else None variables["baseAmount"] = self.base_amount if getattr(self,"base_amount",None) is not None else None variables["markup"] = self.markup if getattr(self,"markup",None) is not None else None return variablesbraintree_python-4.31.0/braintree/exchange_rate_quote_payload.py000066400000000000000000000027251471021343500252310ustar00rootroot00000000000000from braintree.exchange_rate_quote import ExchangeRateQuote from braintree.montary_amount import MontaryAmount class ExchangeRateQuotePayload(object): def __init__(self, data): quote_objs = data.get("quotes") if(quote_objs is not None): self.quotes = list() for quote_obj in quote_objs: base_amount_obj = quote_obj.get("baseAmount") quote_amount_obj = quote_obj.get("quoteAmount") base_attrs = {"value":base_amount_obj.get("value"), "currency_code":base_amount_obj.get("currencyCode")} base_amount = MontaryAmount(base_attrs) quote_attrs = {"value":quote_amount_obj.get("value"), "currency_code":quote_amount_obj.get("currencyCode")} quote_amount = MontaryAmount(quote_attrs) attributes = {"id":quote_obj.get("id"), "exchange_rate":quote_obj.get("exchangeRate"), "trade_rate":quote_obj.get("tradeRate"), "expires_at":quote_obj.get("expiresAt"), "refreshes_at":quote_obj.get("refreshesAt"), "base_amount":base_amount, "quote_amount":quote_amount} quote = ExchangeRateQuote(attributes) self.quotes.append(quote) def get_quotes(self): return self.quotesbraintree_python-4.31.0/braintree/exchange_rate_quote_request.py000066400000000000000000000012461471021343500252650ustar00rootroot00000000000000from braintree.exchange_rate_quote_input import ExchangeRateQuoteInput class ExchangeRateQuoteRequest(object): def __init__(self): self.quotes = list() def add_exchange_rate_quote_input(self,attributes): new_input = ExchangeRateQuoteInput(self,attributes) self.quotes.append(new_input) return new_input def to_graphql_variables(self): variables = dict() input = dict() quote_list = list() for quote in self.quotes: quote_list.append(quote.to_graphql_variables()) input["quotes"] = quote_list variables["exchangeRateQuoteRequest"] = input return variablesbraintree_python-4.31.0/braintree/facilitated_details.py000066400000000000000000000001541471021343500234560ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class FacilitatedDetails(AttributeGetter): pass braintree_python-4.31.0/braintree/facilitator_details.py000066400000000000000000000001541471021343500235060ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class FacilitatorDetails(AttributeGetter): pass braintree_python-4.31.0/braintree/granted_payment_instrument_update.py000066400000000000000000000004141471021343500265120ustar00rootroot00000000000000from braintree.resource import Resource class GrantedPaymentInstrumentUpdate(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.payment_method_nonce = attributes["payment_method_nonce"]["nonce"] braintree_python-4.31.0/braintree/iban_bank_account.py000066400000000000000000000001231471021343500231140ustar00rootroot00000000000000from braintree.resource import Resource class IbanBankAccount(Resource): pass braintree_python-4.31.0/braintree/ids_search.py000066400000000000000000000001471471021343500216060ustar00rootroot00000000000000from braintree.search import Search class IdsSearch: ids = Search.MultipleValueNodeBuilder("ids") braintree_python-4.31.0/braintree/liability_shift.py000066400000000000000000000001501471021343500226530ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class LiabilityShift(AttributeGetter): pass braintree_python-4.31.0/braintree/local_payment.py000066400000000000000000000001411471021343500223230ustar00rootroot00000000000000import braintree from braintree.resource import Resource class LocalPayment(Resource): pass braintree_python-4.31.0/braintree/local_payment_completed.py000066400000000000000000000010251471021343500243610ustar00rootroot00000000000000from braintree.blik_alias import BlikAlias from braintree.resource import Resource from braintree.transaction import Transaction class LocalPaymentCompleted(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "transaction" in attributes: self.transaction = Transaction(gateway, attributes.pop("transaction")) if "blik_aliases" in attributes: self.blik_aliases = [BlikAlias(gateway, blik_alias) for blik_alias in self.blik_aliases] braintree_python-4.31.0/braintree/local_payment_expired.py000066400000000000000000000004011471021343500240420ustar00rootroot00000000000000from braintree.resource import Resource class LocalPaymentExpired(Resource): """ A class representing Braintree LocalPaymentExpired webhook. """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-4.31.0/braintree/local_payment_funded.py000066400000000000000000000005741471021343500236620ustar00rootroot00000000000000from braintree.resource import Resource from braintree.transaction import Transaction class LocalPaymentFunded(Resource): """ A class representing Braintree LocalPaymentFunded webhook. """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.transaction = Transaction(gateway, attributes.pop("transaction")) braintree_python-4.31.0/braintree/local_payment_reversed.py000066400000000000000000000004031471021343500242230ustar00rootroot00000000000000from braintree.resource import Resource class LocalPaymentReversed(Resource): """ A class representing Braintree LocalPaymentReversed webhook. """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-4.31.0/braintree/masterpass_card.py000066400000000000000000000016311471021343500226540ustar00rootroot00000000000000import braintree from braintree.address import Address from braintree.resource import Resource from warnings import warn class MasterpassCard(Resource): """ A class representing Masterpass card. Deprecated """ def __init__(self, gateway, attributes): warn("MasterpassCard is deprecated") Resource.__init__(self, gateway, attributes) if "billing_address" in attributes: self.billing_address = Address(gateway, self.billing_address) else: self.billing_address = None if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] @property def expiration_date(self): return self.expiration_month + "/" + self.expiration_year @property def masked_number(self): return self.bin + "******" + self.last_4 braintree_python-4.31.0/braintree/merchant.py000066400000000000000000000005751471021343500213100ustar00rootroot00000000000000from braintree.resource import Resource from braintree.merchant_account import MerchantAccount class Merchant(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "merchant_accounts" in attributes: self.merchant_accounts = [MerchantAccount(gateway, ma) for ma in attributes.get("merchant_accounts")] braintree_python-4.31.0/braintree/merchant_account/000077500000000000000000000000001471021343500224435ustar00rootroot00000000000000braintree_python-4.31.0/braintree/merchant_account/__init__.py000066400000000000000000000004421471021343500245540ustar00rootroot00000000000000from 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-4.31.0/braintree/merchant_account/address_details.py000066400000000000000000000006071471021343500261520ustar00rootroot00000000000000from 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-4.31.0/braintree/merchant_account/business_details.py000066400000000000000000000010341471021343500263530ustar00rootroot00000000000000from 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-4.31.0/braintree/merchant_account/funding_details.py000066400000000000000000000006531471021343500261600ustar00rootroot00000000000000from 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-4.31.0/braintree/merchant_account/individual_details.py000066400000000000000000000011401471021343500266460ustar00rootroot00000000000000from 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-4.31.0/braintree/merchant_account/merchant_account.py000066400000000000000000000033371471021343500263400ustar00rootroot00000000000000from braintree.configuration import Configuration from braintree.resource import Resource from braintree.merchant_account import BusinessDetails, FundingDetails, IndividualDetails class MerchantAccount(Resource): class Status(object): Active = "active" Pending = "pending" Suspended = "suspended" class FundingDestination(object): Bank = "bank" Email = "email" MobilePhone = "mobile_phone" FundingDestinations = FundingDestination def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.individual_details = IndividualDetails(attributes.get("individual", {})) self.business_details = BusinessDetails(attributes.get("business", {})) self.funding_details = FundingDetails(attributes.get("funding", {})) if "master_merchant_account" in attributes: self.master_merchant_account = MerchantAccount(gateway, attributes.pop("master_merchant_account")) def __repr__(self): detail_list = [ "id", "business_details", "currency_iso_code", "default", "funding_details", "individual_details", "master_merchant_account", "status", ] return super(MerchantAccount, self).__repr__(detail_list) @staticmethod def create(params=None): if params is None: 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-4.31.0/braintree/merchant_account_gateway.py000066400000000000000000000130731471021343500245420ustar00rootroot00000000000000from braintree.error_result import ErrorResult from braintree.merchant_account import MerchantAccount from braintree.paginated_collection import PaginatedCollection from braintree.paginated_result import PaginatedResult from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult from braintree.exceptions.not_found_error import NotFoundError class MerchantAccountGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create(self, params=None): if params is None: params = {} Resource.verify_keys(params, MerchantAccountGateway._create_signature()) return self._post("/merchant_accounts/create_via_api", {"merchant_account": params}) def update(self, merchant_account_id, params=None): if params is None: params = {} Resource.verify_keys(params, MerchantAccountGateway._update_signature()) return self._put("/merchant_accounts/%s/update_via_api" % merchant_account_id, {"merchant_account": params}) def find(self, merchant_account_id): try: if merchant_account_id is None or merchant_account_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/merchant_accounts/" + merchant_account_id) return MerchantAccount(self.gateway, response["merchant_account"]) except NotFoundError: raise NotFoundError("merchant account with id " + repr(merchant_account_id) + " not found") def create_for_currency(self, params=None): if params is None: params = {} return self._post("/merchant_accounts/create_for_currency", {"merchant_account": params}) def all(self): pc = PaginatedCollection(self._fetch_merchant_accounts) return SuccessfulResult({"merchant_accounts": pc}) def _fetch_merchant_accounts(self, current_page): response = self.config.http().get(self.config.base_merchant_path() + "/merchant_accounts/?page=" + str(current_page)) body = response["merchant_accounts"] merchant_accounts = [MerchantAccount(self.gateway, merchant_account) for merchant_account in ResourceCollection._extract_as_array(body, "merchant_account")] return PaginatedResult(body["total_items"], body["page_size"], merchant_accounts) def _post(self, url, params=None): if params is None: params = {} response = self.config.http().post(self.config.base_merchant_path() + url, params) if "response" in response: response = response["response"] if "merchant_account" in response: return SuccessfulResult({"merchant_account": MerchantAccount(self.gateway, response["merchant_account"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def _put(self, url, params=None): if params is None: 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 _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-4.31.0/braintree/merchant_gateway.py000066400000000000000000000022531471021343500230240ustar00rootroot00000000000000from 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=None): if params is None: params = {} response = self.config.http().post("/merchants/create_via_api", { "merchant": params }) if "response" in response and "merchant" in response["response"]: return SuccessfulResult({ "merchant": Merchant(self.gateway, response["response"]["merchant"]), "credentials": OAuthCredentials(self.gateway, response["response"]["credentials"]) }) else: return ErrorResult(self.gateway, response["api_error_response"]) braintree_python-4.31.0/braintree/meta_checkout_card.py000066400000000000000000000010131471021343500232770ustar00rootroot00000000000000import braintree from braintree.address import Address from braintree.resource import Resource class MetaCheckoutCard(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) @property def expiration_date(self): if not self.expiration_month or not self.expiration_year: return None return self.expiration_month + "/" + self.expiration_year @property def masked_number(self): return self.bin + "******" + self.last_4 braintree_python-4.31.0/braintree/meta_checkout_token.py000066400000000000000000000010141471021343500235070ustar00rootroot00000000000000import braintree from braintree.address import Address from braintree.resource import Resource class MetaCheckoutToken(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) @property def expiration_date(self): if not self.expiration_month or not self.expiration_year: return None return self.expiration_month + "/" + self.expiration_year @property def masked_number(self): return self.bin + "******" + self.last_4 braintree_python-4.31.0/braintree/modification.py000066400000000000000000000003601471021343500221440ustar00rootroot00000000000000from 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-4.31.0/braintree/montary_amount.py000066400000000000000000000004601471021343500225540ustar00rootroot00000000000000from decimal import Decimal from braintree.attribute_getter import AttributeGetter class MontaryAmount(AttributeGetter): def __init__(self,attributes): AttributeGetter.__init__(self,attributes) if getattr(self, "value", None) is not None: self.value = Decimal(self.value)braintree_python-4.31.0/braintree/oauth_access_revocation.py000066400000000000000000000003541471021343500243740ustar00rootroot00000000000000from braintree.resource import Resource class OAuthAccessRevocation(Resource): """ A class representing an OAuth access revocation. """ def __init__(self, attributes): Resource.__init__(self, None, attributes) braintree_python-4.31.0/braintree/oauth_credentials.py000066400000000000000000000001241471021343500231720ustar00rootroot00000000000000from braintree.resource import Resource class OAuthCredentials(Resource): pass braintree_python-4.31.0/braintree/oauth_gateway.py000066400000000000000000000051671471021343500223520ustar00rootroot00000000000000import braintree from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult from braintree.exceptions.not_found_error import NotFoundError from braintree.oauth_credentials import OAuthCredentials import sys from urllib.parse import quote_plus from functools import reduce class OAuthGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create_token_from_code(self, params): params["grant_type"] = "authorization_code" return self._create_token(params) def create_token_from_refresh_token(self, params): params["grant_type"] = "refresh_token" return self._create_token(params) def revoke_access_token(self, access_token): self.config.assert_has_client_credentials() response = self.config.http().post("/oauth/revoke_access_token", { "token": access_token }) if "result" in response and response["result"]["success"]: return SuccessfulResult else: return ErrorResult(self.gateway, "could not revoke access token") def _create_token(self, params): self.config.assert_has_client_credentials() response = self.config.http().post("/oauth/access_tokens", { "credentials": params }) if "credentials" in response: return SuccessfulResult({"credentials": OAuthCredentials(self.gateway, response["credentials"])}) else: return ErrorResult(self.gateway, response["api_error_response"]) def connect_url(self, raw_params): params = {"client_id": self.config.client_id} params.update(raw_params) user_params = self._sub_query(params, "user") business_params = self._sub_query(params, "business") def clean_values(accumulator, kv_pair): key, value = kv_pair if isinstance(value, list): accumulator += [(key + "[]", v) for v in value] else: accumulator += [(key, value)] return accumulator params = reduce(clean_values, params.items(), []) query = params + user_params + business_params query_string = "&".join(quote_plus(key) + "=" + quote_plus(value) for key, value in query) return self.config.environment.base_url + "/oauth/connect?" + query_string def _sub_query(self, params, root): if root in params: sub_query = params.pop(root) else: sub_query = {} query = [(root + "[" + key + "]", str(value)) for key, value in sub_query.items()] return query braintree_python-4.31.0/braintree/package_details.py000066400000000000000000000015411471021343500226010ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter from warnings import warn class PackageDetails(AttributeGetter): """ A class representing the package tracking information of a transaction. An example of package details including all available fields:: result = braintree.PackageDetails.create({ "id": "my_id", "carrier": "a_carrier", "tracking_number": "my_tracking_number", "paypal_tracking_id": "my_paypal_tracking_id", "paypal_tracker_id": "my_paypal_tracker_id", }) """ detail_list = [ "id", "carrier", "tracking_number", # NEXT_MAJOR_VERSION remove paypal_tracking_id "paypal_tracking_id", "paypal_tracker_id", ] def __init__(self, attributes): AttributeGetter.__init__(self, attributes) braintree_python-4.31.0/braintree/paginated_collection.py000066400000000000000000000015621471021343500236530ustar00rootroot00000000000000import braintree class PaginatedCollection(object): """ A class representing results from a paginated list. Supports the iterator protocol:: results = braintree.MerchantAccount.all() for merchant_account in results.items: print merchant_account.id """ def __init__(self, method): self.__method = method @property def items(self): """ Returns a generator allowing iteration over all of the results. """ current_page = 0 total_items = 0 while True: current_page += 1 results = self.__method(current_page) total_items = results.total_items for item in results.current_page: yield item if current_page * results.page_size >= total_items: break def __iter__(self): return self.items braintree_python-4.31.0/braintree/paginated_result.py000066400000000000000000000004451471021343500230350ustar00rootroot00000000000000class PaginatedResult(object): """ An instance of this class is returned from paginated operations """ def __init__(self, total_items, page_size, current_page): self.total_items = total_items self.page_size = page_size self.current_page = current_page braintree_python-4.31.0/braintree/partner_merchant.py000066400000000000000000000017721471021343500230430ustar00rootroot00000000000000from 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-4.31.0/braintree/payment_instrument_type.py000066400000000000000000000014431471021343500245100ustar00rootroot00000000000000 class PaymentInstrumentType(): # NEXT_MAJOR_VERSION remove amex express checkout, masterpass, # and SamsungPayCard. They have been deprecated AmexExpressCheckoutCard = "amex_express_checkout_card" AndroidPayCard = "android_pay_card" ApplePayCard = "apple_pay_card" CreditCard = "credit_card" EuropeBankAccount = "europe_bank_account" LocalPayment = "local_payment" MasterpassCard = "masterpass_card" MetaCheckoutCard = "meta_checkout_card" MetaCheckoutToken = "meta_checkout_token" PayPalAccount = "paypal_account" PayPalHere = "paypal_here" SamsungPayCard = "samsung_pay_card" SepaDirectDebitAccount = "sepa_debit_account" UsBankAccount = "us_bank_account" VenmoAccount = "venmo_account" VisaCheckoutCard = "visa_checkout_card" braintree_python-4.31.0/braintree/payment_method.py000066400000000000000000000111621471021343500225160ustar00rootroot00000000000000import braintree from braintree.address import Address from braintree.resource import Resource from braintree.configuration import Configuration class PaymentMethod(Resource): @staticmethod def create(params=None): if params is None: params = {} return Configuration.gateway().payment_method.create(params) @staticmethod def find(payment_method_token): return Configuration.gateway().payment_method.find(payment_method_token) @staticmethod def update(payment_method_token, params): return Configuration.gateway().payment_method.update(payment_method_token, params) @staticmethod def delete(payment_method_token, options=None): if options is None: options = {} return Configuration.gateway().payment_method.delete(payment_method_token, options) @staticmethod def create_signature(): return PaymentMethod.signature("create") @staticmethod def signature(type): options = [ "fail_on_duplicate_payment_method", "fail_on_duplicate_payment_method_for_customer", "make_default", "skip_advanced_fraud_checking", "us_bank_account_verification_method", "verification_account_type", "verification_add_ons", "verification_amount", "verification_merchant_account_id", "verify_card", { "adyen": [ "overwrite_brand", "selected_brand" ] }, { "paypal": [ "payee_email", "order_id", "custom_field", "description", "amount", { "shipping": Address.create_signature() } ], }, ] three_d_secure_pass_thru = [ "cavv", "ds_transaction_id", "eci_flag", "three_d_secure_version", "xid" ] signature = [ "billing_address_id", "cardholder_name", "customer_id", "cvv", "device_data", "expiration_date", "expiration_month", "expiration_year", "number", "payment_method_nonce", "paypal_refresh_token", "token", "device_session_id", # NEXT_MAJOR_VERSION remove device_session_id { "billing_address": Address.create_signature() }, { "options": options }, { "three_d_secure_pass_thru": three_d_secure_pass_thru } ] return signature @staticmethod def update_signature(): three_d_secure_pass_thru = [ "cavv", "ds_transaction_id", "eci_flag", "three_d_secure_version", "xid" ] signature = [ "billing_address_id", "cardholder_name", "cvv", "device_data", "expiration_date", "expiration_month", "expiration_year", "number", "payment_method_nonce", "token", "venmo_sdk_payment_method_code", # NEXT_MJOR_VERSION remove venmo_sdk_payment_method_code "device_session_id", "fraud_merchant_id", # NEXT_MAJOR_VERSION remove device_session_id and fraud_merchant_id { "options": [ "fail_on_duplicate_payment_method_for_customer", "make_default", "skip_advanced_fraud_checking", "us_bank_account_verification_method", "venmo_sdk_session", # NEXT_MJOR_VERSION remove venmo_sdk_session "verification_account_type", "verification_add_ons", "verification_amount", "verification_merchant_account_id", "verify_card", { "adyen": [ "overwrite_brand", "selected_brand" ] } ] }, { "billing_address": Address.update_signature() + [{"options": ["update_existing"]}] }, { "three_d_secure_pass_thru": three_d_secure_pass_thru } ] return signature @staticmethod def delete_signature(): return ["revoke_all_grants"] braintree_python-4.31.0/braintree/payment_method_customer_data_updated_metadata.py000066400000000000000000000012471471021343500310010ustar00rootroot00000000000000from braintree.resource import Resource from braintree.payment_method_parser import parse_payment_method from braintree.enriched_customer_data import EnrichedCustomerData class PaymentMethodCustomerDataUpdatedMetadata(Resource): """ A class representing Braintree PaymentMethodCustomerDataUpdatedMetadata webhook. """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.payment_method = parse_payment_method(gateway, attributes["payment_method"]) if attributes["enriched_customer_data"]: self.enriched_customer_data = EnrichedCustomerData(gateway, attributes["enriched_customer_data"]) braintree_python-4.31.0/braintree/payment_method_gateway.py000066400000000000000000000165311471021343500242440ustar00rootroot00000000000000import 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.android_pay_card import AndroidPayCard # NEXT_MAJOR_VERSION remove amex express checkout from braintree.amex_express_checkout_card import AmexExpressCheckoutCard from braintree.sepa_direct_debit_account import SepaDirectDebitAccount from braintree.venmo_account import VenmoAccount from braintree.us_bank_account import UsBankAccount from braintree.visa_checkout_card import VisaCheckoutCard # NEXT_MAJOR_VERSION remove masterpass from braintree.masterpass_card import MasterpassCard # NEXT_MAJOR_VERSION remove SamsungPayCard from braintree.samsung_pay_card import SamsungPayCard from braintree.unknown_payment_method import UnknownPaymentMethod from braintree.error_result import ErrorResult from braintree.exceptions.not_found_error import NotFoundError from braintree.ids_search import IdsSearch from braintree.payment_method_nonce import PaymentMethodNonce from braintree.payment_method_parser import parse_payment_method from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.successful_result import SuccessfulResult import sys from urllib.parse import urlencode class PaymentMethodGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def create(self, params=None): if params is None: params = {} Resource.verify_keys(params, PaymentMethod.create_signature()) self.__check_for_deprecated_attributes(params); return self._post("/payment_methods", {"payment_method": params}) def find(self, payment_method_token): try: if payment_method_token is None or payment_method_token.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_methods/any/" + payment_method_token) return parse_payment_method(self.gateway, response) except NotFoundError: raise NotFoundError("payment method with token " + repr(payment_method_token) + " not found") def update(self, payment_method_token, params): Resource.verify_keys(params, PaymentMethod.update_signature()) self.__check_for_deprecated_attributes(params); try: if payment_method_token is None or payment_method_token.strip() == "": raise NotFoundError() return self._put( "/payment_methods/any/" + payment_method_token, {"payment_method": params} ) except NotFoundError: raise NotFoundError("payment method with token " + repr(payment_method_token) + " not found") def delete(self, payment_method_token, options=None): if options is None: options = {} Resource.verify_keys(options, PaymentMethod.delete_signature()) query_param = "" if options: if 'revoke_all_grants' in options: options['revoke_all_grants'] = str(options['revoke_all_grants']).lower() query_param = "?" + urlencode(options) self.config.http().delete(self.config.base_merchant_path() + "/payment_methods/any/" + payment_method_token + query_param) return SuccessfulResult() def grant(self, payment_method_token, options=None): if payment_method_token is None or not str(payment_method_token).strip(): raise ValueError("payment method token cannot be empty or blank") try: if isinstance(options, bool): options = { "allow_vaulting": options } elif options is None: options = {} self.options = options params = { "payment_method": { "shared_payment_method_token": payment_method_token } } params["payment_method"].update(options), return self._post( "/payment_methods/grant", params, "payment_method_nonce" ) except NotFoundError: raise NotFoundError("payment method with payment_method_token " + repr(payment_method_token) + " not found") def revoke(self, payment_method_token): if payment_method_token is None or not str(payment_method_token).strip(): raise ValueError try: return self._post( "/payment_methods/revoke", { "payment_method": { "shared_payment_method_token": payment_method_token } }, "revoke" ) except NotFoundError: raise NotFoundError("payment method with payment_method_token " + repr(payment_method_token) + " not found") def _post(self, url, params=None, result_key="payment_method"): if params is None: params = {} 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 == "revoke" and response.get("success", False): return SuccessfulResult() elif result_key == "payment_method_nonce": payment_method_nonce = self._parse_payment_method_nonce(response) return SuccessfulResult({result_key: payment_method_nonce}) else: payment_method = parse_payment_method(self.gateway, response) return SuccessfulResult({result_key: payment_method}) return response def _put(self, url, params=None): if params is None: params = {} response = self.config.http().put(self.config.base_merchant_path() + url, params) if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: payment_method = parse_payment_method(self.gateway, response) return SuccessfulResult({"payment_method": payment_method}) def _parse_payment_method_nonce(self, response): if "payment_method_nonce" in response: return PaymentMethodNonce(self.gateway, response["payment_method_nonce"]) raise ValueError("payment_method_nonce not present in response") # NEXT_MAJOR_VERSION remove these checks when the attributes are removed def __check_for_deprecated_attributes(self, params): if "device_session_id" in params.keys(): warnings.warn("device_session_id is deprecated, use device_data parameter instead", DeprecationWarning) if "fraud_merchant_id" in params.keys(): warnings.warn("fraud_merchant_id is deprecated, use device_data parameter instead", DeprecationWarning) if "venmo_sdk_payment_method_code" in params.keys() or "venmo_sdk_session" in params.keys(): warnings.warn("The Venmo SDK integration is Unsupported. Please update your integration to use Pay with Venmo instead.", DeprecationWarning) if "samsung_pay_card" in params.keys(): warnings.warn("SamsungPay is deprecated", DeprecationWarning) braintree_python-4.31.0/braintree/payment_method_nonce.py000066400000000000000000000024561471021343500237060ustar00rootroot00000000000000import braintree from braintree.resource import Resource from braintree.configuration import Configuration from braintree.three_d_secure_info import ThreeDSecureInfo from braintree.bin_data import BinData class PaymentMethodNonce(Resource): @staticmethod def create(payment_method_token, params = {}): return Configuration.gateway().payment_method_nonce.create(payment_method_token, params) @staticmethod def find(payment_method_nonce): return Configuration.gateway().payment_method_nonce.find(payment_method_nonce) def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "three_d_secure_info" in attributes and not attributes["three_d_secure_info"] is None: self.three_d_secure_info = ThreeDSecureInfo(attributes["three_d_secure_info"]) else: self.three_d_secure_info = None if "authentication_insight" in attributes and not attributes["authentication_insight"] is None: self.authentication_insight = attributes["authentication_insight"] else: self.authentication_insight = None if "bin_data" in attributes and not attributes["bin_data"] is None: self.bin_data = BinData(attributes["bin_data"]) else: self.bin_data = None braintree_python-4.31.0/braintree/payment_method_nonce_gateway.py000066400000000000000000000040441471021343500254220ustar00rootroot00000000000000import 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, params = {"payment_method_nonce": {}}): try: schema = [{"payment_method_nonce": ["merchant_account_id", "authentication_insight", {"authentication_insight_options": ["amount", "recurring_customer_consent", "recurring_max_amount"]}]}] Resource.verify_keys(params, schema) response = self.config.http().post(self.config.base_merchant_path() + "/payment_methods/" + payment_method_token + "/nonces", params) if "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) else: payment_method_nonce = self._parse_payment_method_nonce(response) return SuccessfulResult({"payment_method_nonce": payment_method_nonce}) except NotFoundError: raise NotFoundError("payment method with token " + repr(payment_method_token) + " not found") def find(self, payment_method_nonce): try: if payment_method_nonce is None or payment_method_nonce.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_method_nonces/" + payment_method_nonce) return self._parse_payment_method_nonce(response) except NotFoundError: raise NotFoundError("payment method nonce with id " + repr(payment_method_nonce) + " not found") def _parse_payment_method_nonce(self, response): return PaymentMethodNonce(self.gateway, response["payment_method_nonce"]) braintree_python-4.31.0/braintree/payment_method_parser.py000066400000000000000000000046641471021343500241030ustar00rootroot00000000000000import 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.android_pay_card import AndroidPayCard from braintree.amex_express_checkout_card import AmexExpressCheckoutCard from braintree.venmo_account import VenmoAccount from braintree.us_bank_account import UsBankAccount from braintree.visa_checkout_card import VisaCheckoutCard from braintree.masterpass_card import MasterpassCard from braintree.sepa_direct_debit_account import SepaDirectDebitAccount # NEXT_MAJOR_VERSION remove SamsungPayCard from braintree.samsung_pay_card import SamsungPayCard from braintree.unknown_payment_method import UnknownPaymentMethod def parse_payment_method(gateway, attributes): if "paypal_account" in attributes: return PayPalAccount(gateway, attributes["paypal_account"]) elif "credit_card" in attributes: return CreditCard(gateway, attributes["credit_card"]) elif "europe_bank_account" in attributes: return EuropeBankAccount(gateway, attributes["europe_bank_account"]) elif "apple_pay_card" in attributes: return ApplePayCard(gateway, attributes["apple_pay_card"]) elif "android_pay_card" in attributes: return AndroidPayCard(gateway, attributes["android_pay_card"]) # NEXT_MAJOR_VERSION remove amex express checkout elif "amex_express_checkout_card" in attributes: return AmexExpressCheckoutCard(gateway, attributes["amex_express_checkout_card"]) elif "sepa_debit_account" in attributes: return SepaDirectDebitAccount(gateway, attributes["sepa_debit_account"]) elif "venmo_account" in attributes: return VenmoAccount(gateway, attributes["venmo_account"]) elif "us_bank_account" in attributes: return UsBankAccount(gateway, attributes["us_bank_account"]) elif "visa_checkout_card" in attributes: return VisaCheckoutCard(gateway, attributes["visa_checkout_card"]) # NEXT_MAJOR_VERSION remove masterpass elif "masterpass_card" in attributes: return MasterpassCard(gateway, attributes["masterpass_card"]) elif "samsung_pay_card" in attributes: return SamsungPayCard(gateway, attributes["samsung_pay_card"]) else: name = list(attributes)[0] return UnknownPaymentMethod(gateway, attributes[name]) braintree_python-4.31.0/braintree/paypal_account.py000066400000000000000000000020451471021343500225030ustar00rootroot00000000000000import 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=None): if params is None: 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-4.31.0/braintree/paypal_account_gateway.py000066400000000000000000000034261471021343500242300ustar00rootroot00000000000000import 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=None): if params is None: 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-4.31.0/braintree/paypal_here.py000066400000000000000000000002711471021343500217710ustar00rootroot00000000000000import braintree from braintree.resource import Resource class PayPalHere(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-4.31.0/braintree/plan.py000066400000000000000000000057051471021343500204410ustar00rootroot00000000000000from 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 from braintree.successful_result import SuccessfulResult from braintree.error_result import ErrorResult 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() @staticmethod def create(params=None): if params is None: params = {} return Configuration.gateway().plan.create(params) @staticmethod def find(subscription_id): return Configuration.gateway().plan.find(subscription_id) @staticmethod def update(subscription_id, params=None): if params is None: params = {} return Configuration.gateway().plan.update(subscription_id, params) @staticmethod def create_signature(): return [ "billing_day_of_month", "billing_frequency", "currency_iso_code", "description", "id", "merchant_id", "name", "number_of_billing_cycles", "price", "trial_duration", "trial_duration_unit", "trial_period" ] + Plan._add_on_discount_signature() @staticmethod def update_signature(): return [ "billing_day_of_month", "billing_frequency", "currency_iso_code", "description", "id", "merchant_id", "name", "number_of_billing_cycles", "price", "trial_duration", "trial_duration_unit", "trial_period" ] + Plan._add_on_discount_signature() @staticmethod def _add_on_discount_signature(): return [ { "add_ons": [ {"add": ["amount", "inherited_from_id", "never_expires", "number_of_billing_cycles", "quantity"]}, {"update": ["amount", "existing_id", "never_expires", "number_of_billing_cycles", "quantity"]}, {"remove": ["_any_key_"]} ] }, { "discounts": [ {"add": ["amount", "inherited_from_id", "never_expires", "number_of_billing_cycles", "quantity"]}, {"update": ["amount", "existing_id", "never_expires", "number_of_billing_cycles", "quantity"]}, {"remove": ["_any_key_"]} ] } ] braintree_python-4.31.0/braintree/plan_gateway.py000066400000000000000000000040501471021343500221520ustar00rootroot00000000000000import 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")] def create(self, params=None): if params is None: params = {} Resource.verify_keys(params, Plan.create_signature()) response = self.config.http().post(self.config.base_merchant_path() + "/plans", {"plan": params}) if "plan" in response: return SuccessfulResult({"plan": Plan(self.gateway, response["plan"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def find(self, plan_id): try: if plan_id is None or plan_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/plans/" + plan_id) return Plan(self.gateway, response["plan"]) except NotFoundError: raise NotFoundError("Plan with id " + repr(plan_id) + " not found") def update(self, plan_id, params=None): if params is None: params = {} Resource.verify_keys(params, Plan.update_signature()) response = self.config.http().put(self.config.base_merchant_path() + "/plans/" + plan_id, {"plan": params}) if "plan" in response: return SuccessfulResult({"plan": Plan(self.gateway, response["plan"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) braintree_python-4.31.0/braintree/processor_response_types.py000066400000000000000000000003251471021343500246610ustar00rootroot00000000000000class ProcessorResponseTypes(object): """ A set of constants representing processor response types. """ Approved = "approved" SoftDeclined = "soft_declined" HardDeclined = "hard_declined" braintree_python-4.31.0/braintree/resource.py000066400000000000000000000052651471021343500213370ustar00rootroot00000000000000import re import string import sys from braintree.attribute_getter import AttributeGetter text_type = str raw_type = bytes class Resource(AttributeGetter): @staticmethod def verify_keys(params, signature): allowed_keys = Resource.__flattened_signature(signature) params_keys = Resource.__flattened_params_keys(params) invalid_keys = [key for key in params_keys if key not in allowed_keys] invalid_keys = Resource.__remove_wildcard_keys(allowed_keys, invalid_keys) if len(invalid_keys) > 0: keys_string = ", ".join(invalid_keys) raise KeyError("Invalid keys: " + keys_string) # NEXT_MAJOR_VERSION this method misses a check for param keys that have an empty value # Add a check for a val of length 0 for both types, if true, full_key should be appended @staticmethod def __flattened_params_keys(params, parent=None): if isinstance(params, text_type) or isinstance(params, raw_type): return [ "%s[%s]" % (parent, params) ] else: keys = [] for key, val in params.items(): full_key = "%s[%s]" % (parent, key) if parent else key if isinstance(val, dict): keys += Resource.__flattened_params_keys(val, full_key) elif isinstance(val, list): for item in val: keys += Resource.__flattened_params_keys(item, full_key) else: keys.append(full_key) return keys @staticmethod def __flattened_signature(signature, parent=None): flat_sig = [] for item in signature: if isinstance(item, dict): for key, val in item.items(): full_key = '{0}[{1}]'.format(parent, key) if parent else key flat_sig += Resource.__flattened_signature(val, full_key) else: full_key = '{0}[{1}]'.format(parent, item) if parent else item flat_sig.append(full_key) return flat_sig @staticmethod def __remove_wildcard_keys(allowed_keys, invalid_keys): wildcard_keys = [ re.sub(r"(?<=[^\\])_", "\\_", re.escape(key)).replace(r"\[\_\_any\_key\_\_\]", r"\[[\w.-]+\]") for key in allowed_keys if re.search(r"\[__any_key__\]", key) ] new_keys = [] for key in invalid_keys: if len([match for match in wildcard_keys if re.match(r"\A" + match + r"\Z", key)]) == 0: new_keys.append(key) return new_keys def __init__(self, gateway, attributes): AttributeGetter.__init__(self, attributes) self.gateway = gateway braintree_python-4.31.0/braintree/resource_collection.py000066400000000000000000000036511471021343500235470ustar00rootroot00000000000000import braintree from braintree.exceptions.unexpected_error import UnexpectedError class ResourceCollection(object): """ A class representing results from a search. Supports the iterator protocol:: results = braintree.Transaction.search("411111") for transaction in results: print transaction.id """ def __init__(self, query, results, method): if "search_results" not in results: raise UnexpectedError("Unprocessable entity due to an invalid request") self.__ids = results["search_results"]["ids"] self.__method = method self.__page_size = results["search_results"]["page_size"] self.__query = query @property def maximum_size(self): """ Returns the approximate size of the results. The size is approximate due to race conditions when pulling back results. Due to its inexact nature, maximum_size should be avoided. """ return len(self.__ids) @property def first(self): """ Returns the first item in the results. """ return self.__method(self.__query, self.__ids[0:1])[0] @property def items(self): """ Returns a generator allowing iteration over all of the results. """ for batch in self.__batch_ids(): for item in self.__method(self.__query, batch): yield item @property def ids(self): """ Returns the list of ids in the search result. """ return self.__ids def __iter__(self): return self.items def __batch_ids(self): for i in range(0, len(self.__ids), self.__page_size): yield self.__ids[i:i+self.__page_size] @staticmethod def _extract_as_array(results, attribute): if not attribute in results: return [] value = results[attribute] if not isinstance(value, list): value = [value] return value braintree_python-4.31.0/braintree/revoked_payment_method_metadata.py000066400000000000000000000006201471021343500260720ustar00rootroot00000000000000from braintree.payment_method_parser import parse_payment_method from braintree.resource import Resource class RevokedPaymentMethodMetadata(Resource): def __init__(self, gateway, attributes): self.revoked_payment_method = parse_payment_method(gateway, attributes) self.customer_id = self.revoked_payment_method.customer_id self.token = self.revoked_payment_method.token braintree_python-4.31.0/braintree/risk_data.py000066400000000000000000000005421471021343500214420ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter from braintree.liability_shift import LiabilityShift class RiskData(AttributeGetter): def __init__(self, attributes): AttributeGetter.__init__(self, attributes) if "liability_shift" in attributes: self.liability_shift = LiabilityShift(attributes["liability_shift"]) braintree_python-4.31.0/braintree/samsung_pay_card.py000066400000000000000000000016501471021343500230210ustar00rootroot00000000000000import braintree from braintree.address import Address from braintree.resource import Resource # NEXT_MAJOR_VERSION remove this class # SamsungPay is deprecated class SamsungPayCard(Resource): def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "billing_address" in attributes: self.billing_address = Address(gateway, self.billing_address) else: self.billing_address = None if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] @property def expiration_date(self): if not self.expiration_month or not self.expiration_year: return None return self.expiration_month + "/" + self.expiration_year @property def masked_number(self): return self.bin + "******" + self.last_4 braintree_python-4.31.0/braintree/search.py000066400000000000000000000103071471021343500207460ustar00rootroot00000000000000import warnings class Search: """ Collection of classes used to build search queries. Each Builder class defines one or more methods that returns a Node object with the name of the field, the comparator, and the value. """ class IsNodeBuilder(object): """Builds a query for value equality.""" def __init__(self, name): self.name = name def __eq__(self, value): return self.is_equal(value) def is_equal(self, value): return Search.Node(self.name, {"is": value}) class EqualityNodeBuilder(IsNodeBuilder): """Builds a query for value inequality.""" def __ne__(self, value): return self.is_not_equal(value) def is_not_equal(self, value): return Search.Node(self.name, {"is_not": value}) class KeyValueNodeBuilder(object): """Builds a query based on a key-value map.""" def __init__(self, name): self.name = name def __eq__(self, value): return self.is_equal(value) def is_equal(self, value): return Search.Node(self.name, value) def __ne__(self, value): return self.is_not_equal(value) def is_not_equal(self, value): return Search.Node(self.name, not value) class PartialMatchNodeBuilder(EqualityNodeBuilder): """Builds a query for matching parts of a sequence.""" def starts_with(self, value): return Search.Node(self.name, {"starts_with": value}) def ends_with(self, value): return Search.Node(self.name, {"ends_with": value}) class EndsWithNodeBuilder(object): def __init__(self, name): self.name = name def ends_with(self, value): return Search.Node(self.name, {"ends_with": value}) class TextNodeBuilder(PartialMatchNodeBuilder): """Builds a query for matching any part of a sequence.""" def contains(self, value): return Search.Node(self.name, {"contains": value}) class Node(object): """Container for part of a search query.""" def __init__(self, name, dict): self.name = name self.dict = dict def to_param(self): return self.dict class MultipleValueNodeBuilder(object): """Builds a query to check membership in a sequence.""" def __init__(self, name, whitelist = []): if "chargeback_protection_level" == name: warnings.warn("Use protection_level parameter instead", DeprecationWarning) self.name = name self.whitelist = whitelist def in_list(self, *values): if isinstance(values[0], list): values = values[0] invalid_args = set(values) - set(self.whitelist) if len(self.whitelist) > 0 and len(invalid_args) > 0: error_string = "Invalid argument(s) for %s: %s" % (self.name, ", ".join(invalid_args)) raise AttributeError(error_string) return Search.Node(self.name, list(values)) def __eq__(self, value): return self.in_list([value]) class MultipleValueOrTextNodeBuilder(TextNodeBuilder, MultipleValueNodeBuilder): """Builder node supporting contains and in_list.""" def __init__(self, name, whitelist = []): Search.MultipleValueNodeBuilder.__init__(self, name, whitelist) class RangeNodeBuilder(object): """Builds a query supporting <=, >=, or == value.""" def __init__(self, name): self.name = name def __eq__(self, value): return self.is_equal(value) def is_equal(self, value): return Search.EqualityNodeBuilder(self.name) == value def __ge__(self, min): return self.greater_than_or_equal_to(min) def greater_than_or_equal_to(self, min): return Search.Node(self.name, {"min": min}) def __le__(self, max): return self.less_than_or_equal_to(max) def less_than_or_equal_to(self, max): return Search.Node(self.name, {"max": max}) def between(self, min, max): return Search.Node(self.name, {"min": min, "max": max}) braintree_python-4.31.0/braintree/sepa_direct_debit_account.py000066400000000000000000000013741471021343500246520ustar00rootroot00000000000000import braintree from braintree.resource import Resource from braintree.configuration import Configuration class SepaDirectDebitAccount(Resource): @staticmethod def find(sepa_direct_debit_account_token): return Configuration.gateway().sepa_direct_debit_account.find(sepa_direct_debit_account_token) @staticmethod def delete(sepa_direct_debit_account_token): return Configuration.gateway().sepa_direct_debit_account.delete(sepa_direct_debit_account_token) 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-4.31.0/braintree/sepa_direct_debit_account_gateway.py000066400000000000000000000024751471021343500263760ustar00rootroot00000000000000import braintree from braintree.sepa_direct_debit_account import SepaDirectDebitAccount 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 SepaDirectDebitAccountGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def find(self, sepa_direct_debit_account_token): try: if sepa_direct_debit_account_token is None or sepa_direct_debit_account_token.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_methods/sepa_debit_account/" + sepa_direct_debit_account_token) if "sepa_debit_account" in response: return SepaDirectDebitAccount(self.gateway, response["sepa_debit_account"]) except NotFoundError: raise NotFoundError("sepa direct debit account with token " + repr(sepa_direct_debit_account_token) + " not found") def delete(self, sepa_direct_debit_account_token): self.config.http().delete(self.config.base_merchant_path() + "/payment_methods/sepa_debit_account/" + sepa_direct_debit_account_token) return SuccessfulResult() braintree_python-4.31.0/braintree/settlement_batch_summary.py000066400000000000000000000011571471021343500246060ustar00rootroot00000000000000from 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-4.31.0/braintree/settlement_batch_summary_gateway.py000066400000000000000000000020621471021343500263230ustar00rootroot00000000000000import 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-4.31.0/braintree/signature_service.py000066400000000000000000000010111471021343500232120ustar00rootroot00000000000000import 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-4.31.0/braintree/ssl/000077500000000000000000000000001471021343500177275ustar00rootroot00000000000000braintree_python-4.31.0/braintree/ssl/api_braintreegateway_com.ca.crt000066400000000000000000000673651471021343500260700ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM 9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L 93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU 5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy rqXRfboQnoZsG4q5WTP468SQvvG5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg 1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K 8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r 2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR 8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz 7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 +XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI 0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY +gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl 7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE 76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H 9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT 4PsJYGw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM YyRIHN8wfdVoOw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi 9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW 1KyLa2tJElMzrdfkviT8tQp21KW8EA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I 0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv 6pZjamVFkpUBtA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICFjCCAZ2gAwIBAgIQA2mP5xLVGfPO0P23sWQwETAKBggqhkjOPQQDAzBNMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERp Z2lDZXJ0IENTIEVDQyBQMzg0IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYw MTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu Yy4xJTAjBgNVBAMTHERpZ2lDZXJ0IENTIEVDQyBQMzg0IFJvb3QgRzUwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAAR/FK2Ftpf9AiE1TWDoOJOTmz0FEG2v0/7v+rv7c5nz 7DISjcdouIveiaKIVHeNuyF+M5VWlgno1YyhBLibbhkAYuhCKKZYN4QZVSZ7Mzdn 8ppyraGurgBCPBx+uHqeIZyjQjBAMB0GA1UdDgQWBBTwjJhxOThlwjobphdmHcjt Zd6SNjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQD AwNnADBkAjAjb+EAGSZQ5EYgZYs3p8/rBuHMMskqoewyDXOiHgIcNWEqTmmrOXft l4jAfWvqid0CMEPx0VijdT6Gm7ZVEYsX9z3+CmnFf07GdRtalMvqERHGCCKI3tB6 oqV56OMhp80Tsw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFZDCCA0ygAwIBAgIQBs7hMb5tVcgH98DH+0TmIDANBgkqhkiG9w0BAQwFADBM MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJDAiBgNVBAMT G0RpZ2lDZXJ0IENTIFJTQTQwOTYgUm9vdCBHNTAeFw0yMTAxMTUwMDAwMDBaFw00 NjAxMTQyMzU5NTlaMEwxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg SW5jLjEkMCIGA1UEAxMbRGlnaUNlcnQgQ1MgUlNBNDA5NiBSb290IEc1MIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtjNzgNhiA3AULBEcOV58rnyDhh3+ Ji9MJK2L6oNfqbw9W/wLmEwCRzDs4v7s6DRbZl6/O9cspiX/jFmz3+rafCnZRlBy CB1u0RsK3R/NmYn6Dw9zxOGcHXUyzW+X2ipqlbJsyQnQ6gt7fRcGSZnv1t7gyFPU rsZ38Ya7Ixy4wN9Z94590e+C5iaLWji1/3XVstlPCfM3iFDaEaSKFBTRUwQAffNq RBj+UHAyBxyomg46HcUKH24LJmm3PKJXcCyG+kxulalYQ7msEtb/P+3XQxdrTM6e xJCr//oQUJqjkFfW54wQrp8WGs81HX/Xdu2KnDWnKLinXSH8MDfd3ggZTxXG56ba kEeO95RTTI5TAr79meXqhtCvAwLTm6qT8asojiAB/0z7zLcpQPWHpBITBR9DbtdR UJ84tCDtFwkSj8y5Ga+fzb5pEdOvVRBtF4Z5llLGsgCd5a84sDX0iGuPDgQ9fO6v zdNqEErGzYbKIj2hSlz7Dv+I31xip8C5HtmsbH44N/53kyXChYpPtTcGWgaBFPHO lJ2ZkeoyWs5nPW4EZq0MTy2jLvee9Xid9wr9fo/jQopVlrzxnzct/J5flf6MGBv8 jv1LkK/XA2gSY6zik6eiywTlT2TOA/rGFJ/Zi+jM1GKMa+QALBmfGgbGMYFU+1Mk mq9Vmbqdda64wt0CAwEAAaNCMEAwHQYDVR0OBBYEFGgBk7HSSkBCaZRGLBxaiKkl tEdPMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB DAUAA4ICAQCS/O64AnkXAlF9IcVJZ6ek8agkOOsMaOpaQmuc9HPBaUotszcFUEKY kp4GeSwuBpn2798roM2zkgGDtaDLJ7U8IxqYSaLsLZmlWUOs0rGT1lfXHLyT1sZA 4bNvGVW3E9flQzOktavL2sExZA101iztw41u67uvGUdhYS3A9AW5b3jcOvdCQGVT kb2ZDZOSVKapN1krm8uZxrw99wSE8JQzHQ+CWjnLLkXDKBmjspuYyPwxa2CP9umG KLzgPH10XRaJW2kkxxCLxEu7Nk/UWT/DsKSRmfgu0UoBnfWIEu+/WhFqWU9Za1pn 84+0Ew/A2C89KHKqGX8RfWpbn5XnX7eUT/E+oVr/Lcyd3yd3jzJzHGcKdvP6XLG/ vB29DCibsscXZwszD8O9Ntz7ukILq+2Ew2LWhBapsQdrqW7uxs/msEQpwvCzYYAq i2/SFFwlh1Rk86RMwaH4p2vq/uo6/HnbDo/cxvPJ1Gze6YOhjh0i7Mk6sgB73Dun Qhp/3IupET2Op8Agb10JXUNE5o9mzKlbB/Hvm3oOs1ThlP0OLMaT11X9cZg1uAlK /8YpKCz2Ui3bFBiSJ+IWfozK1GG+goeR65g3P79fXXc/NKwbOEOraHKZMh46Ghml ozhMI9ej58zVKpIXkAtaS70WvfuGauKJmezkoFUYyaMIHxPgMghy0A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICHzCCAaWgAwIBAgIQBk+mpigpFB8OnYNi4RdeOjAKBggqhkjOPQQDAzBRMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKTAnBgNVBAMTIERp Z2lDZXJ0IENsaWVudCBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoX DTQ2MDExNDIzNTk1OVowUTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0 LCBJbmMuMSkwJwYDVQQDEyBEaWdpQ2VydCBDbGllbnQgRUNDIFAzODQgUm9vdCBH NTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGccPoSdUFeo//Ftm0qfjw07rsbG8eqB zMO1usko/cGp2vZs9iBCAYRKWmL9DF88W3kWed3X5delJjH1ZMbzJL/19kUvIYZt 83aXZQUguq+5kcUq7pjF/pcb86fx59LPrqNCMEAwHQYDVR0OBBYEFLMsqpCF7XM8 9c7QwUtG0sVgbZR5MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoG CCqGSM49BAMDA2gAMGUCMA+xAdFskP8ICqhlLebjF8aVdClLedTB64pmR9WrI38F XyW4HOyOxz2nObN2wJVzdAIxAPxsGdjNe5nR/lSqYzVCmsBe59u5HcnCny2HfswZ Nm9hi+opTmtpPNJloAPNqSXojA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIQBMj8A6hU65igmwKIPGajwDANBgkqhkiG9w0BAQwFADBQ MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKDAmBgNVBAMT H0RpZ2lDZXJ0IENsaWVudCBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAw WhcNNDYwMTE0MjM1OTU5WjBQMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl cnQsIEluYy4xKDAmBgNVBAMTH0RpZ2lDZXJ0IENsaWVudCBSU0E0MDk2IFJvb3Qg RzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDj5uj0wpUboAFRLX+I QSuQu82uUBQ2Z5vvcB6iQP+eAEwpG0yWS14MOh8mMifsddzfgmhVsFKbtnxboguE 15i2LlAWtXz5u3f6Mz+krrB2VW1VGG6fF4Yk9EuUMIZyhTeVT8H5rCjRgcu/MWOF eTMCNOD4kT5fcb49xWdRQT4iE3MYDXNRFd5odImBB2yZhmksQQ6Vl/MWA1ZQgWqW 2YbSp1DvlXT+AgPJUb2DvrAA/Rt6I3PfR5ux4sgA6U92sicwkcq696rhA2an39jj 80pCMcwHQ/WouQXqhCf5e0QocgAv8+rzif5MgcFElEk6C1PJAU9nl30lyeDfCmE+ Zoja1fhUoqtUsdXc/iSCZrS3giGWY6KTt7Nwh6EgNPr6WF0vexfIH1y2lDVgw5q7 jiL4prUp3Cbe51dJgU1kue/CPIgLTMwBmNJYLVJEOrPOwz6+zrnDS+XRUbbhMdEy R0HPwJ+Wk1tl55NGtYsVlAJSurMuYlkHtDYFkVNec4Ho/7lMdo/ak3PArTgX7uf4 owW0fV9gNpwqoVBIfhUeRXn4IFEF9uxiHWrRLw2L73RO8aNsNu4TRrE/CIIyu7n0 YLmR4delkuCVoEGFFdjM0Y2htyQy7WOSRbDqB+jkdCDxJrlj9cLHbY2xVuheRRyM vNFAj2LuSb00sKKWwTkd/M1l7wIDAQABo0IwQDAdBgNVHQ4EFgQUk2078qYZI73o uEyOuc/V/vzEvXowDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ KoZIhvcNAQEMBQADggIBAJf7rW+sE2WxsOHVVpktlQqqgbVwgROdfZfVRyH+127F RTQA63zRgbUkkfsLmn7eYl+OUMT7RUYdU0vWsBnhj6GFc4V4lgG0uOg70K+Qa5Lv fPZnUjFmF55q4se9VUqSD2a0RQYAzJu2QQAsCkAKdLbYSsF0KKE1KCS11q7FjpQJ APog8EoWRf+HcFf6MyqaA+awMwy4vsOWO06jolechshjIte2FoLwOHF1j4uK4TUQ twrG651sWHJdC2jEq2XlS9I7gKqHn1ikGiKsq4pRyVN2hmIuLu8vVKfD1XLwoCxf f3T0i+QnCziTjdh5GO6rqvQK9MF5kjpFXnJkNqWaTl0y3GFFNDo3Lo8CtIC2DoVH pILSqMpngrkjnuNNENi3xq6YXBV2oyyHhggwDW9u1Bb2yokrgF1cXdoLfo+811E4 oz3688ZMCpdmhHObOXSf+z1qwJvC4anrv7Lrl2Eb+d5G9lXiKwy0Z+hcVhDWuTl8 4q0yIbA1IbrW0cRQAx2xAEc3u3ZAITXwLmXbUsDpttcIYNqOiVHYeK/7aAzRvkmf ICdRoooBEuLAf+CN0+sxBeYlYUKIAONWBaBDF01dFTkRr1Ebb/Xe38SzyyAeWIVg ZAcMGDpl6+ohzswf6wSVPAxNqDe1t8GeWAM1oDzRSTALzohNU1kgK5YqxhXHkA5A -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICETCCAZegAwIBAgIQDfPZN2WjecWVZuqS4iRPNDAKBggqhkjOPQQDAzBKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xIjAgBgNVBAMTGURp Z2lDZXJ0IEVDQyBQMzg0IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0 MjM1OTU5WjBKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x IjAgBgNVBAMTGURpZ2lDZXJ0IEVDQyBQMzg0IFJvb3QgRzUwdjAQBgcqhkjOPQIB BgUrgQQAIgNiAAT8WR/OmWx/mw62KWNvxoXzCtPWm65XFUwO7V3jCX5tKqOGqrp4 oKdxvUT6CMBKBtZv3SxKOHTl0L3/ev/lOU69vRceH0Ot1bwn2Eu/dowwMqT7+VPl 2Ko4U12ooDegZwqjQjBAMB0GA1UdDgQWBBSSlvfmutURuvkiLnt+WtnwJeUFGzAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBl AjEA/cBN8aSn26cMJhH0Sb0HOGMrRGIGeQjHw9TPmz6rOieqkMf9WaK4MlLbyo4X CwqQAjBdGuxRidRk3PnlHji9Wy7j5UTkOxh61/CVQI/y68/0+dBlokHysOZ8wTYs j1453Tc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI 2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx 1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV 5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY 1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 sycX -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFXjCCA0agAwIBAgIQCL+ib5o/M2WirPCmOMQBcDANBgkqhkiG9w0BAQwFADBJ MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xITAfBgNVBAMT GERpZ2lDZXJ0IFJTQTQwOTYgUm9vdCBHNTAeFw0yMTAxMTUwMDAwMDBaFw00NjAx MTQyMzU5NTlaMEkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5j LjEhMB8GA1UEAxMYRGlnaUNlcnQgUlNBNDA5NiBSb290IEc1MIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAqr4NsgZ9JvlH6uQb50JpuJnCue4ksUaQy1kk UlQ1piTCX5EZyLZC1vNHZZVk54VlZ6mufABP4HgDUK3zf464EeeBYrGL3/JJJgne Dxa82iibociXL5OQ2iAq44TU/6mesC2/tADemx/IoGNTaIVvTYXGqmP5jbI1dmJ0 A9yTmGgFns2QZd3SejGrJC1tQC6QP2NsLOv6HoBUjXkCkBSztU9O9YgEQ4DDSLMm L6xRlTJVJS9BlrBWoQg73JgfcoUsd8qYzDj7jnLJbewF7O1NtzxbFFCF3Zf7WfeQ EvQTv4NNgLIVZRGXYOXWXOYEtVDmcTO2IJOpaAA4zknbtFw7ctdFXFS/zTwBIx58 1vhpLKUACmwySLTecC06ExfBf2TL8zDtoT2WZ/GUtWBsW2lo9YIzCaK22fOFsm6g lPDCxH2hLMpz9a7gUpyiZuYDzurf7RjUuWOL9+j/+7Nbj0PFr7d0lFA1Za7WL/GF j1OhcPSNMl28lsMewgQEnAQPs11+iSDKXicNiUoSI7T2xN3YH/hoszb4HrzG94S2 6IpOiDA4wCbYcAoJOjQOa4ISlhwv5p6t2HE1gbGMBm70bmb/S0quvfD+11xfU7sy PM1i0RSgKR8Q3qlyT7GtZOWDKo+L6oSV7pglmJqzcTzBp1DyrEJiMcKhkMbu4reK qLW2GzsCAwEAAaNCMEAwHQYDVR0OBBYEFGJtt5FPxOqjYmCPoNC+tY8GfGgAMA4G A1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4IC AQBh6PsnbdbiuLMJr6rwsYJM/j0XiU0tFZ377tC7hOyEddtDE96Mn8cp74d0yxNw gVYAdPyu9Nk63iIIUaWgXIJmtntMqdqPq6wcQZZm1p3eVua/TrGyXl/Aw27UwoSQ 9X2xuhbRKYrInenP0McZOz/P7vfhM65CyJjACJ7zWvPf1Cs7jqgoVhnHTnc8JVTc uEhI0fknaj7sE6+yBYn9VV/zfY4NnAldLIp+hc744b8RPTKMWtd+PfQzWM+iBZij s/vOib/9whbdbtyISQ0LoAP/50XpBMHp/aqddfi4H4eD2es501qny5isE4kA/G+V TuF9EUZt9jhGoxOgLAH1Ys+/HFCRJ3Rdt+xHfNDRdct77tFNIwrDYKV3LYDaZw+O a3YH8KYP6oSuHnm/CIraCfP07rU289R6Q7qUNeH6wTsblpmkV2PrtaiC9634d9d2 hvN2U1Zb/CZChM6fg5GRr/S+cBWApdjoabHYkVS4GbJi+aL6Ve0Ev7lEhuTP8ZsA vxEPvrV0JFH/dzRj7EgjDugR63dt2sqCkb6khJNM2qH+zAaE6CHoVLrm0x1jPcJa /ObJg55yZKmGWQCMwvcTg7bQpDHGrJGOe6QiVhPGdccjvItb/EY9/l1SKa+v6MnD dkvoq0cC8poN0yyIgAeGwGMPAkyOBFN2uVhCb3wpcF2/Jw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICHDCCAaOgAwIBAgIQBT9uoAYBcn3tP8OjtqPW7zAKBggqhkjOPQQDAzBQMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKDAmBgNVBAMTH0Rp Z2lDZXJ0IFNNSU1FIEVDQyBQMzg0IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN NDYwMTE0MjM1OTU5WjBQMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs IEluYy4xKDAmBgNVBAMTH0RpZ2lDZXJ0IFNNSU1FIEVDQyBQMzg0IFJvb3QgRzUw djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQWnVXlttT7+2drGtShqtJ3lT6I5QeftnBm ICikiOxwNa+zMv83E0qevAED3oTBuMbmZUeJ8hNVv82lHghgf61/6GGSKc8JR14L HMAfpL/yW7yY75lMzHBrtrrQKB2/vgSjQjBAMB0GA1UdDgQWBBRzemuW20IHi1Jm wmQyF/7gZ5AurTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggq hkjOPQQDAwNnADBkAjA3RPUygONx6/Rtz3zMkZrDbnHY0iNdkk2CQm1cYZX2kfWn CPZql+mclC2YcP0ztgkCMAc8L7lYgl4Po2Kok2fwIMNpvwMsO1CnO69BOMlSSJHW Dvu8YDB8ZD8SHkV/UT70pg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFajCCA1KgAwIBAgIQBfa6BCODRst9XOa5W7ocVTANBgkqhkiG9w0BAQwFADBP MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJzAlBgNVBAMT HkRpZ2lDZXJ0IFNNSU1FIFJTQTQwOTYgUm9vdCBHNTAeFw0yMTAxMTUwMDAwMDBa Fw00NjAxMTQyMzU5NTlaME8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2Vy dCwgSW5jLjEnMCUGA1UEAxMeRGlnaUNlcnQgU01JTUUgUlNBNDA5NiBSb290IEc1 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4Gpb2fj5fey1e+9f3Vw0 2Npd0ctldashfFsA1IJvRYVBiqkSAnIy8BT1A3W7Y5dJD0CZCxoeVqfS0OGr3eUE G+MfFBICiPWggAn2J5pQ8LrjouCsahSRtWs4EHqiMeGRG7e58CtbyHcJdrdRxDYK mVNURCW3CTWGFwVWkz1BtwLXYh+KkhGH6hFt6ggR3LF4SEmS9rRRgHgj2P7hVho6 kBNWNInV4pWLX96yzPs/OLeF9+qevy6hLi9NfWoRLjag/xEIBJVV4Bs7Z5OplFXq Mu0GOn/Cf+OtEyfRNEGzMMO/tIj4A4Kk3z6reHegWZNx593rAAR7zEg5KOAeoxVp yDayoQuX31XW75GcpPYW91EK7gMjkdwE/+DdOPYiAwDCB3EaEsnXRiqUG83Wuxvu v75NUFiwC80wdin1z+W2ai92sLBpatBtZRg1fpO8chfBVULNL8Ilu/T9HaFkIlRd 4p5yQYRucZbqRQe2XnpKhp1zZHc4A9IPU6VVIMRN/2hvVanq3XHkT9mFo3xOKQKe CwnyGlPMAKbd0TT2DcEwsZwCZKw17aWwKbHSlTMP0iAzvewjS/IZ+dqYZOQsMR8u 4Y0cBJUoTYxYzUvlc4KGjOyo1nlc+2S73AxMKPYXr+Jo1haGmNv8AdwxuvicDvko Rkrh/ZYGRXkRaBdlXIsmh1sCAwEAAaNCMEAwHQYDVR0OBBYEFNGj1FcdT1XbdUxc Qp5jFs60xjsfMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG SIb3DQEBDAUAA4ICAQAHpwreU7ua63C/sjaQzeSnuPEM5F1aHXhl/Mm4HiMRV3xp NW0B/1NQvwcOuscBP1gqlHUDqxwLI9wbih43PR1Yj3PZsypv3xCgWwynyrB/uSSi ATUy5V5GQevYf3PnQumkUSZ3gQqo6w8KUJ1+iiBn/AuOOhHTxYxgGNlLsfzU8bRJ Tq6H4dH7dqFf8wbPl5YM6Z51gVxTDSL8NuZJbnTbAIWNfCKgjvsQTNRiE1vvS3Im i/xOio/+lxBTxXiLQmQbX+CJ/bsJf1DgVIUmEWodZflJKdx8Nt/7PffSrO4yjW6m fTmcRcTKDfU7tHlTpS9Wx1HFikxkXZBDI45rTBd4zOi/9TvkqEjPrZsM3zJK09kS jiN4DS2vn6+ePAnClwDtOmkccT8539OPxGb17zaUD/PdkraWX5Cm3XOqpiCUlCVq CQxy5BMjYEyjyhcue2cA29DN6nofOSZXiTB3y07llUVPX/s2XD35ILU6ECVPkzJa 7sGW6OlWBLBJYU3seKidGMH/2OovVu+VK3sEXmfjVUDtOQT5C3n1aoxcD4makMfN i97bJjWhbs2zQvKiDzsMjpP/FM/895P35EEIbhlSEQ9TGXN4DM/YhYH4rVXIsJ5G Y6+cUu5cv/DAWzceCSDSPiPGoRVKDjZ+MMV5arwiiNkMUkAf3U4PZyYW0q0XHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS 7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp 0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 DXZDjC5Ty3zfDBeWUA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv /PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t 9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd +SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N 0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie 4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 /YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ -----END CERTIFICATE-----braintree_python-4.31.0/braintree/status_event.py000066400000000000000000000003601471021343500222230ustar00rootroot00000000000000from 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-4.31.0/braintree/subscription.py000066400000000000000000000214421471021343500222270ustar00rootroot00000000000000from 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://developer.paypal.com/braintree/docs/reference/request/subscription/create/python """ # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class TrialDurationUnit(object): """ Constants representing trial duration units. Available types are: * braintree.Subscription.TrialDurationUnit.Day * braintree.Subscription.TrialDurationUnit.Month """ Day = "day" Month = "month" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class Source(object): Api = "api" ControlPanel = "control_panel" Recurring = "recurring" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class Status(object): """ Constants representing subscription statuses. 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=None): """ Create a Subscription Token and Plan are required::: result = braintree.Subscription.create({ "payment_method_token": "my_payment_token", "plan_id": "some_plan_id", }) """ if params is None: params = {} return Configuration.gateway().subscription.create(params) @staticmethod def create_signature(): return [ "billing_day_of_month", "first_billing_date", "id", "merchant_account_id", "never_expires", "number_of_billing_cycles", "payment_method_nonce", "payment_method_token", "plan_id", "price", "trial_duration", "trial_duration_unit", "trial_period", { "descriptor": ["name", "phone", "url"] }, { "options": [ "do_not_inherit_add_ons_or_discounts", "start_immediately", { "paypal": ["description"] } ] } ] + Subscription._add_ons_discounts_signature() @staticmethod def find(subscription_id): """ Find a subscription given a subscription_id. This does not return a result object. This will raise a :class:`NotFoundError ` if the provided subscription_id is not found. :: subscription = braintree.Subscription.find("my_subscription_id") """ return Configuration.gateway().subscription.find(subscription_id) @staticmethod def retry_charge(subscription_id, amount=None, submit_for_settlement=False): return Configuration.gateway().subscription.retry_charge(subscription_id, amount, submit_for_settlement) @staticmethod def update(subscription_id, params=None): """ Update an existing subscription By subscription_id. The params are similar to create:: result = braintree.Subscription.update("my_subscription_id", { "price": "9.99", }) """ if params is None: params = {} 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 multiple value fields, you can search using the in_list operator. An example:: braintree.Subscription.search([ braintree.SubscriptionSearch.plan_id.starts_with("abc"), braintree.SubscriptionSearch.days_past_due == "30", braintree.SubscriptionSearch.status.in_list([braintree.Subscription.Status.PastDue]) ]) """ return Configuration.gateway().subscription.search(*query) @staticmethod def update_signature(): return [ "id", "merchant_account_id", "never_expires", "number_of_billing_cycles", "payment_method_nonce", "payment_method_token", "plan_id", "price", { "descriptor": [ "name", "phone", "url" ] }, { "options": [ "prorate_charges", "replace_all_add_ons_and_discounts", "revert_subscription_on_proration_failure", { "paypal": [ "description" ] } ] } ] + Subscription._add_ons_discounts_signature() @staticmethod def _add_ons_discounts_signature(): return [ { "add_ons": [{ "add": ["amount", "inherited_from_id", "never_expires", "number_of_billing_cycles", "quantity"], "remove": ["__any_key__"], "update": ["amount", "existing_id", "never_expires", "number_of_billing_cycles", "quantity"] }], "discounts": [{ "add": ["amount", "inherited_from_id", "never_expires", "number_of_billing_cycles", "quantity"], "remove": ["__any_key__"], "update": ["amount", "existing_id", "never_expires", "number_of_billing_cycles", "quantity"] }] } ] def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "price" in attributes: self.price = Decimal(self.price) if "balance" in attributes: self.balance = Decimal(self.balance) if "next_billing_period_amount" in attributes: self.next_billing_period_amount = Decimal(self.next_billing_period_amount) if "add_ons" in attributes: self.add_ons = [AddOn(gateway, add_on) for add_on in self.add_ons] if "descriptor" in attributes: self.descriptor = Descriptor(gateway, attributes.pop("descriptor")) if "description" in attributes: self.description = attributes["description"] if "discounts" in attributes: self.discounts = [Discount(gateway, discount) for discount in self.discounts] if "status_history" in attributes: self.status_history = [SubscriptionStatusEvent(gateway, status_event) for status_event in self.status_history] if "transactions" in attributes: self.transactions = [Transaction(gateway, transaction) for transaction in self.transactions] braintree_python-4.31.0/braintree/subscription_details.py000066400000000000000000000001551471021343500237320ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class SubscriptionDetails(AttributeGetter): pass braintree_python-4.31.0/braintree/subscription_gateway.py000066400000000000000000000104061471021343500237460ustar00rootroot00000000000000import 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=None): if params is None: params = {} Resource.verify_keys(params, Subscription.create_signature()) response = self.config.http().post(self.config.base_merchant_path() + "/subscriptions", {"subscription": params}) if "subscription" in response: return SuccessfulResult({"subscription": Subscription(self.gateway, response["subscription"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def find(self, subscription_id): try: if subscription_id is None or subscription_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/subscriptions/" + subscription_id) return Subscription(self.gateway, response["subscription"]) except NotFoundError: raise NotFoundError("subscription with id " + repr(subscription_id) + " not found") def retry_charge(self, subscription_id, amount=None, submit_for_settlement=False): response = self.config.http().post(self.config.base_merchant_path() + "/transactions", {"transaction": { "amount": amount, "subscription_id": subscription_id, "type": Transaction.Type.Sale, "options": {"submit_for_settlement": submit_for_settlement} }}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def search(self, *query): if isinstance(query[0], list): query = query[0] response = self.config.http().post(self.config.base_merchant_path() + "/subscriptions/advanced_search_ids", {"search": self.__criteria(query)}) return ResourceCollection(query, response, self.__fetch) def update(self, subscription_id, params=None): if params is None: 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-4.31.0/braintree/subscription_search.py000066400000000000000000000016501471021343500235530ustar00rootroot00000000000000from braintree.util import Constants from braintree import Subscription from braintree.search import Search class SubscriptionSearch: billing_cycles_remaining = Search.RangeNodeBuilder("billing_cycles_remaining") created_at = Search.RangeNodeBuilder("created_at") days_past_due = Search.RangeNodeBuilder("days_past_due") id = Search.TextNodeBuilder("id") ids = Search.MultipleValueNodeBuilder("ids") in_trial_period = Search.MultipleValueNodeBuilder("in_trial_period") merchant_account_id = Search.MultipleValueNodeBuilder("merchant_account_id") next_billing_date = Search.RangeNodeBuilder("next_billing_date") plan_id = Search.MultipleValueOrTextNodeBuilder("plan_id") price = Search.RangeNodeBuilder("price") status = Search.MultipleValueNodeBuilder("status", Constants.get_all_constant_values_from_class(Subscription.Status)) transaction_id = Search.TextNodeBuilder("transaction_id") braintree_python-4.31.0/braintree/subscription_status_event.py000066400000000000000000000004471471021343500250350ustar00rootroot00000000000000from 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-4.31.0/braintree/successful_result.py000066400000000000000000000011671471021343500232620ustar00rootroot00000000000000from 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-4.31.0/braintree/test/000077500000000000000000000000001471021343500201055ustar00rootroot00000000000000braintree_python-4.31.0/braintree/test/__init__.py000066400000000000000000000000001471021343500222040ustar00rootroot00000000000000braintree_python-4.31.0/braintree/test/authentication_ids.py000066400000000000000000000026741471021343500243460ustar00rootroot00000000000000class AuthenticationIds(object): ThreeDSecureVisaFullAuthentication = "fake-three-d-secure-visa-full-authentication-id" ThreeDSecureVisaLookupTimeout = "fake-three-d-secure-visa-lookup-timeout-id" ThreeDSecureVisaFailedSignature = "fake-three-d-secure-visa-failed-signature-id" ThreeDSecureVisaFailedAuthentication = "fake-three-d-secure-visa-failed-authentication-id" ThreeDSecureVisaAttemptsNonParticipating = "fake-three-d-secure-visa-attempts-non-participating-id" ThreeDSecureVisaNoteEnrolled = "fake-three-d-secure-visa-not-enrolled-id" ThreeDSecureVisaUnavailable = "fake-three-d-secure-visa-unavailable-id" ThreeDSecureVisaMPILookupError = "fake-three-d-secure-visa-mpi-lookup-error-id" ThreeDSecureVisaMPIAuthenticateError = "fake-three-d-secure-visa-mpi-authenticate-error-id" ThreeDSecureVisaAuthenticationUnavailable = "fake-three-d-secure-visa-authentication-unavailable-id" ThreeDSecureVisaBypassedAuthentication = "fake-three-d-secure-visa-bypassed-authentication-id" ThreeDSecureTwoVisaSuccessfulFrictionlessAuthentication = "fake-three-d-secure-two-visa-successful-frictionless-authentication-id" ThreeDSecureTwoVisaSuccessfulStepUpAuthentication = "fake-three-d-secure-two-visa-successful-step-up-authentication-id" ThreeDSecureTwoVisaErrorOnLookup = "fake-three-d-secure-two-visa-error-on-lookup-id" ThreeDSecureTwoVisaTimeoutOnLookup = "fake-three-d-secure-two-visa-timeout-on-lookup-id" braintree_python-4.31.0/braintree/test/credit_card_defaults.py000066400000000000000000000001411471021343500246050ustar00rootroot00000000000000class CreditCardDefaults(object): CountryOfIssuance = "USA" IssuingBank = "NETWORK ONLY" braintree_python-4.31.0/braintree/test/credit_card_numbers.py000066400000000000000000000024711471021343500244610ustar00rootroot00000000000000class CreditCardNumbers(object): class CardTypeIndicators(object): Commercial = "4111111111131010" DurbinRegulated = "4111161010101010" Debit = "4117101010101010" Healthcare = "4111111510101010" Payroll = "4111111114101010" Prepaid = "4111111111111210" IssuingBank = "4111111141010101" CountryOfIssuance = "4111111111121102" No = "4111111111310101" Unknown = "4111111111112101" Maestro = "6304000000000000" # :nodoc: MasterCard = "5555555555554444" MasterCardInternational = "5105105105105100" # :nodoc: Visa = "4012888888881881" VisaInternational = "4009348888881881" # :nodoc: VisaPrepaid = "4500600000000061" Discover = "6011111111111117" Elo = "5066991111111118" Hiper = "6370950000000005" Hipercard = "6062820524845321" Amex = "378734493671000" class FailsSandboxVerification(object): AmEx = "378734493671000" Discover = "6011000990139424" MasterCard = "5105105105105100" Visa = "4000111111111115" class AmexPayWithPoints(object): Success = "371260714673002" IneligibleCard = "378267515471109" InsufficientPoints = "371544868764018" class Disputes(object): Chargeback = "4023898493988028" braintree_python-4.31.0/braintree/test/merchant_account.py000066400000000000000000000003751471021343500240010ustar00rootroot00000000000000Approve = "approve_me" InsufficientFundsContactUs = "insufficient_funds__contact" AccountNotAuthorizedContactUs = "account_not_authorized__contact" BankRejectedUpdateFundingInformation = "bank_rejected__update" BankRejectedNone = "bank_rejected__none" braintree_python-4.31.0/braintree/test/nonces.py000066400000000000000000000132721471021343500217510ustar00rootroot00000000000000class Nonces(object): AbstractTransactable = "fake-abstract-transactable-nonce" # NEXT_MAJOR_VERSION remove amex express checkout AmexExpressCheckoutCard = "fake-amex-express-checkout-nonce" # NEXT_MAJOR_VERSION - rename AndroidPay to GooglePay AndroidPayCard = "fake-android-pay-nonce" AndroidPayCardAmEx = "fake-android-pay-amex-nonce" AndroidPayCardDiscover = "fake-android-pay-discover-nonce" AndroidPayCardMasterCard = "fake-android-pay-mastercard-nonce" AndroidPayCardVisa = "fake-android-pay-visa-nonce" ApplePayAmEx = "fake-apple-pay-amex-nonce" ApplePayMasterCard = "fake-apple-pay-mastercard-nonce" ApplePayMpan = "fake-apple-pay-mpan-nonce" ApplePayVisa = "fake-apple-pay-visa-nonce" Consumed = "fake-consumed-nonce" Europe = "fake-europe-bank-account-nonce" GatewayRejectedFraud = "fake-gateway-rejected-fraud-nonce" GatewayRejectedRiskThreshold = "fake-gateway-rejected-risk-thresholds-nonce" LocalPayment = "fake-local-payment-method-nonce" LuhnInvalid = "fake-luhn-invalid-nonce" # NEXT_MAJOR_VERSION remove masterpass MasterpassAmEx = "fake-masterpass-amex-nonce" MasterpassDiscover = "fake-masterpass-discover-nonce" MasterpassMasterCard = "fake-masterpass-mastercard-nonce" MasterpassVisa = "fake-masterpass-visa-nonce" PayPalBillingAgreement = "fake-paypal-billing-agreement-nonce" # NEXT_MAJOR_VERSION - no longer supported in the Gateway remove this constant PayPalFuturePayment = "fake-paypal-future-nonce" PayPalFuturePaymentRefreshToken = "fake-paypal-future-refresh-token-nonce" PayPalOneTimePayment = "fake-paypal-one-time-nonce" ProcessorDeclinedAmEx = "fake-processor-declined-amex-nonce" ProcessorDeclinedDiscover = "fake-processor-declined-discover-nonce" ProcessorDeclinedMasterCard = "fake-processor-declined-mastercard-nonce" ProcessorDeclinedVisa = "fake-processor-declined-visa-nonce" ProcessorFailureJCB = "fake-processor-failure-jcb-nonce" SEPA = "fake-sepa-bank-account-nonce" MetaCheckoutCard = "fake-meta-checkout-card-nonce" MetaCheckoutToken = "fake-meta-checkout-token-nonce" VisaCheckoutAmEx = "fake-visa-checkout-amex-nonce" VisaCheckoutDiscover = "fake-visa-checkout-discover-nonce" VisaCheckoutMasterCard = "fake-visa-checkout-mastercard-nonce" VisaCheckoutVisa = "fake-visa-checkout-visa-nonce" # NEXT_MAJOR_VERSION remove SamsungPay nonces SamsungPayAmex = "tokensam_fake_american_express" SamsungPayDiscover = "tokensam_fake_american_express" SamsungPayMasterCard = "tokensam_fake_mastercard" SamsungPayVisa = "tokensam_fake_visa" SepaDirectDebit = "fake-sepa-direct-debit-nonce" ThreeDSecureTwoVisaErrorOnLookup = "fake-three-d-secure-two-visa-error-on-lookup-nonce" ThreeDSecureTwoVisaSuccessfulFrictionlessAuthentication = "fake-three-d-secure-two-visa-successful-frictionless-authentication-nonce" ThreeDSecureTwoVisaSuccessfulStepUpAuthentication = "fake-three-d-secure-two-visa-successful-step-up-authentication-nonce" ThreeDSecureTwoVisaTimeoutOnLookup = "fake-three-d-secure-two-visa-timeout-on-lookup-nonce" ThreeDSecureVisaAttemptsNonParticipating = "fake-three-d-secure-visa-attempts-non-participating-nonce" ThreeDSecureVisaAuthenticationUnavailable = "fake-three-d-secure-visa-authentication-unavailable-nonce" ThreeDSecureVisaBypassedAuthentication = "fake-three-d-secure-visa-bypassed-authentication-nonce" ThreeDSecureVisaFailedAuthentication = "fake-three-d-secure-visa-failed-authentication-nonce" ThreeDSecureVisaFailedSignature = "fake-three-d-secure-visa-failed-signature-nonce" ThreeDSecureVisaFullAuthentication = "fake-three-d-secure-visa-full-authentication-nonce" ThreeDSecureVisaLookupTimeout = "fake-three-d-secure-visa-lookup-timeout-nonce" ThreeDSecureVisaMPIAuthenticateError = "fake-three-d-secure-visa-mpi-authenticate-error-nonce" ThreeDSecureVisaMPILookupError = "fake-three-d-secure-visa-mpi-lookup-error-nonce" ThreeDSecureVisaNoteEnrolled = "fake-three-d-secure-visa-not-enrolled-nonce" ThreeDSecureVisaUnavailable = "fake-three-d-secure-visa-unavailable-nonce" Transactable = "fake-valid-nonce" TransactableAmEx = "fake-valid-amex-nonce" TransactableCommercial = "fake-valid-commercial-nonce" TransactableCountryOfIssuanceCAD = "fake-valid-country-of-issuance-cad-nonce" TransactableCountryOfIssuanceUSA = "fake-valid-country-of-issuance-usa-nonce" TransactableDebit = "fake-valid-debit-nonce" TransactableDinersClub = "fake-valid-dinersclub-nonce" TransactableDiscover = "fake-valid-discover-nonce" TransactableDurbinRegulated = "fake-valid-durbin-regulated-nonce" TransactableHealthcare = "fake-valid-healthcare-nonce" TransactableIssuingBankNetworkOnly = "fake-valid-issuing-bank-network-only-nonce" TransactableJCB = "fake-valid-jcb-nonce" TransactableMaestro = "fake-valid-maestro-nonce" TransactableMasterCard = "fake-valid-mastercard-nonce" TransactableNoIndicators = "fake-valid-no-indicators-nonce" TransactablePayroll = "fake-valid-payroll-nonce" TransactablePinlessDebitVisa = "fake-pinless-debit-visa-nonce" TransactablePrepaid = "fake-valid-prepaid-nonce" TransactableUnknownIndicators = "fake-valid-unknown-indicators-nonce" TransactableVisa = "fake-valid-visa-nonce" VenmoAccount = "fake-venmo-account-nonce" VenmoAccountTokenIssuanceError = "fake-token-issuance-error-venmo-account-nonce" VisaCheckoutAmEx = "fake-visa-checkout-amex-nonce" VisaCheckoutDiscover = "fake-visa-checkout-discover-nonce" VisaCheckoutMasterCard = "fake-visa-checkout-mastercard-nonce" VisaCheckoutVisa = "fake-visa-checkout-visa-nonce" UsBankAccount = "fake-us-bank-account-nonce"braintree_python-4.31.0/braintree/test/venmo_sdk.py000066400000000000000000000004701471021343500224450ustar00rootroot00000000000000def 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-4.31.0/braintree/testing_gateway.py000066400000000000000000000052741471021343500227060ustar00rootroot00000000000000import 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_authentication_id"] 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-4.31.0/braintree/three_d_secure_info.py000066400000000000000000000001521471021343500234710ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter class ThreeDSecureInfo(AttributeGetter): pass braintree_python-4.31.0/braintree/transaction.py000066400000000000000000001201301471021343500220220ustar00rootroot00000000000000import braintree import warnings from decimal import Decimal from braintree.add_on import AddOn from braintree.address import Address from braintree.amex_express_checkout_card import AmexExpressCheckoutCard from braintree.android_pay_card import AndroidPayCard from braintree.apple_pay_card import ApplePayCard from braintree.authorization_adjustment import AuthorizationAdjustment from braintree.configuration import Configuration from braintree.credit_card import CreditCard from braintree.customer import Customer from braintree.descriptor import Descriptor from braintree.disbursement_detail import DisbursementDetail from braintree.discount import Discount from braintree.dispute import Dispute from braintree.error_result import ErrorResult from braintree.europe_bank_account import EuropeBankAccount from braintree.exceptions.not_found_error import NotFoundError from braintree.facilitated_details import FacilitatedDetails from braintree.facilitator_details import FacilitatorDetails from braintree.liability_shift import LiabilityShift from braintree.local_payment import LocalPayment from braintree.masterpass_card import MasterpassCard from braintree.meta_checkout_card import MetaCheckoutCard from braintree.meta_checkout_token import MetaCheckoutToken from braintree.payment_instrument_type import PaymentInstrumentType from braintree.paypal_account import PayPalAccount from braintree.paypal_here import PayPalHere from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.risk_data import RiskData from braintree.samsung_pay_card import SamsungPayCard from braintree.sepa_direct_debit_account import SepaDirectDebitAccount from braintree.package_details import PackageDetails from braintree.status_event import StatusEvent from braintree.subscription_details import SubscriptionDetails from braintree.successful_result import SuccessfulResult from braintree.three_d_secure_info import ThreeDSecureInfo from braintree.transaction_line_item import TransactionLineItem from braintree.us_bank_account import UsBankAccount from braintree.venmo_account import VenmoAccount from braintree.visa_checkout_card import VisaCheckoutCard 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": { "company": "Braintree", "country_name": "United States of America", "extended_address": "Suite 403", "first_name": "Carl", "international_phone": { "country_code": "1", "national_number": "3121234567" }, "last_name": "Jones", "locality": "Chicago", "phone_number": "312-123-4567", "postal_code": "60622", "region": "IL", "street_address": "123 E Main St" }, "shipping": { "company": "Braintree", "country_name": "United States of America", "extended_address": "Apt 2F", "first_name": "Andrew", "international_phone": { "country_code": "1", "national_number": "3121234567" }, "last_name": "Mason", "locality": "Bartlett", "phone_number": "312-123-4567", "postal_code": "60103", "region": "IL", "street_address": "456 W Main St" } }) print(result.transaction.amount) print(result.transaction.order_id) For more information on Transactions, see https://developer.paypal.com/braintree/docs/reference/request/transaction/sale/python """ def __repr__(self): detail_list = [ "acquirer_reference_number", "additional_processor_response", "amount", "authorization_adjustments", "authorization_expires_at", "avs_error_response_code", "avs_postal_code_response_code", "avs_street_address_response_code", "channel", "created_at", "credit_card_details", "currency_iso_code", "customer_id", "cvv_response_code", "debit_network", "discount_amount", "disputes", "escrow_status", "foreign_retailer", "gateway_rejection_reason", "graphql_id", "id", "installments", "liability_shift", "master_merchant_account_id", "merchant_account_id", "merchant_advice_code", "merchant_advice_code_text", "network_response_code", "network_response_text", "network_transaction_id", "order_id", "packages", "payment_instrument_type", "payment_method_token", "plan_id", "processed_with_network_token", "processor_authorization_code", "processor_response_code", "processor_response_text", "processor_settlement_response_code", "processor_settlement_response_text", "purchase_order_number", "recurring", "refund_id", "refunded_transaction_id", "retried", "retried_transaction_id", "retrieval_reference_number", "retry_ids", "service_fee_amount", "settlement_batch_id", "shipping_amount", "shipping_tax_amount", "ships_from_postal_code", "status", "status_history", "sub_merchant_account_id", "subscription_id", "tax_amount", "tax_exempt", "type", "updated_at", "voice_referral_number", ] return super(Transaction, self).__repr__(detail_list) # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ 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" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ 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.ExcessiveRetry * braintree.Transaction.GatewayRejectionReason.Fraud * braintree.Transaction.GatewayRejectionReason.RiskThreshold * braintree.Transaction.GatewayRejectionReason.ThreeDSecure * braintree.Transaction.GatewayRejectionReason.TokenIssuance """ ApplicationIncomplete = "application_incomplete" Avs = "avs" AvsAndCvv = "avs_and_cvv" Cvv = "cvv" Duplicate = "duplicate" ExcessiveRetry = "excessive_retry" Fraud = "fraud" RiskThreshold = "risk_threshold" ThreeDSecure = "three_d_secure" TokenIssuance = "token_issuance" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class ReasonCode(object): ANY_REASON_CODE = 'any_reason_code' # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class Source(object): Api = "api" ControlPanel = "control_panel" Recurring = "recurring" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ 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" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class Status(object): """ Constants representing transaction statuses. Available statuses are: * braintree.Transaction.Status.AuthorizationExpired * braintree.Transaction.Status.Authorized * braintree.Transaction.Status.Authorizing * braintree.Transaction.Status.SettlementPending * braintree.Transaction.Status.SettlementDeclined * braintree.Transaction.Status.Failed * braintree.Transaction.Status.GatewayRejected * braintree.Transaction.Status.ProcessorDeclined * braintree.Transaction.Status.Settled * braintree.Transaction.Status.Settling * braintree.Transaction.Status.SubmittedForSettlement * braintree.Transaction.Status.Voided """ AuthorizationExpired = "authorization_expired" Authorized = "authorized" Authorizing = "authorizing" Failed = "failed" GatewayRejected = "gateway_rejected" ProcessorDeclined = "processor_declined" Settled = "settled" SettlementConfirmed = "settlement_confirmed" SettlementDeclined = "settlement_declined" SettlementFailed = "settlement_failed" SettlementPending = "settlement_pending" Settling = "settling" SubmittedForSettlement = "submitted_for_settlement" Voided = "voided" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class Type(object): """ Constants representing transaction types. Available types are: * braintree.Transaction.Type.Credit * braintree.Transaction.Type.Sale """ Credit = "credit" Sale = "sale" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class IndustryType(object): Lodging = "lodging" TravelAndCruise = "travel_cruise" TravelAndFlight = "travel_flight" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class AdditionalCharge(object): Restaurant = "restaurant" GiftShop = "gift_shop" MiniBar = "mini_bar" Telephone = "telephone" Laundry = "laundry" Other = "other" @staticmethod def adjust_authorization(transaction_id, amount): """ adjust authorization for an existing transaction. It expects a `transaction_id` and `amount`, which is the new total authorization amount result = braintree.Transaction.adjust_authorization("my_transaction_id", "amount") """ return Configuration.gateway().transaction.adjust_authorization(transaction_id, amount) @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 credit(params=None): """ 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" }) """ if params is None: params = {} 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_or_options=None): """ Refunds an existing transaction. It expects a transaction_id.:: result = braintree.Transaction.refund("my_transaction_id") """ return Configuration.gateway().transaction.refund(transaction_id, amount_or_options) @staticmethod def sale(params=None): """ 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" }) """ if params is None: params = {} if "recurring" in params.keys(): warnings.warn("Use transaction_source parameter instead", DeprecationWarning) 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=None): """ Submits an authorized transaction for settlement. Requires the transaction id:: result = braintree.Transaction.submit_for_settlement("my_transaction_id") """ if params is None: params = {} return Configuration.gateway().transaction.submit_for_settlement(transaction_id, amount, params) @staticmethod def update_details(transaction_id, params=None): """ Updates existing details for transaction submitted_for_settlement. Requires the transaction id:: result = braintree.Transaction.update_details("my_transaction_id", { "amount": "100.00", "order_id": "123", "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "url.com" } ) """ if params is None: params = {} return Configuration.gateway().transaction.update_details(transaction_id, params) @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", # NEXT_MAJOR_VERSION use google_pay_card in public API (map to android_pay_card internally) {"android_pay_card": ["number", "cryptogram", "expiration_month", "expiration_year", "eci_indicator", "source_card_type", "source_card_last_four", "google_transaction_id"]}, {"apple_pay_card": ["number", "cardholder_name", "cryptogram", "expiration_month", "expiration_year", "eci_indicator"]}, { "billing": [ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "first_name", {"international_phone": ["country_code", "national_number"]}, "last_name", "locality", "phone_number", "postal_code", "region", "street_address" ] }, "billing_address_id", { "credit_card": [ "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", {"network_tokenization_attributes": ["cryptogram", "ecommerce_indicator", "token_requestor_id"]}, "number", {"payment_reader_card_details": ["encrypted_card_data", "key_serial_number"]}, "token" ] }, { "customer": [ "id", "company", "email", "fax", "first_name", "last_name", "phone", "website" ] }, "customer_id", {"custom_fields": ["__any_key__"]}, "channel", {"descriptor": ["name", "phone", "url"]}, "device_data", "device_session_id", # NEXT_MAJOR_VERSION remove device_session_id "discount_amount", "exchange_rate_quote_id", {"external_vault": ["status", "previous_network_transaction_id"]}, "foreign_retailer", "fraud_merchant_id", # NEXT_MAJOR_VERSION remove fraud_merchant_id {"industry": [ "industry_type", { "data": [ "folio_number", "check_in_date", "check_out_date", "departure_date", "lodging_check_in_date", "lodging_check_out_date", "travel_package", "lodging_name", "room_rate", "passenger_first_name", "passenger_last_name", "passenger_middle_initial", "passenger_title", "issued_date", "travel_agency_name", "travel_agency_code", "ticket_number", "issuing_carrier_code", "customer_code", "fare_amount", "fee_amount", "room_tax", "tax_amount", "restricted_ticket", "no_show", "advanced_deposit", "fire_safe", "property_phone", "arrival_date", "ticket_issuer_address", "date_of_birth", "country_code", { "legs": [ "conjunction_ticket", "exchange_ticket", "coupon_number", "service_class", "carrier_code", "fare_basis_code", "flight_number", "departure_date", "departure_airport_code", "departure_time", "arrival_airport_code", "arrival_time", "stopover_permitted", "fare_amount", "fee_amount", "tax_amount", "endorsement_or_restrictions" ] }, { "additional_charges": [ "kind", "amount" ], } ] } ] }, {"installments": {"count"}}, {"line_items": [ "commodity_code", "description", "discount_amount", "image_url", "kind", "name", "product_code", "quantity", "tax_amount", "total_amount", "unit_amount", "unit_of_measure", "unit_tax_amount", "upc_code", "upc_type", "url", ] }, "merchant_account_id", { "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", # NEXT_MJOR_VERSION remove venmo_sdk_session "payee_id", "payee_email", "skip_advanced_fraud_checking", "skip_avs", "skip_cvv", { "credit_card": [ "account_type", "process_debit_as_credit" ], "paypal": [ "payee_id", "payee_email", "custom_field", "description", {"supplementary_data": ["__any_key__"]} ], "three_d_secure": [ "required" ], "amex_rewards": [ "request_id", "points", "currency_amount", "currency_iso_code" ], "venmo_merchant_data": [ "venmo_merchant_public_id", "originating_transaction_id", "originating_merchant_id", "originating_merchant_kind" ], "venmo": [ "profile_id" ], }, { "adyen": [ "overwrite_brand", "selected_brand" ] }, { "processing_overrides": [ "customer_email", "customer_first_name", "customer_last_name", "customer_tax_identifier" ] } ] }, "order_id", "payment_method_nonce", "payment_method_token", "product_sku", "purchase_order_number", {"paypal_account": ["payee_id", "payee_email", "payer_id", "payment_id"]}, "recurring", { "risk_data": [ "customer_browser", "customer_device_id", "customer_ip", "customer_location_zip", "customer_tenure" ] }, "sca_exemption", "service_fee_amount", "shared_customer_id", "shared_billing_address_id", "shared_payment_method_nonce", "shared_payment_method_token", "shared_shipping_address_id", { "shipping": [ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "first_name", {"international_phone": ["country_code", "national_number"]}, "last_name", "locality", "phone_number", "postal_code", "region", "shipping_method", "street_address" ] }, "shipping_address_id", "shipping_amount", "shipping_tax_amount", "ships_from_postal_code", "tax_amount", "tax_exempt", "three_d_secure_authentication_id", { "three_d_secure_pass_thru": [ "eci_flag", "cavv", "xid", "authentication_response", "directory_response", "cavv_algorithm", "ds_transaction_id", "three_d_secure_version" ] }, "three_d_secure_token", # NEXT_MAJOR_VERSION Remove three_d_secure_token "transaction_source", "type", "venmo_sdk_payment_method_code", # NEXT_MJOR_VERSION remove venmo_sdk_payment_method_code ] @staticmethod def submit_for_settlement_signature(): return [ "order_id", {"descriptor": ["name", "phone", "url"]}, "purchase_order_number", "tax_amount", "tax_exempt", "discount_amount", "shipping_amount", "shipping_tax_amount", "ships_from_postal_code", {"industry": [ "industry_type", { "data": [ "advanced_deposit", "arrival_date", "check_in_date", "check_out_date", "customer_code", "departure_date", "fare_amount", "fee_amount", "fire_safe", "folio_number", "issued_date", "issuing_carrier_code", "lodging_check_in_date", "lodging_check_out_date", "lodging_name", "no_show", "passenger_first_name", "passenger_last_name", "passenger_middle_initial", "passenger_title", "property_phone", "restricted_ticket", "room_rate", "room_tax", "tax_amount", "ticket_issuer_address", "ticket_number", "travel_agency_code", "travel_agency_name", "travel_package", { "legs": [ "arrival_airport_code", "arrival_time", "carrier_code", "conjunction_ticket", "coupon_number", "departure_airport_code", "departure_date", "departure_time", "endorsement_or_restrictions", "exchange_ticket", "fare_amount", "fare_basis_code", "fee_amount", "flight_number", "service_class", "stopover_permitted", "tax_amount" ] }, { "additional_charges": [ "amount", "kind" ], } ] } ] }, {"line_items": [ "commodity_code", "description", "discount_amount", "image_url", "kind", "name", "product_code", "quantity", "tax_amount", "total_amount", "unit_amount", "unit_of_measure", "unit_tax_amount", "upc_code", "upc_type", "url," ] }, {"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", ] }, {"industry": [ "industry_type", { "data": [ "folio_number", "check_in_date", "check_out_date", "departure_date", "lodging_check_in_date", "lodging_check_out_date", "travel_package", "lodging_name", "room_rate", "passenger_first_name", "passenger_last_name", "passenger_middle_initial", "passenger_title", "issued_date", "travel_agency_name", "travel_agency_code", "ticket_number", "issuing_carrier_code", "customer_code", "fare_amount", "fee_amount", "room_tax", "tax_amount", "restricted_ticket", "no_show", "advanced_deposit", "fire_safe", "property_phone", "arrival_date", "ticket_issuer_address", "date_of_birth", "country_code", { "legs": [ "conjunction_ticket", "exchange_ticket", "coupon_number", "service_class", "carrier_code", "fare_basis_code", "flight_number", "departure_date", "departure_airport_code", "departure_time", "arrival_airport_code", "arrival_time", "stopover_permitted", "fare_amount", "fee_amount", "tax_amount", "endorsement_or_restrictions" ] }, { "additional_charges": [ "kind", "amount" ], } ] } ] }, ] @staticmethod def submit_for_partial_settlement_signature(): return Transaction.submit_for_settlement_signature() + [ "final_capture" ] @staticmethod def package_tracking_signature(): return [ "carrier", "notify_payer", "tracking_number", { "line_items": [ "commodity_code", "description", "discount_amount", "image_url", "kind", "name", "product_code", "quantity", "tax_amount", "total_amount", "unit_amount", "unit_of_measure", "unit_tax_amount", "upc_code", "upc_type", "url" ] }, ] @staticmethod def package_tracking(transaction_id, params=None): """ Creates a request to send package tracking information for a transaction which has already submitted for settlement. Requires the transaction id of the transaction and the package tracking request details:: result = braintree.Transaction.package_tracking("my_transaction_id", params ) """ if params is None: params = {} return Configuration.gateway().transaction.package_tracking(transaction_id, params) @staticmethod def update_details_signature(): return ["amount", "order_id", {"descriptor": ["name", "phone", "url"]}] @staticmethod def refund_signature(): return ["amount", "order_id", "merchant_account_id"] @staticmethod def submit_for_partial_settlement(transaction_id, amount, params=None): """ 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") """ if params is None: params = {} return Configuration.gateway().transaction.submit_for_partial_settlement(transaction_id, amount, params) def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) self.amount = Decimal(self.amount) if "tax_amount" in attributes and getattr(self, "tax_amount", None): self.tax_amount = Decimal(self.tax_amount) if "discount_amount" in attributes and getattr(self, "discount_amount", None): self.discount_amount = Decimal(self.discount_amount) if "shipping_amount" in attributes and getattr(self, "shipping_amount", None): self.shipping_amount = Decimal(self.shipping_amount) if "shipping_tax_amount" in attributes and getattr(self, "shipping_tax_amount", None): self.shipping_tax_amount = Decimal(self.shipping_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 "shipments" in attributes: self.packages = [PackageDetails(detail) for detail in self.shipments] if "paypal" in attributes: self.paypal_details = PayPalAccount(gateway, attributes.pop("paypal")) if "paypal_here" in attributes: self.paypal_here_details = PayPalHere(gateway, attributes.pop("paypal_here")) if "local_payment" in attributes: self.local_payment_details = LocalPayment(gateway, attributes.pop("local_payment")) if "sepa_debit_account_detail" in attributes: self.sepa_direct_debit_account_details = SepaDirectDebitAccount(gateway, attributes.pop("sepa_debit_account_detail")) if "europe_bank_account" in attributes: self.europe_bank_account_details = EuropeBankAccount(gateway, attributes.pop("europe_bank_account")) if "us_bank_account" in attributes: self.us_bank_account = UsBankAccount(gateway, attributes.pop("us_bank_account")) if "apple_pay" in attributes: self.apple_pay_details = ApplePayCard(gateway, attributes.pop("apple_pay")) # NEXT_MAJOR_VERSION rename to google_pay_card_details if "android_pay_card" in attributes: self.android_pay_card_details = AndroidPayCard(gateway, attributes.pop("android_pay_card")) # NEXT_MAJOR_VERSION remove amex express checkout if "amex_express_checkout_card" in attributes: self.amex_express_checkout_card_details = AmexExpressCheckoutCard(gateway, attributes.pop("amex_express_checkout_card")) if "venmo_account" in attributes: self.venmo_account_details = VenmoAccount(gateway, attributes.pop("venmo_account")) if "visa_checkout_card" in attributes: self.visa_checkout_card_details = VisaCheckoutCard(gateway, attributes.pop("visa_checkout_card")) # NEXT_MAJOR_VERSION remove masterpass if "masterpass_card" in attributes: self.masterpass_card_details = MasterpassCard(gateway, attributes.pop("masterpass_card")) # NEXT_MAJOR_VERSION remove SamsungPayCard if "samsung_pay_card" in attributes: self.samsung_pay_card_details = SamsungPayCard(gateway, attributes.pop("samsung_pay_card")) if "meta_checkout_card" in attributes: self.meta_checkout_card_details = MetaCheckoutCard(gateway, attributes.pop("meta_checkout_card")) if "meta_checkout_token" in attributes: self.meta_checkout_token_details = MetaCheckoutToken(gateway, attributes.pop("meta_checkout_token")) if "sca_exemption_requested" in attributes: self.sca_exemption_requested = attributes.pop("sca_exemption_requested") else: self.sca_exemption_requested = None if "customer" in attributes: self.customer_details = Customer(gateway, attributes.pop("customer")) if "shipping" in attributes: self.shipping_details = Address(gateway, attributes.pop("shipping")) if "add_ons" in attributes: self.add_ons = [AddOn(gateway, add_on) for add_on in self.add_ons] if "discounts" in attributes: self.discounts = [Discount(gateway, discount) for discount in self.discounts] if "status_history" in attributes: self.status_history = [StatusEvent(gateway, status_event) for status_event in self.status_history] if "subscription" in attributes: self.subscription_details = SubscriptionDetails(attributes.pop("subscription")) if "descriptor" in attributes: self.descriptor = Descriptor(gateway, attributes.pop("descriptor")) if "disbursement_details" in attributes: self.disbursement_details = DisbursementDetail(attributes.pop("disbursement_details")) if "disputes" in attributes: self.disputes = [Dispute(dispute) for dispute in self.disputes] if "authorization_adjustments" in attributes: self.authorization_adjustments = [AuthorizationAdjustment(authorization_adjustment) for authorization_adjustment in self.authorization_adjustments] if "payment_instrument_type" in attributes: self.payment_instrument_type = attributes["payment_instrument_type"] if "risk_data" in attributes: self.risk_data = RiskData(attributes["risk_data"]) else: self.risk_data = None if "three_d_secure_info" in attributes and not attributes["three_d_secure_info"] is None: self.three_d_secure_info = ThreeDSecureInfo(attributes["three_d_secure_info"]) else: self.three_d_secure_info = None if "facilitated_details" in attributes: self.facilitated_details = FacilitatedDetails(attributes.pop("facilitated_details")) if "facilitator_details" in attributes: self.facilitator_details = FacilitatorDetails(attributes.pop("facilitator_details")) if "network_transaction_id" in attributes: self.network_transaction_id = attributes["network_transaction_id"] @property def vault_billing_address(self): """ The vault billing address associated with this transaction """ return self.gateway.address.find(self.customer_details.id, self.billing_details.id) @property def vault_credit_card(self): """ The vault credit card associated with this transaction """ if self.credit_card_details.token is None: return None return self.gateway.credit_card.find(self.credit_card_details.token) @property def vault_customer(self): """ The vault customer associated with this transaction """ if self.customer_details.id is None: return None return self.gateway.customer.find(self.customer_details.id) @property def is_disbursed(self): return self.disbursement_details.is_valid @property def line_items(self): """ The line items associated with this transaction """ return self.gateway.transaction_line_item.find_all(self.id) braintree_python-4.31.0/braintree/transaction_amounts.py000066400000000000000000000003431471021343500235730ustar00rootroot00000000000000class TransactionAmounts(object): """ A class of constants for transaction amounts that will cause different statuses. """ Authorize = "1000.00" Decline = "2000.00" HardDecline = "2015.00" Fail = "3000.00" braintree_python-4.31.0/braintree/transaction_details.py000066400000000000000000000004741471021343500235370ustar00rootroot00000000000000from decimal import Decimal from braintree.attribute_getter import AttributeGetter class TransactionDetails(AttributeGetter): def __init__(self, attributes): AttributeGetter.__init__(self, attributes) if getattr(self, "amount", None) is not None: self.amount = Decimal(self.amount) braintree_python-4.31.0/braintree/transaction_gateway.py000066400000000000000000000255241471021343500235560ustar00rootroot00000000000000import braintree import warnings 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.exceptions.not_found_error import NotFoundError from braintree.exceptions.request_timeout_error import RequestTimeoutError class TransactionGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def adjust_authorization(self, transaction_id, amount): transaction_params = {"amount": amount} response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/adjust_authorization", {"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 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 create(self, params): Resource.verify_keys(params, Transaction.create_signature()) self.__check_for_deprecated_attributes(params) return self._post("/transactions", {"transaction": params}) def credit(self, params): if params is None: params = {} params["type"] = Transaction.Type.Credit return self.create(params) def find(self, transaction_id): try: if transaction_id is None or transaction_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/transactions/" + transaction_id) return Transaction(self.gateway, response["transaction"]) except NotFoundError: raise NotFoundError("transaction with id " + repr(transaction_id) + " not found") def hold_in_escrow(self, transaction_id): """ Holds an existing submerchant transaction for escrow. It expects a transaction_id. :: result = braintree.Transaction.hold_in_escrow("my_transaction_id") """ response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/hold_in_escrow", {}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def refund(self, transaction_id, amount_or_options=None): """ Refunds an existing transaction. It expects a transaction_id. :: result = braintree.Transaction.refund("my_transaction_id") """ if isinstance(amount_or_options, dict): options = amount_or_options else: options = { "amount": amount_or_options } Resource.verify_keys(options, Transaction.refund_signature()) response = self.config.http().post(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/refund", {"transaction": options}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def sale(self, params): if "recurring" in params.keys(): warnings.warn("Use transaction_source parameter instead", DeprecationWarning) 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 RequestTimeoutError("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=None): if params is None: params = {} Resource.verify_keys(params, Transaction.submit_for_settlement_signature()) transaction_params = {"amount": amount} transaction_params.update(params) response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/submit_for_settlement", {"transaction": transaction_params}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def update_details(self, transaction_id, params=None): if params is None: params = {} Resource.verify_keys(params, Transaction.update_details_signature()) response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/update_details", {"transaction": params}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def submit_for_partial_settlement(self, transaction_id, amount, params=None): if params is None: params = {} Resource.verify_keys(params, Transaction.submit_for_partial_settlement_signature()) transaction_params = {"amount": amount} transaction_params.update(params) response = self.config.http().post(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/submit_for_partial_settlement", {"transaction": transaction_params}) if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def package_tracking(self, transaction_id, params=None): try: if params is None: params = {} if transaction_id is None or transaction_id.strip() == "": raise NotFoundError() Resource.verify_keys(params, Transaction.package_tracking_signature()) response = self.config.http().post(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/shipments", {"shipment": 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"]) except NotFoundError: raise NotFoundError("transaction with id " + repr(transaction_id) + " not found") def void(self, transaction_id): response = self.config.http().put(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/void") if "transaction" in response: return SuccessfulResult({"transaction": Transaction(self.gateway, response["transaction"])}) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) def __fetch(self, query, ids): criteria = self.__criteria(query) criteria["ids"] = braintree.transaction_search.TransactionSearch.ids.in_list(ids).to_param() response = self.config.http().post(self.config.base_merchant_path() + "/transactions/advanced_search", {"search": criteria}) if "credit_card_transactions" in response: return [Transaction(self.gateway, item) for item in ResourceCollection._extract_as_array(response["credit_card_transactions"], "transaction")] else: raise RequestTimeoutError("search timeout") def __criteria(self, query): criteria = {} for term in query: if criteria.get(term.name): criteria[term.name] = dict(list(criteria[term.name].items()) + list(term.to_param().items())) else: criteria[term.name] = term.to_param() return criteria def _post(self, url, params=None): if params is None: 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"]) # NEXT_MAJOR_VERSION remove these checks when the attributes are removed def __check_for_deprecated_attributes(self, params): if "device_session_id" in params.keys(): warnings.warn("device_session_id is deprecated, use device_data parameter instead", DeprecationWarning) if "fraud_merchant_id" in params.keys(): warnings.warn("fraud_merchant_id is deprecated, use device_data parameter instead", DeprecationWarning) if "three_d_secure_token" in params.keys(): warnings.warn("three_d_secure_token is deprecated, use three_d_secure_authentication_id parameter instead", DeprecationWarning) if "venmo_sdk_payment_method_code" in params.keys() or "venmo_sdk_session" in params.keys(): warnings.warn("The Venmo SDK integration is Unsupported. Please update your integration to use Pay with Venmo instead.", DeprecationWarning) braintree_python-4.31.0/braintree/transaction_line_item.py000066400000000000000000000023311471021343500240510ustar00rootroot00000000000000import braintree import warnings from braintree.attribute_getter import AttributeGetter from braintree.resource import Resource from braintree.configuration import Configuration class TransactionLineItem(AttributeGetter): pass # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class Kind(object): """ Constants representing transaction line item kinds. Available kinds are: * braintree.TransactionLineItem.Kind.Credit * braintree.TransactionLineItem.Kind.Debit """ Credit = "credit" Debit = "debit" def __init__(self, attributes): AttributeGetter.__init__(self, attributes) @staticmethod def find_all(transaction_id): """ Find all line items on a transaction, given a transaction_id. This returns an array of TransactionLineItems. This will raise a :class:`NotFoundError ` if the provided transaction_id is not found. :: transaction_line_items = braintree.TransactionLineItem.find_all("my_transaction_id") """ return Configuration.gateway().transaction_line_item.find_all(transaction_id) braintree_python-4.31.0/braintree/transaction_line_item_gateway.py000066400000000000000000000022201471021343500255670ustar00rootroot00000000000000import braintree from braintree.error_result import ErrorResult from braintree.resource import Resource from braintree.resource_collection import ResourceCollection from braintree.transaction_line_item import TransactionLineItem from braintree.exceptions.not_found_error import NotFoundError from braintree.exceptions.request_timeout_error import RequestTimeoutError class TransactionLineItemGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def find_all(self, transaction_id): try: if transaction_id is None or transaction_id.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/transactions/" + transaction_id + "/line_items") if "line_items" in response: return [TransactionLineItem(item) for item in ResourceCollection._extract_as_array(response, "line_items")] else: raise RequestTimeoutError() except NotFoundError: raise NotFoundError("transaction line items with id " + repr(transaction_id) + " not found") braintree_python-4.31.0/braintree/transaction_review.py000066400000000000000000000003421471021343500234050ustar00rootroot00000000000000from braintree.resource import Resource class TransactionReview(Resource): """ A class representing a Transaction Review. """ def __init__(self, attributes): Resource.__init__(self, None, attributes) braintree_python-4.31.0/braintree/transaction_search.py000066400000000000000000000137051471021343500233600ustar00rootroot00000000000000from 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") sepa_debit_paypal_v2_order_id = Search.TextNodeBuilder("sepa_debit_paypal_v2_order_id") credit_card_unique_identifier = Search.TextNodeBuilder("credit_card_unique_identifier") store_id = Search.TextNodeBuilder("store_id") 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") store_ids = Search.MultipleValueNodeBuilder("store_ids") 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) ) debit_network = Search.MultipleValueNodeBuilder( "debit_network", Constants.get_all_enum_values(CreditCard.DebitNetwork) ) 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") ach_return_responses_created_at = Search.RangeNodeBuilder("ach_return_responses_created_at") reason_code = Search.MultipleValueNodeBuilder('reason_code') braintree_python-4.31.0/braintree/unknown_payment_method.py000066400000000000000000000003161471021343500242740ustar00rootroot00000000000000import 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-4.31.0/braintree/us_bank_account.py000066400000000000000000000027571471021343500226510ustar00rootroot00000000000000import braintree from braintree.resource import Resource from braintree.configuration import Configuration from braintree.ach_mandate import AchMandate from braintree.us_bank_account_verification import UsBankAccountVerification class UsBankAccount(Resource): @staticmethod def find(token): return Configuration.gateway().us_bank_account.find(token) @staticmethod def sale(token, transactionRequest): transactionRequest["payment_method_token"] = token if not "options" in transactionRequest: transactionRequest["options"] = {} transactionRequest["options"]["submit_for_settlement"] = True return Configuration.gateway().transaction.sale(transactionRequest) @staticmethod def signature(): signature = [ "routing_number", "last_4", "account_type", "account_holder_name", "token", "image_url", "bank_name", "ach_mandate" ] return signature def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if attributes.get("ach_mandate") is not None: self.ach_mandate = AchMandate(gateway, self.ach_mandate) else: self.ach_mandate = None if attributes.get("verifications") is not None: self.verifications = [UsBankAccountVerification(gateway, v) for v in self.verifications] else: self.verifications = None braintree_python-4.31.0/braintree/us_bank_account_gateway.py000066400000000000000000000015321471021343500243600ustar00rootroot00000000000000import braintree from braintree.us_bank_account import UsBankAccount from braintree.exceptions.not_found_error import NotFoundError class UsBankAccountGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def find(self, us_bank_account_token): try: if us_bank_account_token is None or us_bank_account_token.strip() == "": raise NotFoundError() response = self.config.http().get(self.config.base_merchant_path() + "/payment_methods/us_bank_account/" + us_bank_account_token) if "us_bank_account" in response: return UsBankAccount(self.gateway, response["us_bank_account"]) except NotFoundError: raise NotFoundError("US bank account with token " + repr(us_bank_account_token) + " not found") braintree_python-4.31.0/braintree/us_bank_account_verification.py000066400000000000000000000057511471021343500254100ustar00rootroot00000000000000from braintree.attribute_getter import AttributeGetter from braintree.configuration import Configuration import braintree.us_bank_account class UsBankAccountVerification(AttributeGetter): # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class Status(object): """ Constants representing transaction statuses. Available statuses are: * braintree.UsBankAccountVerification.Status.Failed * braintree.UsBankAccountVerification.Status.GatewayRejected * braintree.UsBankAccountVerification.Status.ProcessorDeclined * braintree.UsBankAccountVerification.Status.Unrecognized * braintree.UsBankAccountVerification.Status.Verified * braintree.UsBankAccountVerification.Status.Pending """ Failed = "failed" GatewayRejected = "gateway_rejected" ProcessorDeclined = "processor_declined" Unrecognized = "unrecognized" Verified = "verified" Pending = "pending" # NEXT_MAJOR_VERSION this can be an enum! they were added as of python 3.4 and we support 3.5+ class VerificationMethod(object): """ Constants representing verification types. Available types are: * braintree.UsBankAccountVerification.VerificationMethod.NetworkCheck * braintree.UsBankAccountVerification.VerificationMethod.IndependentCheck * braintree.UsBankAccountVerification.VerificationMethod.TokenizedCheck * braintree.UsBankAccountVerification.VerificationMethod.MicroTransfers """ NetworkCheck = "network_check" IndependentCheck = "independent_check" TokenizedCheck = "tokenized_check" MicroTransfers = "micro_transfers" class VerificationAddOns(object): """ Constants representing verification add on types. Available statuses are: * braintree.UsBankAccountVerification.VerificationAddOns.CustomerVerification """ CustomerVerification = "customer_verification" def __init__(self, gateway, attributes): AttributeGetter.__init__(self, attributes) if attributes.get("us_bank_account") is not None: self.us_bank_account = braintree.us_bank_account.UsBankAccount(gateway, self.us_bank_account) else: self.us_bank_account = None @staticmethod def confirm_micro_transfer_amounts(verification_id, amounts): return Configuration.gateway().us_bank_account_verification.confirm_micro_transfer_amounts(verification_id, amounts) @staticmethod def find(verification_id): return Configuration.gateway().us_bank_account_verification.find(verification_id) @staticmethod def search(*query): return Configuration.gateway().us_bank_account_verification.search(*query) def __eq__(self, other): if not isinstance(other, UsBankAccountVerification): return False return self.id == other.id braintree_python-4.31.0/braintree/us_bank_account_verification_gateway.py000066400000000000000000000066561471021343500271360ustar00rootroot00000000000000from braintree.us_bank_account_verification import UsBankAccountVerification from braintree.us_bank_account_verification_search import UsBankAccountVerificationSearch from braintree.exceptions.not_found_error import NotFoundError from braintree.error_result import ErrorResult from braintree.successful_result import SuccessfulResult from braintree.resource_collection import ResourceCollection class UsBankAccountVerificationGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def confirm_micro_transfer_amounts(self, verification_id, amounts): try: if verification_id is None or verification_id.strip() == "": raise NotFoundError() response = self.config.http().put( self.config.base_merchant_path() + "/us_bank_account_verifications/" + verification_id + "/confirm_micro_transfer_amounts", { "us_bank_account_verification": { "deposit_amounts": amounts, } } ) if "us_bank_account_verification" in response: return SuccessfulResult({ "us_bank_account_verification": UsBankAccountVerification(self.gateway, response["us_bank_account_verification"]) }) elif "api_error_response" in response: return ErrorResult(self.gateway, response["api_error_response"]) except NotFoundError: raise NotFoundError("UsBankAccountVerification with id " + repr(verification_id) + " not found") def find(self, verification_id): try: if verification_id is None or verification_id.strip() == "": raise NotFoundError() response = self.config.http().get( self.config.base_merchant_path() + "/us_bank_account_verifications/" + verification_id ) return UsBankAccountVerification(self.gateway, response["us_bank_account_verification"]) except NotFoundError: raise NotFoundError("UsBankAccountVerification with id " + repr(verification_id) + " not found") def search(self, *query): if isinstance(query[0], list): query = query[0] response = self.config.http().post( self.config.base_merchant_path() + "/us_bank_account_verifications/advanced_search_ids", {"search": self.__criteria(query)} ) return ResourceCollection(query, response, self.__fetch) def __criteria(self, query): criteria = {} for term in query: if criteria.get(term.name): criteria[term.name] = dict(list(criteria[term.name].items()) + list(term.to_param().items())) else: criteria[term.name] = term.to_param() return criteria def __fetch(self, query, ids): criteria = self.__criteria(query) criteria["ids"] = UsBankAccountVerificationSearch.ids.in_list(ids).to_param() response = self.config.http().post( self.config.base_merchant_path() + "/us_bank_account_verifications/advanced_search", {"search": criteria} ) collection_array = ResourceCollection._extract_as_array( response["us_bank_account_verifications"], "us_bank_account_verification" ) return [UsBankAccountVerification(self.gateway, item) for item in collection_array] braintree_python-4.31.0/braintree/us_bank_account_verification_search.py000066400000000000000000000024301471021343500267240ustar00rootroot00000000000000from braintree.us_bank_account import UsBankAccount from braintree.us_bank_account_verification import UsBankAccountVerification from braintree.search import Search from braintree.util import Constants class UsBankAccountVerificationSearch: # Text fields account_holder_name = Search.TextNodeBuilder("account_holder_name") customer_email = Search.TextNodeBuilder("customer_email") customer_id = Search.TextNodeBuilder("customer_id") id = Search.TextNodeBuilder("id") payment_method_token = Search.TextNodeBuilder("payment_method_token") routing_number = Search.TextNodeBuilder("routing_number") # Multiple value fields ids = Search.MultipleValueNodeBuilder("ids") status = Search.MultipleValueNodeBuilder( "status", Constants.get_all_constant_values_from_class(UsBankAccountVerification.Status) ) verification_method = Search.MultipleValueNodeBuilder( "verification_method", Constants.get_all_constant_values_from_class(UsBankAccountVerification.VerificationMethod) ) # Range fields created_at = Search.RangeNodeBuilder("created_at") # Equality fields account_type = Search.EqualityNodeBuilder("account_type") # Ends-with fields account_number = Search.EndsWithNodeBuilder("account_number") braintree_python-4.31.0/braintree/util/000077500000000000000000000000001471021343500201035ustar00rootroot00000000000000braintree_python-4.31.0/braintree/util/__init__.py000066400000000000000000000004711471021343500222160ustar00rootroot00000000000000from braintree.util.constants import Constants from braintree.util.crypto import Crypto from braintree.util.generator import Generator from braintree.util.http import Http from braintree.util.graphql_client import GraphQLClient from braintree.util.parser import Parser from braintree.util.xml_util import XmlUtil braintree_python-4.31.0/braintree/util/constants.py000066400000000000000000000005601471021343500224720ustar00rootroot00000000000000#NEXT_MAJOR_VERSION we can change all Constants to enums, not sure if we'll still need this class Constants(object): @staticmethod def get_all_constant_values_from_class(klass): return [klass.__dict__[item] for item in dir(klass) if not item.startswith("__")] def get_all_enum_values(enum_class): return [item.value for item in enum_class] braintree_python-4.31.0/braintree/util/crypto.py000066400000000000000000000023101471021343500217710ustar00rootroot00000000000000import hashlib import hmac import sys 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-4.31.0/braintree/util/datetime_parser.py000066400000000000000000000020471471021343500236300ustar00rootroot00000000000000import re from datetime import datetime from datetime import timedelta _OFFSET_REGEX = re.compile(r'(\+|\-)(\d\d):(\d\d)$') _SYMBOLS_REGEX = re.compile(r'[-:Z]') def parse_datetime(timestamp): offset_matches = _OFFSET_REGEX.findall(timestamp) if len(offset_matches) == 0: timestamp = _SYMBOLS_REGEX.sub('', timestamp) without_seconds = datetime.strptime(timestamp[:13], '%Y%m%dT%H%M') seconds = timedelta(seconds=float(timestamp[13:])) return without_seconds + seconds else: time_without_offset = parse_datetime(timestamp[:-6]) try: offset_matches = offset_matches[0] offset_is_negative = offset_matches[0] == '-' offset_hours = int(offset_matches[1]) offset_minutes = int(offset_matches[2]) except IndexError: pass offset = timedelta(hours=offset_hours, minutes=offset_minutes) if offset_is_negative: return time_without_offset + offset else: return time_without_offset - offset braintree_python-4.31.0/braintree/util/generator.py000066400000000000000000000047221471021343500224500ustar00rootroot00000000000000import datetime import sys from decimal import Decimal 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 = "<" + self.__escape(key) + " type=\"array\">" return open_tag + self.__generate_list(value) + close_tag elif isinstance(value, bool): open_tag = "<" + self.__escape(key) + " type=\"boolean\">" return open_tag + self.__generate_boolean(value) + close_tag elif isinstance(value, integer_types) and not isinstance(value, bool): open_tag = "<" + self.__escape(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 = "<" + self.__escape(key) + " type=\"datetime\">" return open_tag + self.__generate_datetime(value) + close_tag else: raise RuntimeError("Unexpected XML node type: " + str(type(value))) braintree_python-4.31.0/braintree/util/graphql_client.py000066400000000000000000000054541471021343500234610ustar00rootroot00000000000000import json from braintree.exceptions.authentication_error import AuthenticationError from braintree.exceptions.authorization_error import AuthorizationError from braintree.exceptions.service_unavailable_error import ServiceUnavailableError from braintree.exceptions.not_found_error import NotFoundError from braintree.exceptions.server_error import ServerError from braintree.exceptions.too_many_requests_error import TooManyRequestsError from braintree.exceptions.unexpected_error import UnexpectedError from braintree.exceptions.upgrade_required_error import UpgradeRequiredError from braintree.util.http import Http class GraphQLClient(Http): @staticmethod def raise_exception_for_graphql_error(response): if "errors" not in response: return for error in response["errors"]: if "extensions" in error and "errorClass" in error["extensions"]: error_type = error["extensions"]["errorClass"] if error_type == "VALIDATION": continue elif error_type == "AUTHENTICATION": raise AuthenticationError(error["message"]) elif error_type == "AUTHORIZATION": raise AuthorizationError(error["message"]) elif error_type == "NOT_FOUND": raise NotFoundError elif error_type == "UNSUPPORTED_CLIENT": raise UpgradeRequiredError("Please upgrade your client library.") elif error_type == "RESOURCE_LIMIT": raise TooManyRequestsError elif error_type == "INTERNAL": raise ServerError elif error_type == "SERVICE_AVAILABILITY": raise ServiceUnavailableError else: raise UnexpectedError("Unexpected Response: " + error["message"]) def __init__(self, config=None, environment=None): Http.__init__(self, config, environment) self.graphql_headers = { "Accept": "application/json", "Braintree-Version": config.graphql_api_version(), "Content-Type": "application/json" } def query(self, definition, variables=None, operation_name=None): graphql_request = { "query": definition } if variables is not None: graphql_request["variables"] = variables if operation_name is not None: graphql_request["operationName"] = operation_name response = self._make_request("POST", self.config.graphql_base_url(), Http.ContentType.Json, json.dumps(graphql_request), header_overrides=self.graphql_headers) self.raise_exception_for_graphql_error(response) return response braintree_python-4.31.0/braintree/util/http.py000066400000000000000000000170411471021343500214370ustar00rootroot00000000000000import sys import requests from base64 import encodebytes import json import braintree from braintree import version from braintree.environment import Environment from braintree.util.xml_util import XmlUtil from braintree.exceptions.authentication_error import AuthenticationError from braintree.exceptions.authorization_error import AuthorizationError from braintree.exceptions.gateway_timeout_error import GatewayTimeoutError from braintree.exceptions.http.connection_error import ConnectionError from braintree.exceptions.http.invalid_response_error import InvalidResponseError from braintree.exceptions.http.timeout_error import ConnectTimeoutError from braintree.exceptions.http.timeout_error import ReadTimeoutError from braintree.exceptions.http.timeout_error import TimeoutError from braintree.exceptions.not_found_error import NotFoundError from braintree.exceptions.request_timeout_error import RequestTimeoutError from braintree.exceptions.server_error import ServerError from braintree.exceptions.service_unavailable_error import ServiceUnavailableError from braintree.exceptions.too_many_requests_error import TooManyRequestsError from braintree.exceptions.unexpected_error import UnexpectedError from braintree.exceptions.upgrade_required_error import UpgradeRequiredError class Http(object): class ContentType(object): Xml = "application/xml" Multipart = "multipart/form-data" Json = "application/json" @staticmethod def is_error_status(status): return status not in [200, 201, 204, 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 == 408: raise RequestTimeoutError() elif status == 426: raise UpgradeRequiredError() elif status == 429: raise TooManyRequestsError() elif status == 500: raise ServerError() elif status == 503: raise ServiceUnavailableError() elif status == 504: raise GatewayTimeoutError() else: raise UnexpectedError("Unexpected HTTP_RESPONSE " + str(status)) def __init__(self, config, environment=None): self.config = config self.environment = environment or self.config.environment def post(self, path, params=None): return self._make_request("POST", path, Http.ContentType.Xml, params) def delete(self, path): return self._make_request("DELETE", path, Http.ContentType.Xml) def get(self, path): return self._make_request("GET", path, Http.ContentType.Xml) def put(self, path, params=None): return self._make_request("PUT", path, Http.ContentType.Xml, params) def post_multipart(self, path, files, params=None): return self._make_request("POST", path, Http.ContentType.Multipart, params, files) def _make_request(self, http_verb, path, content_type, params=None, files=None, header_overrides=None): http_strategy = self.config.http_strategy() headers = self.__headers(content_type, header_overrides) request_body = self.__request_body(content_type, params, files) full_path = self.__full_path(path) try: status, response_body = http_strategy.http_do(http_verb, full_path, headers, request_body) except Exception as e: if self.config.wrap_http_exceptions: http_strategy.handle_exception(e) else: raise if Http.is_error_status(status): Http.raise_exception_from_status(status) else: if len(response_body.strip()) == 0: return {} else: if content_type == Http.ContentType.Json: return json.loads(response_body) else: return XmlUtil.dict_from_xml(response_body) def http_do(self, http_verb, path, headers, request_body): data = request_body files = None full_path = self.__full_path(path) if type(request_body) is tuple: data = request_body[0] files = request_body[1] if (self.config.environment == Environment.Development): verify = False else: verify = self.environment.ssl_certificate with requests.Session() as session: request = requests.Request( method=http_verb, url=full_path, headers=headers, data=data, files=files) prepared_request = request.prepare() prepared_request.url = full_path # there's a bug in requests module that requires we manually update proxy settings, # see https://github.com/psf/requests/issues/5677 session.proxies.update(requests.utils.getproxies()) response = session.send(prepared_request, verify=verify, timeout=self.config.timeout) return [response.status_code, response.text] def handle_exception(self, exception): if isinstance(exception, requests.exceptions.ReadTimeout): raise ReadTimeoutError(exception) elif isinstance(exception, requests.exceptions.ConnectTimeout): raise ConnectTimeoutError(exception) elif isinstance(exception, requests.exceptions.ConnectionError): raise ConnectionError(exception) elif isinstance(exception, requests.exceptions.HTTPError): raise InvalidResponseError(exception) elif isinstance(exception, requests.exceptions.Timeout): raise TimeoutError(exception) else: raise UnexpectedError(exception) def __authorization_header(self): if self.config.has_client_credentials(): return b"Basic " + encodebytes( self.config.client_id.encode('ascii') + b":" + self.config.client_secret.encode('ascii') ).replace(b"\n", b"").strip() elif self.config.has_access_token(): return b"Bearer " + self.config.access_token.encode('ascii') else: return b"Basic " + encodebytes( self.config.public_key.encode('ascii') + b":" + self.config.private_key.encode('ascii') ).replace(b"\n", b"").strip() def __headers(self, content_type, header_overrides=None): headers = { "Accept": "application/xml", "Authorization": self.__authorization_header(), "User-Agent": "Braintree Python " + version.Version, "Accept-Encoding": "gzip", "X-ApiVersion": braintree.configuration.Configuration.api_version() } if content_type == Http.ContentType.Xml: headers["Content-type"] = Http.ContentType.Xml headers.update(header_overrides or {}) return headers def __request_body(self, content_type, params, files): if content_type == Http.ContentType.Xml: request_body = XmlUtil.xml_from_dict(params) if params else '' return request_body elif files == None: return params else: return (params, files) def __full_path(self, path): return path if path.startswith(self.config.base_url()) or path.startswith(self.config.graphql_base_url()) else (self.config.base_url() + path) braintree_python-4.31.0/braintree/util/parser.py000066400000000000000000000063251471021343500217570ustar00rootroot00000000000000from xml.dom import minidom from datetime import datetime from braintree.util.datetime_parser import parse_datetime import re import sys 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(r">\s+<", xml)).strip()) def parse(self): return {self.__underscored(self.doc.documentElement.tagName): self.__parse_node(self.doc.documentElement)} def __parse_node(self, root): child = root.firstChild if self.__get_node_attribute(root, "type") == "array": return self.__build_list(child) elif not child: return self.__node_content(root, None) elif (child.nodeType == minidom.Node.TEXT_NODE): return self.__node_content(root, child.nodeValue) else: return self.__build_dict(child) def __convert_to_boolean(self, value): if value == "true" or value == "1": return True else: return False def __convert_to_date(self, value): return datetime.strptime(value, "%Y-%m-%d").date() def __convert_to_datetime(self, value): return parse_datetime(value) def __convert_to_list(self, dict, key): val = dict[key] if not isinstance(val, list): dict[key] = [val] def __build_list(self, child): l = [] while child is not None: if (child.nodeType == minidom.Node.ELEMENT_NODE): l.append(self.__parse_node(child)) child = child.nextSibling return l def __build_dict(self, child): d = {} while child is not None: if (child.nodeType == minidom.Node.ELEMENT_NODE): child_tag = self.__underscored(child.tagName) if self.__get_node_attribute(child, "type") == "array" or child.firstChild and child.firstChild.nodeType == minidom.Node.TEXT_NODE: d[child_tag] = self.__parse_node(child) else: if not d.get(child_tag): d[child_tag] = self.__parse_node(child) else: self.__convert_to_list(d, child_tag) d[child_tag].append(self.__parse_node(child)) child = child.nextSibling return d def __get_node_attribute(self, node, attribute): attribute_node = node.attributes.get(attribute) return attribute_node and attribute_node.value def __node_content(self, parent, content): parent_type = self.__get_node_attribute(parent, "type") parent_nil = self.__get_node_attribute(parent, "nil") if parent_type == "integer": return int(content) elif parent_type == "boolean": return self.__convert_to_boolean(content) elif parent_type == "datetime": return self.__convert_to_datetime(content) elif parent_type == "date": return self.__convert_to_date(content) elif parent_nil == "true": return None else: return content or "" def __underscored(self, string): return string.replace("-", "_") braintree_python-4.31.0/braintree/util/xml_util.py000066400000000000000000000004331471021343500223120ustar00rootroot00000000000000from 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-4.31.0/braintree/validation_error.py000066400000000000000000000007111471021343500230420ustar00rootroot00000000000000from 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-4.31.0/braintree/validation_error_collection.py000066400000000000000000000057501471021343500252650ustar00rootroot00000000000000from braintree.validation_error import ValidationError class ValidationErrorCollection(object): """ A class representing a collection of validation errors. For more information on ValidationErrors, see https://developer.paypal.com/braintree/docs/reference/general/validation-errors/overview/python """ def __init__(self, data=None): if data is None: 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-4.31.0/braintree/venmo_account.py000066400000000000000000000006551471021343500223460ustar00rootroot00000000000000import 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-4.31.0/braintree/venmo_profile_data.py000066400000000000000000000003721471021343500233370ustar00rootroot00000000000000from braintree.resource import Resource class VenmoProfileData(Resource): """ A class representing Braintree VenmoProfileData object. """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) braintree_python-4.31.0/braintree/version.py000066400000000000000000000000231471021343500211600ustar00rootroot00000000000000Version = "4.31.0" braintree_python-4.31.0/braintree/visa_checkout_card.py000066400000000000000000000024531471021343500233240ustar00rootroot00000000000000import braintree from braintree.address import Address from braintree.resource import Resource from braintree.credit_card_verification import CreditCardVerification class VisaCheckoutCard(Resource): """ A class representing Visa Checkout card """ def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "billing_address" in attributes: self.billing_address = Address(gateway, self.billing_address) else: self.billing_address = None if "subscriptions" in attributes: self.subscriptions = [braintree.subscription.Subscription(gateway, subscription) for subscription in self.subscriptions] if "verifications" in attributes: sorted_verifications = sorted(attributes["verifications"], key=lambda verification: verification["created_at"], reverse=True) if len(sorted_verifications) > 0: self.verification = CreditCardVerification(gateway, sorted_verifications[0]) @property def expiration_date(self): if not self.expiration_month or not self.expiration_year: return None return self.expiration_month + "/" + self.expiration_year @property def masked_number(self): return self.bin + "******" + self.last_4 braintree_python-4.31.0/braintree/webhook_notification.py000066400000000000000000000201651471021343500237100ustar00rootroot00000000000000from braintree.account_updater_daily_report import AccountUpdaterDailyReport from braintree.configuration import Configuration from braintree.connected_merchant_paypal_status_changed import ConnectedMerchantPayPalStatusChanged from braintree.connected_merchant_status_transitioned import ConnectedMerchantStatusTransitioned from braintree.disbursement import Disbursement from braintree.dispute import Dispute from braintree.error_result import ErrorResult from braintree.granted_payment_instrument_update import GrantedPaymentInstrumentUpdate from braintree.local_payment_completed import LocalPaymentCompleted from braintree.local_payment_expired import LocalPaymentExpired from braintree.local_payment_funded import LocalPaymentFunded from braintree.local_payment_reversed import LocalPaymentReversed from braintree.merchant_account import MerchantAccount from braintree.oauth_access_revocation import OAuthAccessRevocation from braintree.partner_merchant import PartnerMerchant from braintree.payment_method_customer_data_updated_metadata import PaymentMethodCustomerDataUpdatedMetadata from braintree.resource import Resource from braintree.revoked_payment_method_metadata import RevokedPaymentMethodMetadata from braintree.subscription import Subscription from braintree.transaction import Transaction from braintree.transaction_review import TransactionReview from braintree.validation_error_collection import ValidationErrorCollection class WebhookNotification(Resource): class Kind(object): AccountUpdaterDailyReport = "account_updater_daily_report" Check = "check" ConnectedMerchantPayPalStatusChanged = "connected_merchant_paypal_status_changed" ConnectedMerchantStatusTransitioned = "connected_merchant_status_transitioned" Disbursement = "disbursement" DisbursementException = "disbursement_exception" DisputeAccepted = "dispute_accepted" DisputeAutoAccepted = "dispute_auto_accepted" DisputeDisputed = "dispute_disputed" DisputeExpired = "dispute_expired" DisputeLost = "dispute_lost" DisputeOpened = "dispute_opened" DisputeUnderReview = "dispute_under_review" DisputeWon = "dispute_won" GrantedPaymentMethodRevoked = "granted_payment_method_revoked" GrantorUpdatedGrantedPaymentMethod = "grantor_updated_granted_payment_method" LocalPaymentCompleted = "local_payment_completed" LocalPaymentExpired = "local_payment_expired" LocalPaymentFunded = "local_payment_funded" LocalPaymentReversed = "local_payment_reversed" OAuthAccessRevoked = "oauth_access_revoked" PartnerMerchantConnected = "partner_merchant_connected" PartnerMerchantDeclined = "partner_merchant_declined" PartnerMerchantDisconnected = "partner_merchant_disconnected" PaymentMethodCustomerDataUpdated = "payment_method_customer_data_updated" PaymentMethodRevokedByCustomer = "payment_method_revoked_by_customer" RecipientUpdatedGrantedPaymentMethod = "recipient_updated_granted_payment_method" RefundFailed = "refund_failed" SubMerchantAccountApproved = "sub_merchant_account_approved" SubMerchantAccountDeclined = "sub_merchant_account_declined" SubscriptionBillingSkipped = "subscription_billing_skipped" 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" TransactionDisbursed = "transaction_disbursed" TransactionReviewed = "transaction_reviewed" TransactionSettled = "transaction_settled" TransactionSettlementDeclined = "transaction_settlement_declined" @staticmethod def parse(signature, payload): return Configuration.gateway().webhook_notification.parse(signature, payload) @staticmethod def verify(challenge): return Configuration.gateway().webhook_notification.verify(challenge) def __init__(self, gateway, attributes): Resource.__init__(self, gateway, attributes) if "source_merchant_id" not in attributes: self.source_merchant_id = None if "api_error_response" in attributes["subject"]: node_wrapper = attributes["subject"]["api_error_response"] else: node_wrapper = attributes["subject"] if "subscription" in node_wrapper: self.subscription = Subscription(gateway, node_wrapper['subscription']) elif "merchant_account" in node_wrapper: self.merchant_account = MerchantAccount(gateway, node_wrapper['merchant_account']) elif "transaction" in node_wrapper: self.transaction = Transaction(gateway, node_wrapper['transaction']) elif "transaction_review" in node_wrapper: self.transaction_review = TransactionReview(node_wrapper['transaction_review']) elif "connected_merchant_status_transitioned" in node_wrapper: self.connected_merchant_status_transitioned = ConnectedMerchantStatusTransitioned(gateway, node_wrapper['connected_merchant_status_transitioned']) elif "connected_merchant_paypal_status_changed" in node_wrapper: self.connected_merchant_paypal_status_changed = ConnectedMerchantPayPalStatusChanged(gateway, node_wrapper['connected_merchant_paypal_status_changed']) elif "partner_merchant" in node_wrapper: self.partner_merchant = PartnerMerchant(gateway, node_wrapper['partner_merchant']) elif "oauth_application_revocation" in node_wrapper: self.oauth_access_revocation = OAuthAccessRevocation(node_wrapper["oauth_application_revocation"]) elif "disbursement" in node_wrapper: self.disbursement = Disbursement(gateway, node_wrapper['disbursement']) elif "dispute" in node_wrapper: self.dispute = Dispute(node_wrapper['dispute']) elif "account_updater_daily_report" in node_wrapper: self.account_updater_daily_report = AccountUpdaterDailyReport(gateway, node_wrapper['account_updater_daily_report']) elif "granted_payment_instrument_update" in node_wrapper: self.granted_payment_instrument_update = GrantedPaymentInstrumentUpdate(gateway, node_wrapper["granted_payment_instrument_update"]) elif attributes["kind"] in [WebhookNotification.Kind.GrantedPaymentMethodRevoked, WebhookNotification.Kind.PaymentMethodRevokedByCustomer]: self.revoked_payment_method_metadata = RevokedPaymentMethodMetadata(gateway, node_wrapper) elif "local_payment" in node_wrapper and attributes["kind"] == WebhookNotification.Kind.LocalPaymentCompleted: self.local_payment_completed = LocalPaymentCompleted(gateway, node_wrapper["local_payment"]) elif "local_payment_expired" in node_wrapper and attributes["kind"] == WebhookNotification.Kind.LocalPaymentExpired: self.local_payment_expired = LocalPaymentExpired(gateway, node_wrapper["local_payment_expired"]) elif "local_payment_funded" in node_wrapper and attributes["kind"] == WebhookNotification.Kind.LocalPaymentFunded: self.local_payment_funded = LocalPaymentFunded(gateway, node_wrapper["local_payment_funded"]) elif "local_payment_reversed" in node_wrapper and attributes["kind"] == WebhookNotification.Kind.LocalPaymentReversed: self.local_payment_reversed = LocalPaymentReversed(gateway, node_wrapper["local_payment_reversed"]) elif "payment_method_customer_data_updated_metadata" in node_wrapper and attributes["kind"] == WebhookNotification.Kind.PaymentMethodCustomerDataUpdated: self.payment_method_customer_data_updated_metadata = PaymentMethodCustomerDataUpdatedMetadata(gateway, node_wrapper["payment_method_customer_data_updated_metadata"]) if "errors" in node_wrapper: self.errors = ValidationErrorCollection(node_wrapper['errors']) self.message = node_wrapper['message'] braintree_python-4.31.0/braintree/webhook_notification_gateway.py000066400000000000000000000045631471021343500254350ustar00rootroot00000000000000import re import sys from base64 import decodebytes import sys from braintree.exceptions.invalid_signature_error import InvalidSignatureError from braintree.exceptions.invalid_challenge_error import InvalidChallengeError from braintree.util.crypto import Crypto from braintree.util.xml_util import XmlUtil from braintree.webhook_notification import WebhookNotification text_type = str class WebhookNotificationGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def parse(self, signature, payload): if signature is None: raise InvalidSignatureError("signature cannot be blank") if payload is None: raise InvalidSignatureError("payload cannot be blank") if isinstance(payload, text_type): payload = payload.encode('ascii') if re.search(b"[^A-Za-z0-9+=/\n]", payload): raise InvalidSignatureError("payload contains illegal characters") self.__validate_signature(signature, payload) attributes = XmlUtil.dict_from_xml(decodebytes(payload)) return WebhookNotification(self.gateway, attributes['notification']) def verify(self, challenge): if not re.match("^[a-f0-9]{20,32}$", challenge): raise InvalidChallengeError("challenge contains non-hex characters") digest = Crypto.sha1_hmac_hash(self.config.private_key, challenge) return "%s|%s" % (self.config.public_key, digest) def __matching_signature(self, signature_pairs): for public_key, signature in signature_pairs: if public_key == self.config.public_key: return signature return None def __validate_signature(self, signature_string, payload): signature_pairs = [pair.split("|") for pair in signature_string.split("&") if "|" in pair] signature = self.__matching_signature(signature_pairs) if not signature: raise InvalidSignatureError("no matching public key") if not any(self.__payload_matches(signature, p) for p in [payload, payload + b"\n"]): raise InvalidSignatureError("signature does not match payload - one has been modified") def __payload_matches(self, signature, payload): payload_signature = Crypto.sha1_hmac_hash(self.config.private_key, payload) return Crypto.secure_compare(payload_signature, signature) braintree_python-4.31.0/braintree/webhook_testing.py000066400000000000000000000004351471021343500226750ustar00rootroot00000000000000import braintree from braintree.configuration import Configuration class WebhookTesting(object): @staticmethod def sample_notification(kind, id, source_merchant_id=None): return Configuration.gateway().webhook_testing.sample_notification(kind, id, source_merchant_id) braintree_python-4.31.0/braintree/webhook_testing_gateway.py000066400000000000000000001373501471021343500244250ustar00rootroot00000000000000from braintree.util.crypto import Crypto from braintree.webhook_notification import WebhookNotification import sys from base64 import encodebytes from datetime import datetime class WebhookTestingGateway(object): def __init__(self, gateway): self.gateway = gateway self.config = gateway.config def sample_notification(self, kind, id, source_merchant_id=None): payload = encodebytes(self.__sample_xml(kind, id, source_merchant_id)) hmac_payload = Crypto.sha1_hmac_hash(self.gateway.config.private_key, payload) signature = "%s|%s" % (self.gateway.config.public_key, hmac_payload) return {'bt_signature': signature, 'bt_payload': payload} def __sample_xml(self, kind, id, source_merchant_id): timestamp = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") source_merchant_id_xml = '' if source_merchant_id is not None: source_merchant_id_xml = '%s' % source_merchant_id sample_xml = """ %s %s %s %s """ % (timestamp, kind, source_merchant_id_xml, self.__subject_sample_xml(kind, id)) return sample_xml.encode('utf-8') def __subject_sample_xml(self, kind, id): if kind == WebhookNotification.Kind.Check: return self.__check_sample_xml() if kind == WebhookNotification.Kind.ConnectedMerchantStatusTransitioned: return self.__connected_merchant_status_transitioned_xml(id) if kind == WebhookNotification.Kind.ConnectedMerchantPayPalStatusChanged: return self.__connected_merchant_paypal_status_changed_xml(id) if kind == WebhookNotification.Kind.SubMerchantAccountApproved: return self.__merchant_account_approved_sample_xml(id) elif kind == WebhookNotification.Kind.SubMerchantAccountDeclined: return self.__merchant_account_declined_sample_xml(id) elif kind == WebhookNotification.Kind.TransactionDisbursed: return self.__transaction_disbursed_sample_xml(id) elif kind == WebhookNotification.Kind.TransactionReviewed: return self.__transaction_reviewed_sample_xml(id) elif kind == WebhookNotification.Kind.TransactionSettled: return self.__transaction_settled_sample_xml(id) elif kind == WebhookNotification.Kind.TransactionSettlementDeclined: return self.__transaction_settlement_declined_sample_xml(id) elif kind == WebhookNotification.Kind.PartnerMerchantConnected: return self.__partner_merchant_connected_sample_xml() elif kind == WebhookNotification.Kind.PartnerMerchantDisconnected: return self.__partner_merchant_disconnected_sample_xml() elif kind == WebhookNotification.Kind.PartnerMerchantDeclined: return self.__partner_merchant_declined_sample_xml() elif kind == WebhookNotification.Kind.OAuthAccessRevoked: return self.__oauth_access_revocation_sample_xml(id) elif kind == WebhookNotification.Kind.DisbursementException: return self.__disbursement_exception_sample_xml(id) elif kind == WebhookNotification.Kind.Disbursement: return self.__disbursement_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeAccepted: return self.__dispute_accepted_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeAutoAccepted: return self.__dispute_auto_accepted_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeDisputed: return self.__dispute_disputed_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeExpired: return self.__dispute_expired_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeLost: return self.__dispute_lost_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeOpened: return self.__dispute_opened_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeUnderReview: return self.__dispute_under_review_sample_xml(id) elif kind == WebhookNotification.Kind.DisputeWon: return self.__dispute_won_sample_xml(id) elif kind == WebhookNotification.Kind.RefundFailed: return self.__refund_failed_sample_xml(id) elif kind == WebhookNotification.Kind.SubscriptionBillingSkipped: return self.__subscription_billing_skipped_sample_xml(id) elif kind == WebhookNotification.Kind.SubscriptionChargedSuccessfully: return self.__subscription_charged_successfully_sample_xml(id) elif kind == WebhookNotification.Kind.SubscriptionChargedUnsuccessfully: return self.__subscription_charged_unsuccessfully_sample_xml(id) elif kind == WebhookNotification.Kind.AccountUpdaterDailyReport: return self.__account_updater_daily_report_sample_xml() elif kind == WebhookNotification.Kind.GrantorUpdatedGrantedPaymentMethod: return self.__granted_payment_instrument_update() elif kind == WebhookNotification.Kind.RecipientUpdatedGrantedPaymentMethod: return self.__granted_payment_instrument_update() elif kind == WebhookNotification.Kind.PaymentMethodRevokedByCustomer: return self.__payment_method_revoked_by_customer(id) elif kind == WebhookNotification.Kind.GrantedPaymentMethodRevoked: return self.__granted_payment_method_revoked(id) elif kind == WebhookNotification.Kind.LocalPaymentCompleted: return self.__local_payment_completed(id) elif kind == WebhookNotification.Kind.LocalPaymentExpired: return self.__local_payment_expired() elif kind == WebhookNotification.Kind.LocalPaymentFunded: return self.__local_payment_funded() elif kind == WebhookNotification.Kind.LocalPaymentReversed: return self.__local_payment_reversed() elif kind == WebhookNotification.Kind.PaymentMethodCustomerDataUpdated: return self.__payment_method_customer_data_updated_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 __transaction_reviewed_sample_xml(self, id): return """ %s a smart decision hey@girl.com I reviewed this 2021-04-20T06:09:00Z """ % id def __transaction_settled_sample_xml(self, id): return """ %s settled sale USD 100.00 ogaotkivejpfayqfeaimuktty us_bank_account 123456789 1234 checking Dan Schulman 0 """ % id def __transaction_settlement_declined_sample_xml(self, id): return """ %s settlement_declined sale USD 100.00 ogaotkivejpfayqfeaimuktty us_bank_account 123456789 1234 checking Dan Schulman 0 """ % id def __disbursement_exception_sample_xml(self, id): return """ %s afv56j kj8hjk false false merchant_account_token USD false active 100.00 2014-02-09 bank_rejected update_funding_information """ % id def __disbursement_sample_xml(self, id): return """ %s afv56j kj8hjk true false merchant_account_token USD false active 100.00 2014-02-09 """ % id def __dispute_under_review_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_under_review_sample_xml(id) else: return self.__new_dispute_under_review_sample_xml(id) def __dispute_opened_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_opened_sample_xml(id) else: return self.__new_dispute_opened_sample_xml(id) def __dispute_lost_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_lost_sample_xml(id) else: return self.__new_dispute_lost_sample_xml(id) def __dispute_won_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_won_sample_xml(id) else: return self.__new_dispute_won_sample_xml(id) def __dispute_accepted_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_accepted_sample_xml(id) else: return self.__new_dispute_accepted_sample_xml(id) def __dispute_auto_accepted_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_auto_accepted_sample_xml(id) else: return self.__new_dispute_auto_accepted_sample_xml(id) def __dispute_disputed_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_disputed_sample_xml(id) else: return self.__new_dispute_disputed_sample_xml(id) def __dispute_expired_sample_xml(self, id): if id == "legacy_dispute_id": return self.__old_dispute_expired_sample_xml(id) else: return self.__new_dispute_expired_sample_xml(id) def __old_dispute_under_review_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback under_review fraud %s %s 250.00 2014-03-28 """ % (id, id) def __old_dispute_opened_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback open fraud %s %s 250.00 2014-03-28 """ % (id, id) def __old_dispute_lost_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback lost fraud %s %s 250.00 2014-03-28 """ % (id, id) def __old_dispute_won_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback won fraud %s %s 250.00 2014-03-28 2014-09-01 """ % (id, id) def __old_dispute_accepted_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback accepted fraud %s %s 250.00 2014-03-28 """ % (id, id) def __old_dispute_auto_accepted_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback auto_accepted fraud %s %s 250.00 2014-03-28 """ % (id, id) def __old_dispute_disputed_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback disputed fraud %s %s 250.00 2014-03-28 """ % (id, id) def __old_dispute_expired_sample_xml(self, id): return """ 250.00 USD 2014-03-01 2014-03-21 chargeback expired fraud %s %s 250.00 2014-03-28 """ % (id, id) def __new_dispute_under_review_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 under_review 2017-06-16T20:44:41Z 9qde5qgp under_review 2017-06-15T20:44:41Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 """ % (id, id) def __new_dispute_opened_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 open 2017-06-16T20:44:41Z 9qde5qgp open 2017-06-16T20:44:41Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 """ % (id, id) def __new_dispute_lost_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 lost 2017-06-21T20:44:41Z 9qde5qgp open 2017-06-16T20:44:41Z lost 2017-06-25T20:50:55Z rxtngk9j5j93tsrq 2017-06-21T20:44:42Z s3.amazonaws.com/foo.jpg 88cfb8dd text evidence 2017-06-21T20:44:42Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 """ % (id, id) def __new_dispute_won_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 won 2017-06-21T20:44:41Z 9qde5qgp open 2017-06-16T20:44:41Z won 2017-06-25T20:50:55Z rxtngk9j5j93tsrq 2017-06-21T20:44:42Z s3.amazonaws.com/foo.jpg 88cfb8dd text evidence 2017-06-21T20:44:42Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 2014-09-01 """ % (id, id) def __new_dispute_accepted_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 accepted 2017-06-16T20:44:41Z 9qde5qgp open 2017-06-15T20:44:41Z accepted 2017-06-16T20:44:41Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 """ % (id, id) def __new_dispute_auto_accepted_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 auto_accepted 2017-06-16T20:44:41Z 9qde5qgp open 2017-06-15T20:44:41Z auto_accepted 2017-06-16T20:44:41Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 """ % (id, id) def __new_dispute_disputed_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 disputed 2017-06-16T20:44:41Z 9qde5qgp open 2017-06-15T20:44:41Z disputed 2017-06-16T20:44:41Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 """ % (id, id) def __new_dispute_expired_sample_xml(self, id): return """ %s 100.00 100.00 95.00 CASE-12345 2017-06-16T20:44:41Z USD chargeback ytnlulaloidoqwvzxjrdqputg fraud 2016-02-15 REF-9876 2016-02-22 expired 2017-06-16T20:44:41Z 9qde5qgp open 2017-06-15T20:44:41Z expired 2017-06-25T20:44:41Z %s 100.00 2017-06-21T20:44:41Z Visa 2014-03-28 """ % (id, id) def __refund_failed_sample_xml(self, id): return """ %s 100 1234560000001234 123 processor_declined 1 """ % id def __subscription_sample_xml(self, id): return """ %s """ % id def __subscription_billing_skipped_sample_xml(self, id): return """ %s """ % id def __subscription_charged_successfully_sample_xml(self, id): return """ %s %s submitted_for_settlement 49.99 """ % (id, id) def __subscription_charged_unsuccessfully_sample_xml(self, id): return """ %s %s failed 49.99 """ % (id, id) def __merchant_account_approved_sample_xml(self, id): return """ %s active master_ma_for_%s active """ % (id, id) def __merchant_account_declined_sample_xml(self, id): return """ Credit score is too low 82621 Credit score is too low base %s suspended master_ma_for_%s suspended """ % (id, id) def __partner_merchant_connected_sample_xml(self): return """ abc123 public_key private_key public_id cse_key """ def __partner_merchant_disconnected_sample_xml(self): return """ abc123 """ def __connected_merchant_status_transitioned_xml(self, id): return """ new_status %s oauth_application_client_id """ % id def __connected_merchant_paypal_status_changed_xml(self, id): return """ link %s oauth_application_client_id """ % id def __partner_merchant_declined_sample_xml(self): return """ abc123 """ def __oauth_access_revocation_sample_xml(self, id): return """ %s oauth_application_client_id """ % id def __account_updater_daily_report_sample_xml(self): return """ 2016-01-14 link-to-csv-report """ def __granted_payment_instrument_update(self): return """ vczo7jqrpwrsi2px cf0i8wgarszuy6hc ee257d98-de40-47e8-96b3-a6954ea7a9a4 false false abc123z expiration-month expiration-year """ def __granted_payment_method_revoked(self, id): return self.__venmo_account_xml(id) def __payment_method_revoked_by_customer(self, id): return """ a-billing-agreement-id 2019-01-01T12:00:00Z a-customer-id true name@email.com cGF5bWVudG1ldGhvZF9jaDZieXNz https://assets.braintreegateway.com/payment_method_logo/paypal.png?environment=test %s 2019-01-02T12:00:00Z a-payer-id 2019-01-02T12:00:00Z """ % id def __local_payment_completed(self, id): if id == "blik_one_click_id": return self.__blik_one_click_local_payment_completed() else: return self.__default_local_payment_completed() def __default_local_payment_completed(self): return """ a-bic 1234 a-payer-id a-payer-id a-payer-name a-payment-id ee257d98-de40-47e8-96b3-a6954ea7a9a4 1 authorizing 10.00 order1234 """ def __blik_one_click_local_payment_completed(self): return """ a-bic alias-key-1 1234 a-payer-id a-payer-id a-payer-name a-payment-id ee257d98-de40-47e8-96b3-a6954ea7a9a4 1 authorizing 10.00 order1234 """ def __local_payment_expired(self): return """ a-payment-id a-context-payment-id """ def __local_payment_funded(self): return """ a-payment-id a-context-payment-id 1 settled 10.00 order1234 """ def __local_payment_reversed(self): return """ a-payment-id """ def __payment_method_customer_data_updated_sample_xml(self, id): return """ TOKEN-12345 %s 2022-01-01T21:28:37Z username venmo_username John Doe 1231231234 john.doe@paypal.com Street Address Extended Address Locality Region Postal Code Street Address Extended Address Locality Region Postal Code """ % self.__venmo_account_xml(id) def __venmo_account_xml(self, id): return """ 2018-10-11T21:28:37Z 2018-10-11T21:28:37Z true https://assets.braintreegateway.com/payment_method_logo/venmo.png?environment=test %s Venmo Account: venmojoe venmojoe 456 venmo_customer_id cGF5bWVudG1ldGhvZF92ZW5tb2FjY291bnQ """ % id braintree_python-4.31.0/ci.sh000077500000000000000000000003201471021343500161000ustar00rootroot00000000000000#!/bin/bash if [[ "$1" == "http" ]]; then python_tests="test:http" fi if [[ "$1" == "python3" ]]; then /usr/local/lib/python3.3/bin/python3 -m unittest discover else env rake $python_tests --trace fi braintree_python-4.31.0/dev_requirements.txt000066400000000000000000000000441471021343500212730ustar00rootroot00000000000000twine>=1.9,<2.0 -r requirements.txt braintree_python-4.31.0/docs/000077500000000000000000000000001471021343500161035ustar00rootroot00000000000000braintree_python-4.31.0/docs/requirements.txt000066400000000000000000000000161471021343500213640ustar00rootroot00000000000000docutils<0.18 braintree_python-4.31.0/polaris.yml000066400000000000000000000025311471021343500173500ustar00rootroot00000000000000#This is the default configuration file generated by Polaris. Documentation on configuration options can be found here https://sig-docs.synopsys.com/polaris/topics/c_conf-overview.html version: "1" project: name: ${scm.git.repo} branch: ${scm.git.branch} revision: name: ${scm.git.commit} date: ${scm.git.commit.date} groups: # Required: This allows the Jenkins Polaris service account to create new projects braintree-jenkins: "Contributor" PP_SSO_POLARIS_USER: "Observer" PP_SSO_POLARIS_SECURITY_CHAMPION: "Contributor" PP_SSO_POLARIS_ADMIN: "Administrator" capture: fileSystem: ears: extensions: [ear] files: - directory: ${project.projectDir} java: files: - directory: ${project.projectDir} javascript: files: - directory: ${project.projectDir} - excludeRegex: node_modules|bower_components|vendor php: files: - directory: ${project.projectDir} python: files: - directory: ${project.projectDir} ruby: files: - directory: ${project.projectDir} typescript: files: - directory: ${project.projectDir} wars: extensions: [war] files: - directory: ${project.projectDir} analyze: mode: central install: coverity: version: default serverUrl: ${POLARIS_SERVER_URL} braintree_python-4.31.0/requirements.txt000066400000000000000000000000261471021343500204350ustar00rootroot00000000000000requests>=0.11.0,<3.0 braintree_python-4.31.0/setup.cfg000066400000000000000000000000341471021343500167710ustar00rootroot00000000000000[bdist_wheel] universal = 1 braintree_python-4.31.0/setup.py000066400000000000000000000026441471021343500166730ustar00rootroot00000000000000try: from setuptools import setup except ImportError: from distutils.core import setup long_description = """ The Braintree Python SDK provides integration access to the Braintree Gateway. 1. https://github.com/braintree/braintree_python - README and Samples 2. https://developer.paypal.com/braintree/docs/reference/overview - API Reference """ setup( name="braintree", version="4.31.0", description="Braintree Python Library", long_description=long_description, author="Braintree", author_email="support@braintreepayments.com", url="https://developer.paypal.com/braintree/docs/reference/overview", packages=["braintree", "braintree.dispute_details", "braintree.exceptions", "braintree.exceptions.http", "braintree.merchant_account", "braintree.util", "braintree.test"], package_data={"braintree": ["ssl/*"]}, install_requires=["requests>=0.11.1,<3.0"], zip_safe=False, license="MIT", classifiers=[ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12" ] ) braintree_python-4.31.0/tests/000077500000000000000000000000001471021343500163155ustar00rootroot00000000000000braintree_python-4.31.0/tests/__init__.py000066400000000000000000000000001471021343500204140ustar00rootroot00000000000000braintree_python-4.31.0/tests/fixtures/000077500000000000000000000000001471021343500201665ustar00rootroot00000000000000braintree_python-4.31.0/tests/fixtures/bt_logo.png000066400000000000000000000046131471021343500223250ustar00rootroot00000000000000‰PNG  IHDRu ,G7øsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î< IDAThí›{°WUÇ?KyÉ› (ò  s CËÔñA0db¦å£$¨f´TC™b„|›SC# DÖÊR0)ˆ‚¢‚¼®€p/÷Ûký¼‡Ã9¿‹è½€ý¾3gÎïì½ÖÚk¿÷^kýŒc ’ç›Ìlò‘Öçh„Ij—‘Wl4³òÚU©8$ÝüXefÝj@~ 5Pnf>mùµIÛ• I«%Ý")«ãk’î Ý^­!ùýBþë5!¿6Pxhtö+#¯1Ðè LÚ7Õ¾Ša°%žò éòkSé %ý:òÊ%µ8R:Ö>+35f¶[Ò|†ÖN¶H M? ”áû]_À€%À]föFHR#à`p:¾:¬f3ÍLi=¢¬ RÉïšÙø,½%ΉÏ]ÀÀ`0ÐX< Ì(”'i"Ð89øZIšžý¶™Ý™(§05©0ø>p9¾7o5³ÇR:ÖF—ð3Ì«A;7§^LJÜ+ñÔ€ÕÀ¤Û.o¦FÞ¥‘·CÒ ‰ô_¤öß©’veìËïH:9x:IÚPd §22hs÷TI%èÊ$­Ê)ï7 žbzðrºcÒ:Iš—Ã;.Áw¢¤eEÊù­¼“e5•´ ÏÓ’êguêVIã™ –Ç32UHoIתªÁ*%m”tµ¤¶’ºFÞ>I£‚§Ž¤Y’^‘4DRIŸ—46ø%éìŒNê%é;ñÜtÅ:õ«’nKT¸"êÓKR;IÓ"}¿¤Ó‚gxÔçW‘·9¾“Ï%©rŽ‹ô‚N…:üNRŸ¨ÛÏ"mEЛ¤ç"m½¤‹äÛ\Óµ;ònK•5+Ò7IºBRcIBïm‘7%«Só0«PùŒükÐìÔ6•×FRãTZ=Iu3ä, 9cò:+è¾tEO¿’º$ô›Ê;^Ò–ÈœÊûØ{ª¤þ‰²&¥òLR— ÚrI3dŠü²BÛIê–VÏÐÈÛ'©uzOÝÜ¿ONâëþy’™Ù¿rêö¸™½™Lȹçµ®–Ôß¿Êð=îs‘ß(GþáBÀƒ)½öKZ´êgr*€ ©²ü;‘Ô?ÞeÀ]ÒAGˆÂ€oŒŸ žIðì~œÁc@eðHwêf63•6IÒ}Àð«M²±2'ý#HÌÄL9>ˆZ}ªãýøÀ̶f¤WÖ@Yo›Ù¶jhšÅ»pY5´mR< …§èé7Åx§v/B³ïäLÅ;ôAàV3Û ©%0‹üS›(tv½Ãà=”6XïÕÀAç‡v§xÞÃû ¢Ïžj­DÑà?ŒÏþ»ÉÍo…=÷þB‡šg®ìOïÆûTI“’Α4âÊ ïü/#Íl[ò¶ã³±©™í žùÀN|;¼)Í|C€SÌìC“4·&uÇGÆâ„-ðÆ®à‹Íìé¨à|üîÚ ßW%d»™´LȯL¿ã³v?p0_†ÞÖšÙÁ3 ¿›Ð_®?^H¤¯0³±Á37úŸe,f›ÙTIჴ/>˜–ïG§{I‹ƒ÷-`°è|·“ÃÌæÊo#¢zg´ßd3›ŸÑ〻ãóoÀ`+ÐïÐøêif»‚ç»ÀCÁ³xŸ¹§ߌvÜô¨Îö[ÀRI\þ%í-Bÿ^º"Ás®ªNI¬“´$ñ]žà¹ûô“¤çkçšÙÛ šø*—‡×Ìì¼LIMqKY7 ÞÞ/KÍlOCàë@Oü|²ø'°ØÌŠíµ%”PB %”PB %”P±èÝ+i¥¤¡Õsfʪ/igBÞI”Ô¼OW¹nBMMâ¨&«ôŠ÷#¸Å¦F(|t¢*Zâ^Üqµ‡¸ç䈄ĪAÿ¨„¤ssŒ]póà Ài¸]´r%p&:² ÑùnyÁÌI2à:Ü•µ1dÎ1³1’šß ymQx§ÿ7_.¦Ê¸ñZJßá¸×å 3;fã jòH—t°Ñ½Q,};$ýRÒ‹±lNVUôÀšXF+%½%©µ< â¹qsÐÝ¡ªй’¦È×Jº0~ï–´\UQ7Jš¿[&ôê*omºäìþ¿G4vI×§Ò{§l¢ïKz@ÒyñýHÐuŽïgâûy¹m÷+ÑQË$Õ•ôû„¬rùþò•±òë ¡ß­’ÆIºFò2VÒOå‘*×Kú¹¤Á ÏQ ´Çäž*©'î…ù20 •Ý5Þ÷›£¥™]‹Ç-¼ïÂwa‰œ/£•ÀUñï„‚¼öfV×ÌÎ0³9x4ß`­|¹.¸×àûðK/P×Ì’ŽùáÀ2àvà Ü 4 ÷–ÍĽDÍl"n¾%t|·û~ ²œ)·i÷5³mÇÜž 8ßtT7ñ÷B'¤Ãn–àûìyYïH/4þL` ¾?^gfkbfu¶šÙú”¼Åxc¯ÄÖñ•:x„BºS·É=] óqçÅÒÐwî+= x wÁ¼/7ú7ÀÝ›eÀÅA¿8?À­‹6Á2[î(†¤Ö@+3[ß}€uf¶%¾/Æ}¥S“•È\Š{C–ã3}š™½%™Z€Ÿ–/43Éû·ëÍlzJVCàf܃ôü„½˜‹О2³$è ø~ˆz6ÊÿÓàx<Òð­føLTü~?´ šu¸ï¶ ÷Ô´›ÙìÃjÔÏ"$µ˜6ÉO¨G’îTøm«¡k$D/! IÍ%/÷tê!Ò5—Ô,™ö?ÒQÿâc¶°pIEND®B`‚braintree_python-4.31.0/tests/fixtures/gif_extension_bt_logo.gif000066400000000000000000000046131471021343500252270ustar00rootroot00000000000000‰PNG  IHDRu ,G7øsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î< IDAThí›{°WUÇ?KyÉ› (ò  s CËÔñA0db¦å£$¨f´TC™b„|›SC# DÖÊR0)ˆ‚¢‚¼®€p/÷Ûký¼‡Ã9¿‹è½€ý¾3gÎïì½ÖÚk¿÷^kýŒc ’ç›Ìlò‘Öçh„Ij—‘Wl4³òÚU©8$ÝüXefÝj@~ 5Pnf>mùµIÛ• I«%Ý")«ãk’î Ý^­!ùýBþë5!¿6Pxhtö+#¯1Ðè LÚ7Õ¾Ša°%žò éòkSé %ý:òÊ%µ8R:Ö>+35f¶[Ò|†ÖN¶H M? ”áû]_À€%À]föFHR#à`p:¾:¬f3ÍLi=¢¬ RÉïšÙø,½%ΉÏ]ÀÀ`0ÐX< Ì(”'i"Ð89øZIšžý¶™Ý™(§05©0ø>p9¾7o5³ÇR:ÖF—ð3Ì«A;7§^LJÜ+ñÔ€ÕÀ¤Û.o¦FÞ¥‘·CÒ ‰ô_¤öß©’veìËïH:9x:IÚPd §22hs÷TI%èÊ$­Ê)ï7 žbzðrºcÒ:Iš—Ã;.Áw¢¤eEÊù­¼“e5•´ ÏÓ’êguêVIã™ –Ç32UHoIתªÁ*%m”tµ¤¶’ºFÞ>I£‚§Ž¤Y’^‘4DRIŸ—46ø%éìŒNê%é;ñÜtÅ:õ«’nKT¸"êÓKR;IÓ"}¿¤Ó‚gxÔçW‘·9¾“Ï%©rŽ‹ô‚N…:üNRŸ¨ÛÏ"mEЛ¤ç"m½¤‹äÛ\Óµ;ònK•5+Ò7IºBRcIBïm‘7%«Só0«PùŒükÐìÔ6•×FRãTZ=Iu3ä, 9cò:+è¾tEO¿’º$ô›Ê;^Ò–ÈœÊûØ{ª¤þ‰²&¥òLR— ÚrI3dŠü²BÛIê–VÏÐÈÛ'©uzOÝÜ¿ONâëþy’™Ù¿rêö¸™½™Lȹçµ®–Ôß¿Êð=îs‘ß(GþáBÀƒ)½öKZ´êgr*€ ©²ü;‘Ô?ÞeÀ]ÒAGˆÂ€oŒŸ žIðì~œÁc@eðHwêf63•6IÒ}Àð«M²±2'ý#HÌÄL9>ˆZ}ªãýøÀ̶f¤WÖ@Yo›Ù¶jhšÅ»pY5´mR< …§èé7Åx§v/B³ïäLÅ;ôAàV3Û ©%0‹üS›(tv½Ãà=”6XïÕÀAç‡v§xÞÃû ¢Ïžj­DÑà?ŒÏþ»ÉÍo…=÷þB‡šg®ìOïÆûTI“’Α4âÊ ïü/#Íl[ò¶ã³±©™í žùÀN|;¼)Í|C€SÌìC“4·&uÇGÆâ„-ðÆ®à‹Íìé¨à|üîÚ ßW%d»™´LȯL¿ã³v?p0_†ÞÖšÙÁ3 ¿›Ð_®?^H¤¯0³±Á37úŸe,f›ÙTIჴ/>˜–ïG§{I‹ƒ÷-`°è|·“ÃÌæÊo#¢zg´ßd3›ŸÑ〻ãóoÀ`+ÐïÐøêif»‚ç»ÀCÁ³xŸ¹§ߌvÜô¨Îö[ÀRI\þ%í-Bÿ^º"Ás®ªNI¬“´$ñ]žà¹ûô“¤çkçšÙÛ šø*—‡×Ìì¼LIMqKY7 ÞÞ/KÍlOCàë@Oü|²ø'°ØÌŠíµ%”PB %”PB %”P±èÝ+i¥¤¡Õsfʪ/igBÞI”Ô¼OW¹nBMMâ¨&«ôŠ÷#¸Å¦F(|t¢*Zâ^Üqµ‡¸ç䈄ĪAÿ¨„¤ssŒ]póà Ài¸]´r%p&:² ÑùnyÁÌI2à:Ü•µ1dÎ1³1’šß ymQx§ÿ7_.¦Ê¸ñZJßá¸×å 3;fã jòH—t°Ñ½Q,};$ýRÒ‹±lNVUôÀšXF+%½%©µ< â¹qsÐÝ¡ªй’¦È×Jº0~ï–´\UQ7Jš¿[&ôê*omºäìþ¿G4vI×§Ò{§l¢ïKz@ÒyñýHÐuŽïgâûy¹m÷+ÑQË$Õ•ôû„¬rùþò•±òë ¡ß­’ÆIºFò2VÒOå‘*×Kú¹¤Á ÏQ ´Çäž*©'î…ù20 •Ý5Þ÷›£¥™]‹Ç-¼ïÂwa‰œ/£•ÀUñï„‚¼öfV×ÌÎ0³9x4ß`­|¹.¸×àûðK/P×Ì’ŽùáÀ2àvà Ü 4 ÷–ÍĽDÍl"n¾%t|·û~ ²œ)·i÷5³mÇÜž 8ßtT7ñ÷B'¤Ãn–àûìyYïH/4þL` ¾?^gfkbfu¶šÙú”¼Åxc¯ÄÖñ•:x„BºS·É=] óqçÅÒÐwî+= x wÁ¼/7ú7ÀÝ›eÀÅA¿8?À­‹6Á2[î(†¤Ö@+3[ß}€uf¶%¾/Æ}¥S“•È\Š{C–ã3}š™½%™Z€Ÿ–/43Éû·ëÍlzJVCàf܃ôü„½˜‹О2³$è ø~ˆz6ÊÿÓàx<Òð­føLTü~?´ šu¸ï¶ ÷Ô´›ÙìÃjÔÏ"$µ˜6ÉO¨G’îTøm«¡k$D/! IÍ%/÷tê!Ò5—Ô,™ö?ÒQÿâc¶°pIEND®B`‚braintree_python-4.31.0/tests/fixtures/malformed_pdf.pdf000066400000000000000000000002261471021343500234600ustar00rootroot00000000000000XXXXXXXXXXX¾?^gfkbfu¶šÙú”¼Åxc¯ÄÂÖÂñ•:x„BºS·É=] ÂóqçÅÒÃwî+= x wü/7ú7ÀÛeÀÅA¿8?À­‹6Ã2[î(†¤Ö@+3[ß} braintree_python-4.31.0/tests/fixtures/too_long.pdf000066400000000000000000002322401471021343500225040ustar00rootroot00000000000000%PDF-1.4 %Çì¢ 5 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 6 0 obj 30 endobj 10 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 11 0 obj 30 endobj 14 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 15 0 obj 30 endobj 18 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 19 0 obj 30 endobj 22 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 23 0 obj 30 endobj 26 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 27 0 obj 30 endobj 30 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 31 0 obj 30 endobj 34 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 35 0 obj 30 endobj 38 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 39 0 obj 30 endobj 42 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 43 0 obj 30 endobj 46 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 47 0 obj 30 endobj 50 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 51 0 obj 30 endobj 54 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 55 0 obj 30 endobj 58 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 59 0 obj 30 endobj 62 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 63 0 obj 30 endobj 66 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 67 0 obj 30 endobj 70 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 71 0 obj 30 endobj 74 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 75 0 obj 30 endobj 78 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 79 0 obj 30 endobj 82 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 83 0 obj 30 endobj 86 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 87 0 obj 30 endobj 90 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 91 0 obj 30 endobj 94 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 95 0 obj 30 endobj 98 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 99 0 obj 30 endobj 102 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 103 0 obj 30 endobj 106 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 107 0 obj 30 endobj 110 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 111 0 obj 30 endobj 114 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 115 0 obj 30 endobj 118 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 119 0 obj 30 endobj 122 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 123 0 obj 30 endobj 126 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 127 0 obj 30 endobj 130 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 131 0 obj 30 endobj 134 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 135 0 obj 30 endobj 138 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 139 0 obj 30 endobj 142 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 143 0 obj 30 endobj 146 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 147 0 obj 30 endobj 150 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 151 0 obj 30 endobj 154 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 155 0 obj 30 endobj 158 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 159 0 obj 30 endobj 162 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 163 0 obj 30 endobj 166 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 167 0 obj 30 endobj 170 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 171 0 obj 30 endobj 174 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 175 0 obj 30 endobj 178 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 179 0 obj 30 endobj 182 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 183 0 obj 30 endobj 186 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 187 0 obj 30 endobj 190 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 191 0 obj 30 endobj 194 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 195 0 obj 30 endobj 198 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 199 0 obj 30 endobj 202 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 203 0 obj 30 endobj 206 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 207 0 obj 30 endobj 210 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 211 0 obj 30 endobj 214 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 215 0 obj 30 endobj 218 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 219 0 obj 30 endobj 222 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 223 0 obj 30 endobj 226 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 227 0 obj 30 endobj 230 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 231 0 obj 30 endobj 234 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 235 0 obj 30 endobj 238 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 239 0 obj 30 endobj 242 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 243 0 obj 30 endobj 246 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 247 0 obj 30 endobj 250 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 251 0 obj 30 endobj 254 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 255 0 obj 30 endobj 258 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 259 0 obj 30 endobj 262 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 263 0 obj 30 endobj 266 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 267 0 obj 30 endobj 270 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 271 0 obj 30 endobj 274 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 275 0 obj 30 endobj 278 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 279 0 obj 30 endobj 282 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 283 0 obj 30 endobj 286 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 287 0 obj 30 endobj 290 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 291 0 obj 30 endobj 294 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 295 0 obj 30 endobj 298 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 299 0 obj 30 endobj 302 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 303 0 obj 30 endobj 306 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 307 0 obj 30 endobj 310 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 311 0 obj 30 endobj 314 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 315 0 obj 30 endobj 318 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 319 0 obj 30 endobj 322 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 323 0 obj 30 endobj 326 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 327 0 obj 30 endobj 330 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 331 0 obj 30 endobj 334 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 335 0 obj 30 endobj 338 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 339 0 obj 30 endobj 342 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 343 0 obj 30 endobj 346 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 347 0 obj 30 endobj 350 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 351 0 obj 30 endobj 354 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 355 0 obj 30 endobj 358 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 359 0 obj 30 endobj 362 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 363 0 obj 30 endobj 366 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 367 0 obj 30 endobj 370 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 371 0 obj 30 endobj 374 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 375 0 obj 30 endobj 378 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 379 0 obj 30 endobj 382 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 383 0 obj 30 endobj 386 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 387 0 obj 30 endobj 390 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 391 0 obj 30 endobj 394 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 395 0 obj 30 endobj 398 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 399 0 obj 30 endobj 402 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 403 0 obj 30 endobj 406 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 407 0 obj 30 endobj 410 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 411 0 obj 30 endobj 414 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 415 0 obj 30 endobj 418 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 419 0 obj 30 endobj 422 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 423 0 obj 30 endobj 426 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 427 0 obj 30 endobj 430 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 431 0 obj 30 endobj 434 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 435 0 obj 30 endobj 438 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 439 0 obj 30 endobj 442 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 443 0 obj 30 endobj 446 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 447 0 obj 30 endobj 450 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 451 0 obj 30 endobj 454 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 455 0 obj 30 endobj 458 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 459 0 obj 30 endobj 462 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 463 0 obj 30 endobj 466 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 467 0 obj 30 endobj 470 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 471 0 obj 30 endobj 474 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 475 0 obj 30 endobj 478 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 479 0 obj 30 endobj 482 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 483 0 obj 30 endobj 486 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 487 0 obj 30 endobj 490 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 491 0 obj 30 endobj 494 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 495 0 obj 30 endobj 498 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 499 0 obj 30 endobj 502 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 503 0 obj 30 endobj 506 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 507 0 obj 30 endobj 510 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 511 0 obj 30 endobj 514 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 515 0 obj 30 endobj 518 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 519 0 obj 30 endobj 522 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 523 0 obj 30 endobj 526 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 527 0 obj 30 endobj 530 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 531 0 obj 30 endobj 534 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 535 0 obj 30 endobj 538 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 539 0 obj 30 endobj 542 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 543 0 obj 30 endobj 546 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 547 0 obj 30 endobj 550 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 551 0 obj 30 endobj 554 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 555 0 obj 30 endobj 558 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 559 0 obj 30 endobj 562 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 563 0 obj 30 endobj 566 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 567 0 obj 30 endobj 570 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 571 0 obj 30 endobj 574 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 575 0 obj 30 endobj 578 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 579 0 obj 30 endobj 582 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 583 0 obj 30 endobj 586 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 587 0 obj 30 endobj 590 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 591 0 obj 30 endobj 594 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 595 0 obj 30 endobj 598 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 599 0 obj 30 endobj 602 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 603 0 obj 30 endobj 606 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 607 0 obj 30 endobj 610 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 611 0 obj 30 endobj 614 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 615 0 obj 30 endobj 618 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 619 0 obj 30 endobj 622 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 623 0 obj 30 endobj 626 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 627 0 obj 30 endobj 630 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 631 0 obj 30 endobj 634 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 635 0 obj 30 endobj 638 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 639 0 obj 30 endobj 642 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 643 0 obj 30 endobj 646 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 647 0 obj 30 endobj 650 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 651 0 obj 30 endobj 654 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 655 0 obj 30 endobj 658 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 659 0 obj 30 endobj 662 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 663 0 obj 30 endobj 666 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 667 0 obj 30 endobj 670 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 671 0 obj 30 endobj 674 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 675 0 obj 30 endobj 678 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 679 0 obj 30 endobj 682 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 683 0 obj 30 endobj 686 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 687 0 obj 30 endobj 690 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 691 0 obj 30 endobj 694 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 695 0 obj 30 endobj 698 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 699 0 obj 30 endobj 702 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 703 0 obj 30 endobj 706 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 707 0 obj 30 endobj 710 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 711 0 obj 30 endobj 714 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 715 0 obj 30 endobj 718 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 719 0 obj 30 endobj 722 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 723 0 obj 30 endobj 726 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 727 0 obj 30 endobj 730 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 731 0 obj 30 endobj 734 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 735 0 obj 30 endobj 738 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 739 0 obj 30 endobj 742 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 743 0 obj 30 endobj 746 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 747 0 obj 30 endobj 750 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 751 0 obj 30 endobj 754 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 755 0 obj 30 endobj 758 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 759 0 obj 30 endobj 762 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 763 0 obj 30 endobj 766 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 767 0 obj 30 endobj 770 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 771 0 obj 30 endobj 774 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 775 0 obj 30 endobj 778 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 779 0 obj 30 endobj 782 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 783 0 obj 30 endobj 786 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 787 0 obj 30 endobj 790 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 791 0 obj 30 endobj 794 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 795 0 obj 30 endobj 798 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 799 0 obj 30 endobj 802 0 obj <> stream xœ+T0Ð3T0A(œË¥d®^ÌÈ[ô!endstream endobj 803 0 obj 30 endobj 4 0 obj <> /Contents 5 0 R >> endobj 9 0 obj <> /Contents 10 0 R >> endobj 13 0 obj <> /Contents 14 0 R >> endobj 17 0 obj <> /Contents 18 0 R >> endobj 21 0 obj <> /Contents 22 0 R >> endobj 25 0 obj <> /Contents 26 0 R >> endobj 29 0 obj <> /Contents 30 0 R >> endobj 33 0 obj <> /Contents 34 0 R >> endobj 37 0 obj <> /Contents 38 0 R >> endobj 41 0 obj <> /Contents 42 0 R >> endobj 45 0 obj <> /Contents 46 0 R >> endobj 49 0 obj <> /Contents 50 0 R >> endobj 53 0 obj <> /Contents 54 0 R >> endobj 57 0 obj <> /Contents 58 0 R >> endobj 61 0 obj <> /Contents 62 0 R >> endobj 65 0 obj <> /Contents 66 0 R >> endobj 69 0 obj <> /Contents 70 0 R >> endobj 73 0 obj <> /Contents 74 0 R >> endobj 77 0 obj <> /Contents 78 0 R >> endobj 81 0 obj <> /Contents 82 0 R >> endobj 85 0 obj <> /Contents 86 0 R >> endobj 89 0 obj <> /Contents 90 0 R >> endobj 93 0 obj <> /Contents 94 0 R >> endobj 97 0 obj <> /Contents 98 0 R >> endobj 101 0 obj <> /Contents 102 0 R >> endobj 105 0 obj <> /Contents 106 0 R >> endobj 109 0 obj <> /Contents 110 0 R >> endobj 113 0 obj <> /Contents 114 0 R >> endobj 117 0 obj <> /Contents 118 0 R >> endobj 121 0 obj <> /Contents 122 0 R >> endobj 125 0 obj <> /Contents 126 0 R >> endobj 129 0 obj <> /Contents 130 0 R >> endobj 133 0 obj <> /Contents 134 0 R >> endobj 137 0 obj <> /Contents 138 0 R >> endobj 141 0 obj <> /Contents 142 0 R >> endobj 145 0 obj <> /Contents 146 0 R >> endobj 149 0 obj <> /Contents 150 0 R >> endobj 153 0 obj <> /Contents 154 0 R >> endobj 157 0 obj <> /Contents 158 0 R >> endobj 161 0 obj <> /Contents 162 0 R >> endobj 165 0 obj <> /Contents 166 0 R >> endobj 169 0 obj <> /Contents 170 0 R >> endobj 173 0 obj <> /Contents 174 0 R >> endobj 177 0 obj <> /Contents 178 0 R >> endobj 181 0 obj <> /Contents 182 0 R >> endobj 185 0 obj <> /Contents 186 0 R >> endobj 189 0 obj <> /Contents 190 0 R >> endobj 193 0 obj <> /Contents 194 0 R >> endobj 197 0 obj <> /Contents 198 0 R >> endobj 201 0 obj <> /Contents 202 0 R >> endobj 205 0 obj <> /Contents 206 0 R >> endobj 209 0 obj <> /Contents 210 0 R >> endobj 213 0 obj <> /Contents 214 0 R >> endobj 217 0 obj <> /Contents 218 0 R >> endobj 221 0 obj <> /Contents 222 0 R >> endobj 225 0 obj <> /Contents 226 0 R >> endobj 229 0 obj <> /Contents 230 0 R >> endobj 233 0 obj <> /Contents 234 0 R >> endobj 237 0 obj <> /Contents 238 0 R >> endobj 241 0 obj <> /Contents 242 0 R >> endobj 245 0 obj <> /Contents 246 0 R >> endobj 249 0 obj <> /Contents 250 0 R >> endobj 253 0 obj <> /Contents 254 0 R >> endobj 257 0 obj <> /Contents 258 0 R >> endobj 261 0 obj <> /Contents 262 0 R >> endobj 265 0 obj <> /Contents 266 0 R >> endobj 269 0 obj <> /Contents 270 0 R >> endobj 273 0 obj <> /Contents 274 0 R >> endobj 277 0 obj <> /Contents 278 0 R >> endobj 281 0 obj <> /Contents 282 0 R >> endobj 285 0 obj <> /Contents 286 0 R >> endobj 289 0 obj <> /Contents 290 0 R >> endobj 293 0 obj <> /Contents 294 0 R >> endobj 297 0 obj <> /Contents 298 0 R >> endobj 301 0 obj <> /Contents 302 0 R >> endobj 305 0 obj <> /Contents 306 0 R >> endobj 309 0 obj <> /Contents 310 0 R >> endobj 313 0 obj <> /Contents 314 0 R >> endobj 317 0 obj <> /Contents 318 0 R >> endobj 321 0 obj <> /Contents 322 0 R >> endobj 325 0 obj <> /Contents 326 0 R >> endobj 329 0 obj <> /Contents 330 0 R >> endobj 333 0 obj <> /Contents 334 0 R >> endobj 337 0 obj <> /Contents 338 0 R >> endobj 341 0 obj <> /Contents 342 0 R >> endobj 345 0 obj <> /Contents 346 0 R >> endobj 349 0 obj <> /Contents 350 0 R >> endobj 353 0 obj <> /Contents 354 0 R >> endobj 357 0 obj <> /Contents 358 0 R >> endobj 361 0 obj <> /Contents 362 0 R >> endobj 365 0 obj <> /Contents 366 0 R >> endobj 369 0 obj <> /Contents 370 0 R >> endobj 373 0 obj <> /Contents 374 0 R >> endobj 377 0 obj <> /Contents 378 0 R >> endobj 381 0 obj <> /Contents 382 0 R >> endobj 385 0 obj <> /Contents 386 0 R >> endobj 389 0 obj <> /Contents 390 0 R >> endobj 393 0 obj <> /Contents 394 0 R >> endobj 397 0 obj <> /Contents 398 0 R >> endobj 401 0 obj <> /Contents 402 0 R >> endobj 405 0 obj <> /Contents 406 0 R >> endobj 409 0 obj <> /Contents 410 0 R >> endobj 413 0 obj <> /Contents 414 0 R >> endobj 417 0 obj <> /Contents 418 0 R >> endobj 421 0 obj <> /Contents 422 0 R >> endobj 425 0 obj <> /Contents 426 0 R >> endobj 429 0 obj <> /Contents 430 0 R >> endobj 433 0 obj <> /Contents 434 0 R >> endobj 437 0 obj <> /Contents 438 0 R >> endobj 441 0 obj <> /Contents 442 0 R >> endobj 445 0 obj <> /Contents 446 0 R >> endobj 449 0 obj <> /Contents 450 0 R >> endobj 453 0 obj <> /Contents 454 0 R >> endobj 457 0 obj <> /Contents 458 0 R >> endobj 461 0 obj <> /Contents 462 0 R >> endobj 465 0 obj <> /Contents 466 0 R >> endobj 469 0 obj <> /Contents 470 0 R >> endobj 473 0 obj <> /Contents 474 0 R >> endobj 477 0 obj <> /Contents 478 0 R >> endobj 481 0 obj <> /Contents 482 0 R >> endobj 485 0 obj <> /Contents 486 0 R >> endobj 489 0 obj <> /Contents 490 0 R >> endobj 493 0 obj <> /Contents 494 0 R >> endobj 497 0 obj <> /Contents 498 0 R >> endobj 501 0 obj <> /Contents 502 0 R >> endobj 505 0 obj <> /Contents 506 0 R >> endobj 509 0 obj <> /Contents 510 0 R >> endobj 513 0 obj <> /Contents 514 0 R >> endobj 517 0 obj <> /Contents 518 0 R >> endobj 521 0 obj <> /Contents 522 0 R >> endobj 525 0 obj <> /Contents 526 0 R >> endobj 529 0 obj <> /Contents 530 0 R >> endobj 533 0 obj <> /Contents 534 0 R >> endobj 537 0 obj <> /Contents 538 0 R >> endobj 541 0 obj <> /Contents 542 0 R >> endobj 545 0 obj <> /Contents 546 0 R >> endobj 549 0 obj <> /Contents 550 0 R >> endobj 553 0 obj <> /Contents 554 0 R >> endobj 557 0 obj <> /Contents 558 0 R >> endobj 561 0 obj <> /Contents 562 0 R >> endobj 565 0 obj <> /Contents 566 0 R >> endobj 569 0 obj <> /Contents 570 0 R >> endobj 573 0 obj <> /Contents 574 0 R >> endobj 577 0 obj <> /Contents 578 0 R >> endobj 581 0 obj <> /Contents 582 0 R >> endobj 585 0 obj <> /Contents 586 0 R >> endobj 589 0 obj <> /Contents 590 0 R >> endobj 593 0 obj <> /Contents 594 0 R >> endobj 597 0 obj <> /Contents 598 0 R >> endobj 601 0 obj <> /Contents 602 0 R >> endobj 605 0 obj <> /Contents 606 0 R >> endobj 609 0 obj <> /Contents 610 0 R >> endobj 613 0 obj <> /Contents 614 0 R >> endobj 617 0 obj <> /Contents 618 0 R >> endobj 621 0 obj <> /Contents 622 0 R >> endobj 625 0 obj <> /Contents 626 0 R >> endobj 629 0 obj <> /Contents 630 0 R >> endobj 633 0 obj <> /Contents 634 0 R >> endobj 637 0 obj <> /Contents 638 0 R >> endobj 641 0 obj <> /Contents 642 0 R >> endobj 645 0 obj <> /Contents 646 0 R >> endobj 649 0 obj <> /Contents 650 0 R >> endobj 653 0 obj <> /Contents 654 0 R >> endobj 657 0 obj <> /Contents 658 0 R >> endobj 661 0 obj <> /Contents 662 0 R >> endobj 665 0 obj <> /Contents 666 0 R >> endobj 669 0 obj <> /Contents 670 0 R >> endobj 673 0 obj <> /Contents 674 0 R >> endobj 677 0 obj <> /Contents 678 0 R >> endobj 681 0 obj <> /Contents 682 0 R >> endobj 685 0 obj <> /Contents 686 0 R >> endobj 689 0 obj <> /Contents 690 0 R >> endobj 693 0 obj <> /Contents 694 0 R >> endobj 697 0 obj <> /Contents 698 0 R >> endobj 701 0 obj <> /Contents 702 0 R >> endobj 705 0 obj <> /Contents 706 0 R >> endobj 709 0 obj <> /Contents 710 0 R >> endobj 713 0 obj <> /Contents 714 0 R >> endobj 717 0 obj <> /Contents 718 0 R >> endobj 721 0 obj <> /Contents 722 0 R >> endobj 725 0 obj <> /Contents 726 0 R >> endobj 729 0 obj <> /Contents 730 0 R >> endobj 733 0 obj <> /Contents 734 0 R >> endobj 737 0 obj <> /Contents 738 0 R >> endobj 741 0 obj <> /Contents 742 0 R >> endobj 745 0 obj <> /Contents 746 0 R >> endobj 749 0 obj <> /Contents 750 0 R >> endobj 753 0 obj <> /Contents 754 0 R >> endobj 757 0 obj <> /Contents 758 0 R >> endobj 761 0 obj <> /Contents 762 0 R >> endobj 765 0 obj <> /Contents 766 0 R >> endobj 769 0 obj <> /Contents 770 0 R >> endobj 773 0 obj <> /Contents 774 0 R >> endobj 777 0 obj <> /Contents 778 0 R >> endobj 781 0 obj <> /Contents 782 0 R >> endobj 785 0 obj <> /Contents 786 0 R >> endobj 789 0 obj <> /Contents 790 0 R >> endobj 793 0 obj <> /Contents 794 0 R >> endobj 797 0 obj <> /Contents 798 0 R >> endobj 801 0 obj <> /Contents 802 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 9 0 R 13 0 R 17 0 R 21 0 R 25 0 R 29 0 R 33 0 R 37 0 R 41 0 R 45 0 R 49 0 R 53 0 R 57 0 R 61 0 R 65 0 R 69 0 R 73 0 R 77 0 R 81 0 R 85 0 R 89 0 R 93 0 R 97 0 R 101 0 R 105 0 R 109 0 R 113 0 R 117 0 R 121 0 R 125 0 R 129 0 R 133 0 R 137 0 R 141 0 R 145 0 R 149 0 R 153 0 R 157 0 R 161 0 R 165 0 R 169 0 R 173 0 R 177 0 R 181 0 R 185 0 R 189 0 R 193 0 R 197 0 R 201 0 R 205 0 R 209 0 R 213 0 R 217 0 R 221 0 R 225 0 R 229 0 R 233 0 R 237 0 R 241 0 R 245 0 R 249 0 R 253 0 R 257 0 R 261 0 R 265 0 R 269 0 R 273 0 R 277 0 R 281 0 R 285 0 R 289 0 R 293 0 R 297 0 R 301 0 R 305 0 R 309 0 R 313 0 R 317 0 R 321 0 R 325 0 R 329 0 R 333 0 R 337 0 R 341 0 R 345 0 R 349 0 R 353 0 R 357 0 R 361 0 R 365 0 R 369 0 R 373 0 R 377 0 R 381 0 R 385 0 R 389 0 R 393 0 R 397 0 R 401 0 R 405 0 R 409 0 R 413 0 R 417 0 R 421 0 R 425 0 R 429 0 R 433 0 R 437 0 R 441 0 R 445 0 R 449 0 R 453 0 R 457 0 R 461 0 R 465 0 R 469 0 R 473 0 R 477 0 R 481 0 R 485 0 R 489 0 R 493 0 R 497 0 R 501 0 R 505 0 R 509 0 R 513 0 R 517 0 R 521 0 R 525 0 R 529 0 R 533 0 R 537 0 R 541 0 R 545 0 R 549 0 R 553 0 R 557 0 R 561 0 R 565 0 R 569 0 R 573 0 R 577 0 R 581 0 R 585 0 R 589 0 R 593 0 R 597 0 R 601 0 R 605 0 R 609 0 R 613 0 R 617 0 R 621 0 R 625 0 R 629 0 R 633 0 R 637 0 R 641 0 R 645 0 R 649 0 R 653 0 R 657 0 R 661 0 R 665 0 R 669 0 R 673 0 R 677 0 R 681 0 R 685 0 R 689 0 R 693 0 R 697 0 R 701 0 R 705 0 R 709 0 R 713 0 R 717 0 R 721 0 R 725 0 R 729 0 R 733 0 R 737 0 R 741 0 R 745 0 R 749 0 R 753 0 R 757 0 R 761 0 R 765 0 R 769 0 R 773 0 R 777 0 R 781 0 R 785 0 R 789 0 R 793 0 R 797 0 R 801 0 R ] /Count 200 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 8 0 obj <> endobj 12 0 obj <> endobj 16 0 obj <> endobj 20 0 obj <> endobj 24 0 obj <> endobj 28 0 obj <> endobj 32 0 obj <> endobj 36 0 obj <> endobj 40 0 obj <> endobj 44 0 obj <> endobj 48 0 obj <> endobj 52 0 obj <> endobj 56 0 obj <> endobj 60 0 obj <> endobj 64 0 obj <> endobj 68 0 obj <> endobj 72 0 obj <> endobj 76 0 obj <> endobj 80 0 obj <> endobj 84 0 obj <> endobj 88 0 obj <> endobj 92 0 obj <> endobj 96 0 obj <> endobj 100 0 obj <> endobj 104 0 obj <> endobj 108 0 obj <> endobj 112 0 obj <> endobj 116 0 obj <> endobj 120 0 obj <> endobj 124 0 obj <> endobj 128 0 obj <> endobj 132 0 obj <> endobj 136 0 obj <> endobj 140 0 obj <> endobj 144 0 obj <> endobj 148 0 obj <> endobj 152 0 obj <> endobj 156 0 obj <> endobj 160 0 obj <> endobj 164 0 obj <> endobj 168 0 obj <> endobj 172 0 obj <> endobj 176 0 obj <> endobj 180 0 obj <> endobj 184 0 obj <> endobj 188 0 obj <> endobj 192 0 obj <> endobj 196 0 obj <> endobj 200 0 obj <> endobj 204 0 obj <> endobj 208 0 obj <> endobj 212 0 obj <> endobj 216 0 obj <> endobj 220 0 obj <> endobj 224 0 obj <> endobj 228 0 obj <> endobj 232 0 obj <> endobj 236 0 obj <> endobj 240 0 obj <> endobj 244 0 obj <> endobj 248 0 obj <> endobj 252 0 obj <> endobj 256 0 obj <> endobj 260 0 obj <> endobj 264 0 obj <> endobj 268 0 obj <> endobj 272 0 obj <> endobj 276 0 obj <> endobj 280 0 obj <> endobj 284 0 obj <> endobj 288 0 obj <> endobj 292 0 obj <> endobj 296 0 obj <> endobj 300 0 obj <> endobj 304 0 obj <> endobj 308 0 obj <> endobj 312 0 obj <> endobj 316 0 obj <> endobj 320 0 obj <> endobj 324 0 obj <> endobj 328 0 obj <> endobj 332 0 obj <> endobj 336 0 obj <> endobj 340 0 obj <> endobj 344 0 obj <> endobj 348 0 obj <> endobj 352 0 obj <> endobj 356 0 obj <> endobj 360 0 obj <> endobj 364 0 obj <> endobj 368 0 obj <> endobj 372 0 obj <> endobj 376 0 obj <> endobj 380 0 obj <> endobj 384 0 obj <> endobj 388 0 obj <> endobj 392 0 obj <> endobj 396 0 obj <> endobj 400 0 obj <> endobj 404 0 obj <> endobj 408 0 obj <> endobj 412 0 obj <> endobj 416 0 obj <> endobj 420 0 obj <> endobj 424 0 obj <> endobj 428 0 obj <> endobj 432 0 obj <> endobj 436 0 obj <> endobj 440 0 obj <> endobj 444 0 obj <> endobj 448 0 obj <> endobj 452 0 obj <> endobj 456 0 obj <> endobj 460 0 obj <> endobj 464 0 obj <> endobj 468 0 obj <> endobj 472 0 obj <> endobj 476 0 obj <> endobj 480 0 obj <> endobj 484 0 obj <> endobj 488 0 obj <> endobj 492 0 obj <> endobj 496 0 obj <> endobj 500 0 obj <> endobj 504 0 obj <> endobj 508 0 obj <> endobj 512 0 obj <> endobj 516 0 obj <> endobj 520 0 obj <> endobj 524 0 obj <> endobj 528 0 obj <> endobj 532 0 obj <> endobj 536 0 obj <> endobj 540 0 obj <> endobj 544 0 obj <> endobj 548 0 obj <> endobj 552 0 obj <> endobj 556 0 obj <> endobj 560 0 obj <> endobj 564 0 obj <> endobj 568 0 obj <> endobj 572 0 obj <> endobj 576 0 obj <> endobj 580 0 obj <> endobj 584 0 obj <> endobj 588 0 obj <> endobj 592 0 obj <> endobj 596 0 obj <> endobj 600 0 obj <> endobj 604 0 obj <> endobj 608 0 obj <> endobj 612 0 obj <> endobj 616 0 obj <> endobj 620 0 obj <> endobj 624 0 obj <> endobj 628 0 obj <> endobj 632 0 obj <> endobj 636 0 obj <> endobj 640 0 obj <> endobj 644 0 obj <> endobj 648 0 obj <> endobj 652 0 obj <> endobj 656 0 obj <> endobj 660 0 obj <> endobj 664 0 obj <> endobj 668 0 obj <> endobj 672 0 obj <> endobj 676 0 obj <> endobj 680 0 obj <> endobj 684 0 obj <> endobj 688 0 obj <> endobj 692 0 obj <> endobj 696 0 obj <> endobj 700 0 obj <> endobj 704 0 obj <> endobj 708 0 obj <> endobj 712 0 obj <> endobj 716 0 obj <> endobj 720 0 obj <> endobj 724 0 obj <> endobj 728 0 obj <> endobj 732 0 obj <> endobj 736 0 obj <> endobj 740 0 obj <> endobj 744 0 obj <> endobj 748 0 obj <> endobj 752 0 obj <> endobj 756 0 obj <> endobj 760 0 obj <> endobj 764 0 obj <> endobj 768 0 obj <> endobj 772 0 obj <> endobj 776 0 obj <> endobj 780 0 obj <> endobj 784 0 obj <> endobj 788 0 obj <> endobj 792 0 obj <> endobj 796 0 obj <> endobj 800 0 obj <> endobj 804 0 obj <> endobj 805 0 obj <>stream 2018-04-17T21:15:35Z 2018-04-17T21:15:35Z UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 806 0000000000 65535 f 0000054894 00000 n 0000062609 00000 n 0000053265 00000 n 0000024740 00000 n 0000000015 00000 n 0000000115 00000 n 0000054960 00000 n 0000055021 00000 n 0000024877 00000 n 0000000133 00000 n 0000000235 00000 n 0000055050 00000 n 0000025016 00000 n 0000000254 00000 n 0000000356 00000 n 0000055080 00000 n 0000025156 00000 n 0000000375 00000 n 0000000477 00000 n 0000055110 00000 n 0000025296 00000 n 0000000496 00000 n 0000000598 00000 n 0000055140 00000 n 0000025436 00000 n 0000000617 00000 n 0000000719 00000 n 0000055170 00000 n 0000025576 00000 n 0000000738 00000 n 0000000840 00000 n 0000055200 00000 n 0000025716 00000 n 0000000859 00000 n 0000000961 00000 n 0000055230 00000 n 0000025856 00000 n 0000000980 00000 n 0000001082 00000 n 0000055260 00000 n 0000025996 00000 n 0000001101 00000 n 0000001203 00000 n 0000055290 00000 n 0000026136 00000 n 0000001222 00000 n 0000001324 00000 n 0000055320 00000 n 0000026276 00000 n 0000001343 00000 n 0000001445 00000 n 0000055350 00000 n 0000026416 00000 n 0000001464 00000 n 0000001566 00000 n 0000055380 00000 n 0000026556 00000 n 0000001585 00000 n 0000001687 00000 n 0000055410 00000 n 0000026696 00000 n 0000001706 00000 n 0000001808 00000 n 0000055440 00000 n 0000026836 00000 n 0000001827 00000 n 0000001929 00000 n 0000055470 00000 n 0000026976 00000 n 0000001948 00000 n 0000002050 00000 n 0000055500 00000 n 0000027116 00000 n 0000002069 00000 n 0000002171 00000 n 0000055530 00000 n 0000027256 00000 n 0000002190 00000 n 0000002292 00000 n 0000055560 00000 n 0000027396 00000 n 0000002311 00000 n 0000002413 00000 n 0000055590 00000 n 0000027536 00000 n 0000002432 00000 n 0000002534 00000 n 0000055620 00000 n 0000027676 00000 n 0000002553 00000 n 0000002655 00000 n 0000055650 00000 n 0000027816 00000 n 0000002674 00000 n 0000002776 00000 n 0000055680 00000 n 0000027956 00000 n 0000002795 00000 n 0000002897 00000 n 0000055710 00000 n 0000028097 00000 n 0000002916 00000 n 0000003020 00000 n 0000055741 00000 n 0000028240 00000 n 0000003040 00000 n 0000003144 00000 n 0000055772 00000 n 0000028383 00000 n 0000003164 00000 n 0000003268 00000 n 0000055803 00000 n 0000028526 00000 n 0000003288 00000 n 0000003392 00000 n 0000055834 00000 n 0000028669 00000 n 0000003412 00000 n 0000003516 00000 n 0000055865 00000 n 0000028812 00000 n 0000003536 00000 n 0000003640 00000 n 0000055896 00000 n 0000028955 00000 n 0000003660 00000 n 0000003764 00000 n 0000055927 00000 n 0000029098 00000 n 0000003784 00000 n 0000003888 00000 n 0000055958 00000 n 0000029241 00000 n 0000003908 00000 n 0000004012 00000 n 0000055989 00000 n 0000029384 00000 n 0000004032 00000 n 0000004136 00000 n 0000056020 00000 n 0000029527 00000 n 0000004156 00000 n 0000004260 00000 n 0000056051 00000 n 0000029670 00000 n 0000004280 00000 n 0000004384 00000 n 0000056082 00000 n 0000029813 00000 n 0000004404 00000 n 0000004508 00000 n 0000056113 00000 n 0000029956 00000 n 0000004528 00000 n 0000004632 00000 n 0000056144 00000 n 0000030099 00000 n 0000004652 00000 n 0000004756 00000 n 0000056175 00000 n 0000030242 00000 n 0000004776 00000 n 0000004880 00000 n 0000056206 00000 n 0000030385 00000 n 0000004900 00000 n 0000005004 00000 n 0000056237 00000 n 0000030528 00000 n 0000005024 00000 n 0000005128 00000 n 0000056268 00000 n 0000030671 00000 n 0000005148 00000 n 0000005252 00000 n 0000056299 00000 n 0000030814 00000 n 0000005272 00000 n 0000005376 00000 n 0000056330 00000 n 0000030957 00000 n 0000005396 00000 n 0000005500 00000 n 0000056361 00000 n 0000031100 00000 n 0000005520 00000 n 0000005624 00000 n 0000056392 00000 n 0000031243 00000 n 0000005644 00000 n 0000005748 00000 n 0000056423 00000 n 0000031386 00000 n 0000005768 00000 n 0000005872 00000 n 0000056454 00000 n 0000031529 00000 n 0000005892 00000 n 0000005996 00000 n 0000056485 00000 n 0000031672 00000 n 0000006016 00000 n 0000006120 00000 n 0000056516 00000 n 0000031815 00000 n 0000006140 00000 n 0000006244 00000 n 0000056547 00000 n 0000031958 00000 n 0000006264 00000 n 0000006368 00000 n 0000056578 00000 n 0000032101 00000 n 0000006388 00000 n 0000006492 00000 n 0000056609 00000 n 0000032244 00000 n 0000006512 00000 n 0000006616 00000 n 0000056640 00000 n 0000032387 00000 n 0000006636 00000 n 0000006740 00000 n 0000056671 00000 n 0000032530 00000 n 0000006760 00000 n 0000006864 00000 n 0000056702 00000 n 0000032673 00000 n 0000006884 00000 n 0000006988 00000 n 0000056733 00000 n 0000032816 00000 n 0000007008 00000 n 0000007112 00000 n 0000056764 00000 n 0000032959 00000 n 0000007132 00000 n 0000007236 00000 n 0000056795 00000 n 0000033102 00000 n 0000007256 00000 n 0000007360 00000 n 0000056826 00000 n 0000033245 00000 n 0000007380 00000 n 0000007484 00000 n 0000056857 00000 n 0000033388 00000 n 0000007504 00000 n 0000007608 00000 n 0000056888 00000 n 0000033531 00000 n 0000007628 00000 n 0000007732 00000 n 0000056919 00000 n 0000033674 00000 n 0000007752 00000 n 0000007856 00000 n 0000056950 00000 n 0000033817 00000 n 0000007876 00000 n 0000007980 00000 n 0000056981 00000 n 0000033960 00000 n 0000008000 00000 n 0000008104 00000 n 0000057012 00000 n 0000034103 00000 n 0000008124 00000 n 0000008228 00000 n 0000057043 00000 n 0000034246 00000 n 0000008248 00000 n 0000008352 00000 n 0000057074 00000 n 0000034389 00000 n 0000008372 00000 n 0000008476 00000 n 0000057105 00000 n 0000034532 00000 n 0000008496 00000 n 0000008600 00000 n 0000057136 00000 n 0000034675 00000 n 0000008620 00000 n 0000008724 00000 n 0000057167 00000 n 0000034818 00000 n 0000008744 00000 n 0000008848 00000 n 0000057198 00000 n 0000034961 00000 n 0000008868 00000 n 0000008972 00000 n 0000057229 00000 n 0000035104 00000 n 0000008992 00000 n 0000009096 00000 n 0000057260 00000 n 0000035247 00000 n 0000009116 00000 n 0000009220 00000 n 0000057291 00000 n 0000035390 00000 n 0000009240 00000 n 0000009344 00000 n 0000057322 00000 n 0000035533 00000 n 0000009364 00000 n 0000009468 00000 n 0000057353 00000 n 0000035676 00000 n 0000009488 00000 n 0000009592 00000 n 0000057384 00000 n 0000035819 00000 n 0000009612 00000 n 0000009716 00000 n 0000057415 00000 n 0000035962 00000 n 0000009736 00000 n 0000009840 00000 n 0000057446 00000 n 0000036105 00000 n 0000009860 00000 n 0000009964 00000 n 0000057477 00000 n 0000036248 00000 n 0000009984 00000 n 0000010088 00000 n 0000057508 00000 n 0000036391 00000 n 0000010108 00000 n 0000010212 00000 n 0000057539 00000 n 0000036534 00000 n 0000010232 00000 n 0000010336 00000 n 0000057570 00000 n 0000036677 00000 n 0000010356 00000 n 0000010460 00000 n 0000057601 00000 n 0000036820 00000 n 0000010480 00000 n 0000010584 00000 n 0000057632 00000 n 0000036963 00000 n 0000010604 00000 n 0000010708 00000 n 0000057663 00000 n 0000037106 00000 n 0000010728 00000 n 0000010832 00000 n 0000057694 00000 n 0000037249 00000 n 0000010852 00000 n 0000010956 00000 n 0000057725 00000 n 0000037392 00000 n 0000010976 00000 n 0000011080 00000 n 0000057756 00000 n 0000037535 00000 n 0000011100 00000 n 0000011204 00000 n 0000057787 00000 n 0000037678 00000 n 0000011224 00000 n 0000011328 00000 n 0000057818 00000 n 0000037821 00000 n 0000011348 00000 n 0000011452 00000 n 0000057849 00000 n 0000037964 00000 n 0000011472 00000 n 0000011576 00000 n 0000057880 00000 n 0000038107 00000 n 0000011596 00000 n 0000011700 00000 n 0000057911 00000 n 0000038250 00000 n 0000011720 00000 n 0000011824 00000 n 0000057942 00000 n 0000038393 00000 n 0000011844 00000 n 0000011948 00000 n 0000057973 00000 n 0000038536 00000 n 0000011968 00000 n 0000012072 00000 n 0000058004 00000 n 0000038679 00000 n 0000012092 00000 n 0000012196 00000 n 0000058035 00000 n 0000038822 00000 n 0000012216 00000 n 0000012320 00000 n 0000058066 00000 n 0000038965 00000 n 0000012340 00000 n 0000012444 00000 n 0000058097 00000 n 0000039108 00000 n 0000012464 00000 n 0000012568 00000 n 0000058128 00000 n 0000039251 00000 n 0000012588 00000 n 0000012692 00000 n 0000058159 00000 n 0000039394 00000 n 0000012712 00000 n 0000012816 00000 n 0000058190 00000 n 0000039537 00000 n 0000012836 00000 n 0000012940 00000 n 0000058221 00000 n 0000039680 00000 n 0000012960 00000 n 0000013064 00000 n 0000058252 00000 n 0000039823 00000 n 0000013084 00000 n 0000013188 00000 n 0000058283 00000 n 0000039966 00000 n 0000013208 00000 n 0000013312 00000 n 0000058314 00000 n 0000040109 00000 n 0000013332 00000 n 0000013436 00000 n 0000058345 00000 n 0000040252 00000 n 0000013456 00000 n 0000013560 00000 n 0000058376 00000 n 0000040395 00000 n 0000013580 00000 n 0000013684 00000 n 0000058407 00000 n 0000040538 00000 n 0000013704 00000 n 0000013808 00000 n 0000058438 00000 n 0000040681 00000 n 0000013828 00000 n 0000013932 00000 n 0000058469 00000 n 0000040824 00000 n 0000013952 00000 n 0000014056 00000 n 0000058500 00000 n 0000040967 00000 n 0000014076 00000 n 0000014180 00000 n 0000058531 00000 n 0000041110 00000 n 0000014200 00000 n 0000014304 00000 n 0000058562 00000 n 0000041253 00000 n 0000014324 00000 n 0000014428 00000 n 0000058593 00000 n 0000041396 00000 n 0000014448 00000 n 0000014552 00000 n 0000058624 00000 n 0000041539 00000 n 0000014572 00000 n 0000014676 00000 n 0000058655 00000 n 0000041682 00000 n 0000014696 00000 n 0000014800 00000 n 0000058686 00000 n 0000041825 00000 n 0000014820 00000 n 0000014924 00000 n 0000058717 00000 n 0000041968 00000 n 0000014944 00000 n 0000015048 00000 n 0000058748 00000 n 0000042111 00000 n 0000015068 00000 n 0000015172 00000 n 0000058779 00000 n 0000042254 00000 n 0000015192 00000 n 0000015296 00000 n 0000058810 00000 n 0000042397 00000 n 0000015316 00000 n 0000015420 00000 n 0000058841 00000 n 0000042540 00000 n 0000015440 00000 n 0000015544 00000 n 0000058872 00000 n 0000042683 00000 n 0000015564 00000 n 0000015668 00000 n 0000058903 00000 n 0000042826 00000 n 0000015688 00000 n 0000015792 00000 n 0000058934 00000 n 0000042969 00000 n 0000015812 00000 n 0000015916 00000 n 0000058965 00000 n 0000043112 00000 n 0000015936 00000 n 0000016040 00000 n 0000058996 00000 n 0000043255 00000 n 0000016060 00000 n 0000016164 00000 n 0000059027 00000 n 0000043398 00000 n 0000016184 00000 n 0000016288 00000 n 0000059058 00000 n 0000043541 00000 n 0000016308 00000 n 0000016412 00000 n 0000059089 00000 n 0000043684 00000 n 0000016432 00000 n 0000016536 00000 n 0000059120 00000 n 0000043827 00000 n 0000016556 00000 n 0000016660 00000 n 0000059151 00000 n 0000043970 00000 n 0000016680 00000 n 0000016784 00000 n 0000059182 00000 n 0000044113 00000 n 0000016804 00000 n 0000016908 00000 n 0000059213 00000 n 0000044256 00000 n 0000016928 00000 n 0000017032 00000 n 0000059244 00000 n 0000044399 00000 n 0000017052 00000 n 0000017156 00000 n 0000059275 00000 n 0000044542 00000 n 0000017176 00000 n 0000017280 00000 n 0000059306 00000 n 0000044685 00000 n 0000017300 00000 n 0000017404 00000 n 0000059337 00000 n 0000044828 00000 n 0000017424 00000 n 0000017528 00000 n 0000059368 00000 n 0000044971 00000 n 0000017548 00000 n 0000017652 00000 n 0000059399 00000 n 0000045114 00000 n 0000017672 00000 n 0000017776 00000 n 0000059430 00000 n 0000045257 00000 n 0000017796 00000 n 0000017900 00000 n 0000059461 00000 n 0000045400 00000 n 0000017920 00000 n 0000018024 00000 n 0000059492 00000 n 0000045543 00000 n 0000018044 00000 n 0000018148 00000 n 0000059523 00000 n 0000045686 00000 n 0000018168 00000 n 0000018272 00000 n 0000059554 00000 n 0000045829 00000 n 0000018292 00000 n 0000018396 00000 n 0000059585 00000 n 0000045972 00000 n 0000018416 00000 n 0000018520 00000 n 0000059616 00000 n 0000046115 00000 n 0000018540 00000 n 0000018644 00000 n 0000059647 00000 n 0000046258 00000 n 0000018664 00000 n 0000018768 00000 n 0000059678 00000 n 0000046401 00000 n 0000018788 00000 n 0000018892 00000 n 0000059709 00000 n 0000046544 00000 n 0000018912 00000 n 0000019016 00000 n 0000059740 00000 n 0000046687 00000 n 0000019036 00000 n 0000019140 00000 n 0000059771 00000 n 0000046830 00000 n 0000019160 00000 n 0000019264 00000 n 0000059802 00000 n 0000046973 00000 n 0000019284 00000 n 0000019388 00000 n 0000059833 00000 n 0000047116 00000 n 0000019408 00000 n 0000019512 00000 n 0000059864 00000 n 0000047259 00000 n 0000019532 00000 n 0000019636 00000 n 0000059895 00000 n 0000047402 00000 n 0000019656 00000 n 0000019760 00000 n 0000059926 00000 n 0000047545 00000 n 0000019780 00000 n 0000019884 00000 n 0000059957 00000 n 0000047688 00000 n 0000019904 00000 n 0000020008 00000 n 0000059988 00000 n 0000047831 00000 n 0000020028 00000 n 0000020132 00000 n 0000060019 00000 n 0000047974 00000 n 0000020152 00000 n 0000020256 00000 n 0000060050 00000 n 0000048117 00000 n 0000020276 00000 n 0000020380 00000 n 0000060081 00000 n 0000048260 00000 n 0000020400 00000 n 0000020504 00000 n 0000060112 00000 n 0000048403 00000 n 0000020524 00000 n 0000020628 00000 n 0000060143 00000 n 0000048546 00000 n 0000020648 00000 n 0000020752 00000 n 0000060174 00000 n 0000048689 00000 n 0000020772 00000 n 0000020876 00000 n 0000060205 00000 n 0000048832 00000 n 0000020896 00000 n 0000021000 00000 n 0000060236 00000 n 0000048975 00000 n 0000021020 00000 n 0000021124 00000 n 0000060267 00000 n 0000049118 00000 n 0000021144 00000 n 0000021248 00000 n 0000060298 00000 n 0000049261 00000 n 0000021268 00000 n 0000021372 00000 n 0000060329 00000 n 0000049404 00000 n 0000021392 00000 n 0000021496 00000 n 0000060360 00000 n 0000049547 00000 n 0000021516 00000 n 0000021620 00000 n 0000060391 00000 n 0000049690 00000 n 0000021640 00000 n 0000021744 00000 n 0000060422 00000 n 0000049833 00000 n 0000021764 00000 n 0000021868 00000 n 0000060453 00000 n 0000049976 00000 n 0000021888 00000 n 0000021992 00000 n 0000060484 00000 n 0000050119 00000 n 0000022012 00000 n 0000022116 00000 n 0000060515 00000 n 0000050262 00000 n 0000022136 00000 n 0000022240 00000 n 0000060546 00000 n 0000050405 00000 n 0000022260 00000 n 0000022364 00000 n 0000060577 00000 n 0000050548 00000 n 0000022384 00000 n 0000022488 00000 n 0000060608 00000 n 0000050691 00000 n 0000022508 00000 n 0000022612 00000 n 0000060639 00000 n 0000050834 00000 n 0000022632 00000 n 0000022736 00000 n 0000060670 00000 n 0000050977 00000 n 0000022756 00000 n 0000022860 00000 n 0000060701 00000 n 0000051120 00000 n 0000022880 00000 n 0000022984 00000 n 0000060732 00000 n 0000051263 00000 n 0000023004 00000 n 0000023108 00000 n 0000060763 00000 n 0000051406 00000 n 0000023128 00000 n 0000023232 00000 n 0000060794 00000 n 0000051549 00000 n 0000023252 00000 n 0000023356 00000 n 0000060825 00000 n 0000051692 00000 n 0000023376 00000 n 0000023480 00000 n 0000060856 00000 n 0000051835 00000 n 0000023500 00000 n 0000023604 00000 n 0000060887 00000 n 0000051978 00000 n 0000023624 00000 n 0000023728 00000 n 0000060918 00000 n 0000052121 00000 n 0000023748 00000 n 0000023852 00000 n 0000060949 00000 n 0000052264 00000 n 0000023872 00000 n 0000023976 00000 n 0000060980 00000 n 0000052407 00000 n 0000023996 00000 n 0000024100 00000 n 0000061011 00000 n 0000052550 00000 n 0000024120 00000 n 0000024224 00000 n 0000061042 00000 n 0000052693 00000 n 0000024244 00000 n 0000024348 00000 n 0000061073 00000 n 0000052836 00000 n 0000024368 00000 n 0000024472 00000 n 0000061104 00000 n 0000052979 00000 n 0000024492 00000 n 0000024596 00000 n 0000061135 00000 n 0000053122 00000 n 0000024616 00000 n 0000024720 00000 n 0000061166 00000 n 0000061197 00000 n trailer << /Size 806 /Root 1 0 R /Info 2 0 R /ID [<9E6D85AA6B3DFDFB7051887B05827804><9E6D85AA6B3DFDFB7051887B05827804>] >> startxref 62732 %%EOF braintree_python-4.31.0/tests/integration/000077500000000000000000000000001471021343500206405ustar00rootroot00000000000000braintree_python-4.31.0/tests/integration/__init__.py000066400000000000000000000000001471021343500227370ustar00rootroot00000000000000braintree_python-4.31.0/tests/integration/test_add_ons.py000066400000000000000000000022761471021343500236670ustar00rootroot00000000000000from tests.test_helper import * class TestAddOn(unittest.TestCase): def test_all_returns_all_add_ons(self): new_id = str(random.randint(1, 1000000)) attributes = { "amount": "100.00", "description": "some description", "id": new_id, "kind": "add_on", "name": "python_add_on", "never_expires": False, "number_of_billing_cycles": 1 } Configuration.instantiate().http().post(Configuration.instantiate().base_merchant_path() + "/modifications/create_modification_for_tests", {"modification": attributes}) add_ons = AddOn.all() for add_on in add_ons: if add_on.id == new_id: break else: add_on = None self.assertNotEqual(None, add_on) self.assertEqual(Decimal("100.00"), add_on.amount) self.assertEqual("some description", add_on.description) self.assertEqual(new_id, add_on.id) self.assertEqual("add_on", add_on.kind) self.assertEqual("python_add_on", add_on.name) self.assertEqual(False, add_on.never_expires) self.assertEqual(add_on.number_of_billing_cycles, 1) braintree_python-4.31.0/tests/integration/test_address.py000066400000000000000000000176411471021343500237070ustar00rootroot00000000000000from 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", "phone_number": "8675309", "international_phone": {"country_code": "1", "national_number": "3121234567"}, "country_name": "United States of America", "country_code_alpha2": "US", "country_code_alpha3": "USA", "country_code_numeric": "840" }) self.assertTrue(result.is_success) address = result.address self.assertEqual(customer.id, address.customer_id) self.assertEqual("Ben", address.first_name) self.assertEqual("Moore", address.last_name) self.assertEqual("Moore Co.", address.company) self.assertEqual("1811 E Main St", address.street_address) self.assertEqual("Suite 200", address.extended_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60622", address.postal_code) self.assertEqual("8675309", address.phone_number) self.assertEqual("1", address.international_phone["country_code"]) self.assertEqual("3121234567", address.international_phone["national_number"]) self.assertEqual("US", address.country_code_alpha2) self.assertEqual("USA", address.country_code_alpha3) self.assertEqual("840", address.country_code_numeric) self.assertEqual("United States of America", address.country_name) def test_error_response_if_invalid(self): customer = Customer.create().customer result = Address.create({ "customer_id": customer.id, "country_name": "zzzzzz", "country_code_alpha2": "zz", "country_code_alpha3": "zzz", "country_code_numeric": "000" }) self.assertFalse(result.is_success) country_name_errors = result.errors.for_object("address").on("country_name") self.assertEqual(1, len(country_name_errors)) self.assertEqual(ErrorCodes.Address.CountryNameIsNotAccepted, country_name_errors[0].code) country_code_alpha2_errors = result.errors.for_object("address").on("country_code_alpha2") self.assertEqual(1, len(country_code_alpha2_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, country_code_alpha2_errors[0].code) country_code_alpha3_errors = result.errors.for_object("address").on("country_code_alpha3") self.assertEqual(1, len(country_code_alpha3_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha3IsNotAccepted, country_code_alpha3_errors[0].code) country_code_numeric_errors = result.errors.for_object("address").on("country_code_numeric") self.assertEqual(1, len(country_code_numeric_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeNumericIsNotAccepted, country_code_numeric_errors[0].code) def test_error_response_if_inconsistent_country(self): customer = Customer.create().customer result = Address.create({ "customer_id": customer.id, "country_code_alpha2": "US", "country_code_alpha3": "MEX" }) self.assertFalse(result.is_success) address_errors = result.errors.for_object("address").on("base") self.assertEqual(1, len(address_errors)) self.assertEqual(ErrorCodes.Address.InconsistentCountry, address_errors[0].code) def test_delete_with_valid_customer_id_and_address_id(self): customer = Customer.create().customer address = Address.create({"customer_id": customer.id, "street_address": "123 Main St."}).address result = Address.delete(customer.id, address.id) self.assertTrue(result.is_success) def test_delete_with_valid_customer_id_and_non_existing_address(self): with self.assertRaises(NotFoundError): customer = Customer.create().customer Address.delete(customer.id, "notreal") def test_find_with_valid_customer_id_and_address_id(self): customer = Customer.create().customer address = Address.create({"customer_id": customer.id, "street_address": "123 Main St."}).address found_address = Address.find(customer.id, address.id) self.assertEqual(address.street_address, found_address.street_address) def test_find_with_invalid_customer_id_and_address_id(self): with self.assertRaisesRegex(NotFoundError, "address for customer 'notreal' with id 'badaddress' not found"): Address.find("notreal", "badaddress") def test_update_with_valid_values(self): customer = Customer.create().customer address = Address.create({ "customer_id": customer.id, "street_address": "1811 E Main St", "extended_address": "Suite 200", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America" }).address result = Address.update(customer.id, address.id, { "street_address": "123 E New St", "extended_address": "New Suite 3", "locality": "Chicago", "region": "Illinois", "postal_code": "60621", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484", "country_name": "Mexico", "phone_number": "8675309", "international_phone": {"country_code": "1", "national_number": "3121234567"} }) self.assertTrue(result.is_success) address = result.address self.assertEqual(customer.id, address.customer_id) self.assertEqual("123 E New St", address.street_address) self.assertEqual("New Suite 3", address.extended_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60621", address.postal_code) self.assertEqual("MX", address.country_code_alpha2) self.assertEqual("MEX", address.country_code_alpha3) self.assertEqual("484", address.country_code_numeric) self.assertEqual("Mexico", address.country_name) self.assertEqual("8675309", address.phone_number) self.assertEqual("1", address.international_phone["country_code"]) self.assertEqual("3121234567", address.international_phone["national_number"]) def test_update_with_invalid_values(self): customer = Customer.create().customer address = Address.create({ "customer_id": customer.id, "street_address": "1811 E Main St", "extended_address": "Suite 200", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America" }).address result = Address.update(customer.id, address.id, { "street_address": "123 E New St", "country_name": "United States of Invalid" }) self.assertFalse(result.is_success) country_name_errors = result.errors.for_object("address").on("country_name") self.assertEqual(1, len(country_name_errors)) self.assertEqual(ErrorCodes.Address.CountryNameIsNotAccepted, country_name_errors[0].code) def test_update_raises_not_found_error_if_given_bad_address(self): with self.assertRaises(NotFoundError): customer = Customer.create().customer Address.update(customer.id, "notfound", {"street_address": "123 Main St."}) braintree_python-4.31.0/tests/integration/test_apple_pay.py000066400000000000000000000042121471021343500242220ustar00rootroot00000000000000from tests.test_helper import * class TestApplePay(unittest.TestCase): @staticmethod def get_gateway(): config = Configuration("development", "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key") return BraintreeGateway(config) def test_register_domain_registers_an_apple_pay_domain(self): result = self.get_gateway().apple_pay.register_domain("www.example.com") self.assertTrue(result.is_success) def test_register_domain_gets_a_validation_error_when_attempting_to_register_no_domains(self): result = self.get_gateway().apple_pay.register_domain("") self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("apple_pay")[0].message, "Domain name is required.") def test_delete_customer_with_path_traversal(self): try: customer = Customer.create({"first_name":"Waldo"}).customer self.get_gateway().apple_pay.unregister_domain("../../../customers/{}".format(customer.id)) except NotFoundError: pass found_customer = Customer.find(customer.id) self.assertNotEqual(None, found_customer) self.assertEqual("Waldo", found_customer.first_name) def test_unregister_domain_unregisters_an_apple_pay_domain(self): result = self.get_gateway().apple_pay.unregister_domain("example.org") self.assertTrue(result.is_success) def test_unregister_domain_unregisters_an_apple_pay_domain_with_schem_in_url(self): result = self.get_gateway().apple_pay.unregister_domain("http://example.org") self.assertTrue(result.is_success) def test_unregister_domain_escapes_the_unregistered_domain_query_parameter(self): result = self.get_gateway().apple_pay.unregister_domain("ex&mple.org") self.assertTrue(result.is_success) def test_registered_domains_returns_stubbed_registered_domains(self): result = self.get_gateway().apple_pay.registered_domains() self.assertEqual(len(result), 1) self.assertEqual(result[0], "www.example.com") braintree_python-4.31.0/tests/integration/test_braintree_gateway.py000066400000000000000000000047221471021343500257520ustar00rootroot00000000000000from tests.test_helper import * from braintree.braintree_gateway import BraintreeGateway from braintree.configuration import Configuration from braintree.environment import Environment class TestBraintreeGateway(unittest.TestCase): @staticmethod def get_gateway(): config = Configuration("development", "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key") return BraintreeGateway(config) @unittest.skip("until we have a more stable ci env") def test_can_make_tokenize_credit_card_via_graphql(self): definition = """ mutation ExampleServerSideSingleUseToken($input: TokenizeCreditCardInput!) { tokenizeCreditCard(input: $input) { paymentMethod { id usage details { ... on CreditCardDetails { bin brandCode last4 expirationYear expirationMonth } } } } } """ variables = { "input" : { "creditCard" : { "number" : "4005519200000004", "expirationYear": "2024", "expirationMonth": "05", "cardholderName": "Joe Bloggs" } } } gateway = self.get_gateway() response = gateway.graphql_client.query(definition, variables) payment_method = response["data"]["tokenizeCreditCard"]["paymentMethod"] details = payment_method["details"] self.assertTrue("data" in response) self.assertTrue("id" in payment_method) self.assertEqual(details["bin"], "400551") self.assertEqual(details["last4"], "0004"); self.assertEqual(details["brandCode"], "VISA"); self.assertEqual(details["expirationMonth"], "05"); self.assertEqual(details["expirationYear"], "2024"); def test_can_make_graphql_queries_without_variables(self): definition = """ query { ping } """ gateway = self.get_gateway() response = gateway.graphql_client.query(definition) self.assertTrue("data" in response) self.assertTrue("ping" in response["data"]) self.assertEqual("pong", response["data"]["ping"]) braintree_python-4.31.0/tests/integration/test_client_token.py000066400000000000000000000206341471021343500247340ustar00rootroot00000000000000from tests.test_helper import * import json import urllib import datetime import braintree from braintree.util import Http from base64 import b64decode class TestClientTokenGenerate(unittest.TestCase): def test_allows_client_token_version_to_be_specified(self): client_token = ClientToken.generate({"version": 1}) version = json.loads(client_token)["version"] self.assertEqual(1, version) def test_allows_client_token_domains_to_be_specified(self): client_token = ClientToken.generate({"domains": ["example.com"]}) self.assertIsNotNone(client_token) def test_error_for_invalid_domain_format(self): self.assertRaises(ValueError, ClientToken.generate, {"domains": ["example"] }) def test_error_for_too_many_domains(self): self.assertRaises(ValueError, ClientToken.generate, {"domains": [ "example1.com", "example2.com", "example3.com", "example4.com", "example5.com", "example6.com", ]} ) def test_error_in_generate_raises_value_error(self): self.assertRaises(ValueError, ClientToken.generate, { "customer_id": "i_am_not_a_real_customer" }) class TestClientToken(unittest.TestCase): def test_is_authorized_with_authorization_fingerprint(self): config = Configuration.instantiate() client_token = TestHelper.generate_decoded_client_token() authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, _ = http.get_cards() self.assertEqual(200, status_code) def test_client_token_version_defaults_to_two(self): client_token = TestHelper.generate_decoded_client_token() version = json.loads(client_token)["version"] self.assertEqual(2, version) def test_can_pass_verify_card(self): config = Configuration.instantiate() result = braintree.Customer.create() customer_id = result.customer.id client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, "options": { "verify_card": True } }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, _ = http.add_card({ "credit_card": { "number": "4000111111111115", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(422, status_code) def test_can_pass_make_default(self): config = Configuration.instantiate() result = braintree.Customer.create() customer_id = result.customer.id client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, "options": { "make_default": True } }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, _ = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) status_code, _ = http.add_card({ "credit_card": { "number": "4005519200000004", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) customer = braintree.Customer.find(customer_id) self.assertEqual(2, len(customer.credit_cards)) for credit_card in customer.credit_cards: if credit_card.bin == "400551": self.assertTrue(credit_card.default) def test_can_pass_fail_on_duplicate_payment_method(self): config = Configuration.instantiate() result = braintree.Customer.create() customer_id = result.customer.id client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, _ = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, "options": { "fail_on_duplicate_payment_method": True } }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http.set_authorization_fingerprint(authorization_fingerprint) status_code, _ = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(422, status_code) customer = braintree.Customer.find(customer_id) self.assertEqual(1, len(customer.credit_cards)) def test_can_pass_fail_on_duplicate_payment_method_for_customer(self): config = Configuration.instantiate() result = braintree.Customer.create() customer_id = result.customer.id client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, _ = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer_id, "options": { "fail_on_duplicate_payment_method_for_customer": True } }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http.set_authorization_fingerprint(authorization_fingerprint) status_code, _ = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(422, status_code) customer = braintree.Customer.find(customer_id) self.assertEqual(1, len(customer.credit_cards)) def test_can_pass_merchant_account_id(self): expected_merchant_account_id = TestHelper.non_default_merchant_account_id client_token = TestHelper.generate_decoded_client_token({ "merchant_account_id": expected_merchant_account_id }) merchant_account_id = json.loads(client_token)["merchantAccountId"] self.assertEqual(expected_merchant_account_id, merchant_account_id) def test_required_data_cannot_be_overridden(self): with self.assertRaisesRegex(Exception, "'Invalid keys: merchant_id'"): TestHelper.generate_decoded_client_token({ "merchant_id": "1234" }) braintree_python-4.31.0/tests/integration/test_credentials_parser.py000066400000000000000000000067341471021343500261340ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.nonces import Nonces from braintree.credentials_parser import CredentialsParser class TestCredentialsParser(unittest.TestCase): def test_parses_client_credentials(self): parser = CredentialsParser( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) parser.parse_client_credentials() self.assertEqual("client_id$development$integration_client_id", parser.client_id) self.assertEqual("client_secret$development$integration_client_secret", parser.client_secret) self.assertEqual(braintree.Environment.Development, parser.environment) def test_error_on_inconsistent_environment(self): with self.assertRaises(ConfigurationError) as error: parser = CredentialsParser( client_id="client_id$qa$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) parser.parse_client_credentials() config_error = error.exception self.assertIn("Mismatched credential environments", str(config_error)) def test_error_on_missing_client_id(self): with self.assertRaises(ConfigurationError) as error: parser = CredentialsParser( client_id=None, client_secret="client_secret$development$integration_client_secret" ) parser.parse_client_credentials() config_error = error.exception self.assertIn("Missing client_id", str(config_error)) def test_error_on_missing_client_secret(self): with self.assertRaises(ConfigurationError) as error: parser = CredentialsParser( client_id="client_id$development$integration_client_id", client_secret=None ) parser.parse_client_credentials() config_error = error.exception self.assertIn("Missing client_secret", str(config_error)) def test_error_on_invalid_client_id(self): with self.assertRaises(ConfigurationError) as error: parser = CredentialsParser( client_id="client_secret$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) parser.parse_client_credentials() config_error = error.exception self.assertIn("Value passed for client_id is not a client_id", str(config_error)) def test_error_on_invalid_client_secret(self): with self.assertRaises(ConfigurationError) as error: parser = CredentialsParser( client_id="client_id$development$integration_client_id", client_secret="client_id$development$integration_client_secret" ) parser.parse_client_credentials() config_error = error.exception self.assertIn("Value passed for client_secret is not a client_secret", str(config_error)) def test_parses_access_token(self): parser = CredentialsParser( access_token="access_token$development$integration_merchant_id$fb27c79dd" ) parser.parse_access_token() self.assertEqual("access_token$development$integration_merchant_id$fb27c79dd", parser.access_token) self.assertEqual("integration_merchant_id", parser.merchant_id) self.assertEqual(braintree.Environment.Development, parser.environment) braintree_python-4.31.0/tests/integration/test_credit_card.py000066400000000000000000001542721471021343500245270ustar00rootroot00000000000000import datetime from tests.test_helper import * from braintree.test.credit_card_defaults import CreditCardDefaults from braintree.test.credit_card_numbers import CreditCardNumbers class TestCreditCard(unittest.TestCase): def test_create_with_three_d_secure_nonce(self): customer_id = Customer.create().customer.id result = CreditCard.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.ThreeDSecureVisaFullAuthentication, "options": { "verify_card": "true", } }) self.assertTrue(result.is_success) three_d_secure_info = result.credit_card.verification.three_d_secure_info self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertIsInstance(three_d_secure_info.enrolled, str) self.assertIsInstance(three_d_secure_info.cavv, str) self.assertIsInstance(three_d_secure_info.xid, str) self.assertIsInstance(three_d_secure_info.eci_flag, str) self.assertIsInstance(three_d_secure_info.three_d_secure_version, str) def test_create_with_three_d_secure_pass_thru(self): customer_id = Customer.create().customer.id result = CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2009", "three_d_secure_pass_thru": { "three_d_secure_version": "1.1.1", "eci_flag": "05", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": "true", } }) self.assertTrue(result.is_success) def test_create_with_three_d_secure_pass_thru_without_eci_flag(self): customer_id = Customer.create().customer.id result = CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2009", "three_d_secure_pass_thru": { "three_d_secure_version": "1.1.1", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": "true", } }) self.assertFalse(result.is_success) self.assertEqual("EciFlag is required.", result.message) def test_create_adds_credit_card_to_existing_customer(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertTrue(re.search(r"\A\w{4,}\Z", credit_card.token) is not None) self.assertEqual("411111", credit_card.bin) self.assertEqual("1111", credit_card.last_4) self.assertEqual("05", credit_card.expiration_month) self.assertEqual("2014", credit_card.expiration_year) self.assertEqual("05/2014", credit_card.expiration_date) self.assertEqual("John Doe", credit_card.cardholder_name) self.assertNotEqual(re.search(r"\A\w{32}\Z", credit_card.unique_number_identifier), None) self.assertNotEqual(re.search("png", credit_card.image_url), None) def test_create_and_make_default(self): customer = Customer.create().customer card1 = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card self.assertTrue(card1.default) card2 = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe", "options": {"make_default": True} }).credit_card card1 = CreditCard.find(card1.token) self.assertFalse(card1.default) self.assertTrue(card2.default) def test_create_with_expiration_month_and_year(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertEqual("05/2014", credit_card.expiration_date) def test_create_with_security_params(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe", "device_data": "abc123" }) self.assertTrue(result.is_success) def test_create_with_deprecated_security_params_sends_warning(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") 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) assert len(w) > 0 assert issubclass(w[-1].category, DeprecationWarning) def test_create_can_specify_the_desired_token(self): token = str(random.randint(1, 1000000)) customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "token": token }) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertEqual(token, credit_card.token) def test_create_with_billing_address(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484", "country_name": "Mexico", "phone_number": "312-123-4567" } }) self.assertTrue(result.is_success) address = result.credit_card.billing_address self.assertEqual("123 Abc Way", address.street_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60622", address.postal_code) self.assertEqual("MX", address.country_code_alpha2) self.assertEqual("MEX", address.country_code_alpha3) self.assertEqual("484", address.country_code_numeric) self.assertEqual("Mexico", address.country_name) self.assertEqual("312-123-4567", address.phone_number) def test_create_with_billing_address_id(self): customer = Customer.create().customer address = Address.create({ "customer_id": customer.id, "street_address": "123 Abc Way" }).address result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address_id": address.id }) self.assertTrue(result.is_success) billing_address = result.credit_card.billing_address self.assertEqual(address.id, billing_address.id) self.assertEqual("123 Abc Way", billing_address.street_address) def test_create_without_billing_address_still_has_billing_address_method(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", }) self.assertTrue(result.is_success) self.assertEqual(None, result.credit_card.billing_address) def test_unsuccessful_create_with_card_verification_returns_risk_data(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": {"verify_card": True}, "device_data": "abc123" }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertIsInstance(verification.risk_data, RiskData) self.assertTrue(hasattr(verification.risk_data, 'id')) self.assertTrue(hasattr(verification.risk_data, 'decision')) self.assertTrue(hasattr(verification.risk_data, 'decision_reasons')) self.assertTrue(hasattr(verification.risk_data, 'fraud_service_provider')) self.assertTrue(hasattr(verification.risk_data, 'transaction_risk_score')) def test_successful_create_with_card_verification_returns_risk_data(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "options": {"verify_card": True}, "device_data": "abc123" }) self.assertTrue(result.is_success) verification = result.credit_card.verification self.assertIsInstance(verification.risk_data, RiskData) def test_create_includes_risk_data_when_skip_advanced_fraud_checking_is_false(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "options": { "verify_card": True, "skip_advanced_fraud_checking": False }, }) self.assertTrue(result.is_success) verification = result.credit_card.verification self.assertIsInstance(verification.risk_data, RiskData) def test_create_does_not_include_risk_data_when_skip_advanced_fraud_checking_is_true(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "options": { "verify_card": True, "skip_advanced_fraud_checking": True }, }) self.assertTrue(result.is_success) verification = result.credit_card.verification self.assertIsNone(verification.risk_data) def test_create_with_card_verification(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": {"verify_card": True} }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, verification.status) self.assertEqual("2000", verification.processor_response_code) self.assertEqual("Do Not Honor", verification.processor_response_text) self.assertEqual("I", verification.cvv_response_code) self.assertEqual(None, verification.avs_error_response_code) self.assertEqual("I", verification.avs_postal_code_response_code) self.assertEqual("I", verification.avs_street_address_response_code) self.assertEqual(Decimal("0.00"), verification.amount) self.assertEqual("USD", verification.currency_iso_code) self.assertEqual(TestHelper.default_merchant_account_id, verification.merchant_account_id) def test_create_with_card_verification_with_overridden_amount(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": {"verify_card": True, "verification_amount": "1.02"} }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, verification.status) self.assertEqual("2000", verification.processor_response_code) self.assertEqual("Do Not Honor", verification.processor_response_text) self.assertEqual("I", verification.cvv_response_code) self.assertEqual(None, verification.avs_error_response_code) self.assertEqual("I", verification.avs_postal_code_response_code) self.assertEqual("I", verification.avs_street_address_response_code) self.assertEqual(Decimal("1.02"), verification.amount) self.assertEqual("USD", verification.currency_iso_code) self.assertEqual(TestHelper.default_merchant_account_id, verification.merchant_account_id) def test_create_with_card_verification_and_non_default_merchant_account(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": { "verification_merchant_account_id": TestHelper.non_default_merchant_account_id, "verify_card": True } }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, verification.status) self.assertEqual(None, verification.gateway_rejection_reason) self.assertEqual(TestHelper.non_default_merchant_account_id, verification.merchant_account_id) def test_verify_gateway_rejected_responds_to_processor_response_code(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "postal_code": "20000" }, "options": { "verify_card": True } }) self.assertFalse(result.is_success) self.assertEqual('1000', result.credit_card_verification.processor_response_code) self.assertEqual('Approved', result.credit_card_verification.processor_response_text) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_expose_gateway_rejection_reason_on_verification(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "200", "options": { "verify_card": True } }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual(Transaction.GatewayRejectionReason.Cvv, verification.gateway_rejection_reason) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_create_with_card_verification_set_to_false(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": {"verify_card": False} }) self.assertTrue(result.is_success) def test_create_with_fail_on_duplicate_payment_method_set_to_true(self): customer = Customer.create().customer CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014" }) result = CreditCard.create({ "customer_id": customer.id, "number": "4000111111111115", "expiration_date": "05/2014", "options": {"fail_on_duplicate_payment_method": True} }) self.assertFalse(result.is_success) self.assertEqual("Duplicate card exists in the vault.", result.message) credit_card_number_errors = result.errors.for_object("credit_card").on("number") self.assertEqual(1, len(credit_card_number_errors)) self.assertEqual(ErrorCodes.CreditCard.DuplicateCardExists, credit_card_number_errors[0].code) def test_create_with_fail_on_duplicate_payment_method_for_customer_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_for_customer": True} }) self.assertFalse(result.is_success) self.assertEqual("Duplicate card exists in the vault for the customer.", result.message) credit_card_number_errors = result.errors.for_object("credit_card").on("number") self.assertEqual(1, len(credit_card_number_errors)) self.assertEqual(ErrorCodes.CreditCard.DuplicateCardExistsForCustomer, credit_card_number_errors[0].code) def test_create_with_invalid_invalid_options(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "invalid_date", }) self.assertFalse(result.is_success) self.assertEqual("Expiration date is invalid.", result.message) expiration_date_errors = result.errors.for_object("credit_card").on("expiration_date") self.assertEqual(1, len(expiration_date_errors)) self.assertEqual(ErrorCodes.CreditCard.ExpirationDateIsInvalid, expiration_date_errors[0].code) def test_create_with_invalid_country_codes(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2012", "billing_address": { "country_code_alpha2": "ZZ", "country_code_alpha3": "ZZZ", "country_code_numeric": "000", "country_name": "zzzzzzz" } }) self.assertFalse(result.is_success) country_code_alpha2_errors = result.errors.for_object("credit_card").for_object("billing_address").on("country_code_alpha2") self.assertEqual(1, len(country_code_alpha2_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, country_code_alpha2_errors[0].code) country_code_alpha3_errors = result.errors.for_object("credit_card").for_object("billing_address").on("country_code_alpha3") self.assertEqual(1, len(country_code_alpha3_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha3IsNotAccepted, country_code_alpha3_errors[0].code) country_code_numeric_errors = result.errors.for_object("credit_card").for_object("billing_address").on("country_code_numeric") self.assertEqual(1, len(country_code_numeric_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeNumericIsNotAccepted, country_code_numeric_errors[0].code) country_name_errors = result.errors.for_object("credit_card").for_object("billing_address").on("country_name") self.assertEqual(1, len(country_name_errors)) self.assertEqual(ErrorCodes.Address.CountryNameIsNotAccepted, country_name_errors[0].code) def test_create_with_payment_method_nonce(self): config = Configuration.instantiate() authorization_fingerprint = json.loads(TestHelper.generate_decoded_client_token())["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) _, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) nonce = json.loads(response)["creditCards"][0]["nonce"] customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "payment_method_nonce": nonce }) self.assertTrue(result.is_success) self.assertEqual("411111", result.credit_card.bin) def test_delete_customer_with_path_traversal(self): try: customer = Customer.create({"first_name":"Waldo"}).customer CreditCard.delete("../../customers/{}".format(customer.id)) except NotFoundError: pass found_customer = Customer.find(customer.id) self.assertNotEqual(None, found_customer) self.assertEqual("Waldo", found_customer.first_name) def test_update_with_valid_options(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card result = CreditCard.update(credit_card.token, { "number": "5105105105105100", "expiration_date": "06/2010", "cvv": "123", "cardholder_name": "Jane Jones" }) self.assertTrue(result.is_success) credit_card = result.credit_card self.assertTrue(re.search(r"\A\w{4,}\Z", credit_card.token) is not None) self.assertEqual("510510", credit_card.bin) self.assertEqual("5100", credit_card.last_4) self.assertEqual("06", credit_card.expiration_month) self.assertEqual("2010", credit_card.expiration_year) self.assertEqual("06/2010", credit_card.expiration_date) self.assertEqual("Jane Jones", credit_card.cardholder_name) def test_update_with_three_d_secure_pass_thru(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": "4111111111111111", "expiration_date": "05/2009", "cvv": "123", "three_d_secure_pass_thru": { "three_d_secure_version": "1.1.1", "eci_flag": "05", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": "true", } }) self.assertTrue(result.is_success) def test_update_with_three_d_secure_pass_thru_without_eci_flag(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": "4111111111111111", "expiration_date": "05/2009", "cvv": "123", "three_d_secure_pass_thru": { "three_d_secure_version": "1.1.1", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": "true", } }) self.assertFalse(result.is_success) self.assertEqual("EciFlag is required.", result.message) def test_update_billing_address_creates_new_by_default(self): customer = Customer.create().customer initial_credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "123 Nigeria Ave", } }).credit_card updated_credit_card = CreditCard.update(initial_credit_card.token, { "billing_address": { "region": "IL", "country_code_alpha2": "NG", "country_code_alpha3": "NGA", "country_code_numeric": "566", "country_name": "Nigeria" } }).credit_card self.assertEqual("IL", updated_credit_card.billing_address.region) self.assertEqual("NG", updated_credit_card.billing_address.country_code_alpha2) self.assertEqual("NGA", updated_credit_card.billing_address.country_code_alpha3) self.assertEqual("566", updated_credit_card.billing_address.country_code_numeric) self.assertEqual("Nigeria", updated_credit_card.billing_address.country_name) self.assertEqual(None, updated_credit_card.billing_address.street_address) self.assertNotEqual(initial_credit_card.billing_address.id, updated_credit_card.billing_address.id) def test_update_billing_address_when_update_existing_is_True(self): customer = Customer.create().customer initial_credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "123 Nigeria Ave", } }).credit_card updated_credit_card = CreditCard.update(initial_credit_card.token, { "billing_address": { "region": "IL", "options": { "update_existing": True } } }).credit_card self.assertEqual("IL", updated_credit_card.billing_address.region) self.assertEqual("123 Nigeria Ave", updated_credit_card.billing_address.street_address) self.assertEqual(initial_credit_card.billing_address.id, updated_credit_card.billing_address.id) def test_update_and_make_default(self): customer = Customer.create().customer card1 = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card card2 = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card self.assertTrue(card1.default) self.assertFalse(card2.default) CreditCard.update(card2.token, { "options": { "make_default": True } }) self.assertFalse(CreditCard.find(card1.token).default) self.assertTrue(CreditCard.find(card2.token).default) def test_update_verifies_card_if_option_is_provided(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card result = CreditCard.update(credit_card.token, { "number": "4000111111111115", "expiration_date": "06/2010", "cvv": "123", "cardholder_name": "Jane Jones", "options": {"verify_card": True} }) self.assertFalse(result.is_success) self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, result.credit_card_verification.status) def test_update_verifies_card_with_non_default_merchant_account(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card result = CreditCard.update(credit_card.token, { "number": "4000111111111115", "expiration_date": "06/2010", "cvv": "123", "cardholder_name": "Jane Jones", "options": { "verification_merchant_account_id": TestHelper.non_default_merchant_account_id, "verify_card": True } }) self.assertFalse(result.is_success) self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, result.credit_card_verification.status) def test_update_includes_risk_data_when_skip_advanced_fraud_checking_is_false(self): with FraudProtectionEnterpriseIntegrationMerchant(): 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, { "expiration_date": "06/2020", "options": { "verify_card": True, "skip_advanced_fraud_checking": False } }) self.assertTrue(result.is_success) verification = result.credit_card.verification self.assertIsInstance(verification.risk_data, RiskData) def test_update_does_not_include_risk_data_when_skip_advanced_fraud_checking_is_true(self): with FraudProtectionEnterpriseIntegrationMerchant(): 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, { "expiration_date": "06/2020", "options": { "verify_card": True, "skip_advanced_fraud_checking": True } }) self.assertTrue(result.is_success) verification = result.credit_card.verification self.assertIsNone(verification.risk_data) def test_update_billing_address(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "321 Xyz Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60621" } }).credit_card result = CreditCard.update(credit_card.token, { "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622" } }) self.assertTrue(result.is_success) address = result.credit_card.billing_address self.assertEqual("123 Abc Way", address.street_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60622", address.postal_code) def test_update_returns_error_if_invalid(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014" }).credit_card result = CreditCard.update(credit_card.token, { "expiration_date": "invalid_date" }) self.assertFalse(result.is_success) expiration_date_errors = result.errors.for_object("credit_card").on("expiration_date") self.assertEqual(1, len(expiration_date_errors)) self.assertEqual(ErrorCodes.CreditCard.ExpirationDateIsInvalid, expiration_date_errors[0].code) def test_update_returns_error_with_duplicate_payment_method_if_fail_on_duplicate_payment_method_is_set(self): create_result = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2021", } }) self.assertTrue(create_result.is_success) update_result = Customer.update(create_result.customer.id, { "credit_card": { "number": "4111111111111111", "expiration_date": "05/2021", "options": { "fail_on_duplicate_payment_method": True, }, } }) self.assertFalse(update_result.is_success) number_errors = update_result.errors.for_object("customer").for_object("credit_card").on("number") self.assertEqual(1, len(number_errors)) self.assertEqual(ErrorCodes.CreditCard.DuplicateCardExists, number_errors[0].code) def test_update_returns_error_with_duplicate_payment_method_for_customer_if_fail_on_duplicate_payment_method_is_set(self): create_result = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2021", } }) self.assertTrue(create_result.is_success) update_result = Customer.update(create_result.customer.id, { "credit_card": { "number": "4111111111111111", "expiration_date": "05/2021", "options": { "fail_on_duplicate_payment_method_for_customer": True, }, } }) self.assertFalse(update_result.is_success) number_errors = update_result.errors.for_object("customer").for_object("credit_card").on("number") self.assertEqual(1, len(number_errors)) self.assertEqual(ErrorCodes.CreditCard.DuplicateCardExistsForCustomer, number_errors[0].code) def test_delete_with_valid_token(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014" }).credit_card result = CreditCard.delete(credit_card.token) self.assertTrue(result.is_success) def test_delete_raises_error_when_deleting_twice(self): with self.assertRaises(NotFoundError): 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) def test_delete_with_invalid_token(self): with self.assertRaises(NotFoundError): CreditCard.delete("notreal") def test_find_with_valid_token(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014" }).credit_card found_credit_card = CreditCard.find(credit_card.token) self.assertTrue(re.search(r"\A\w{4,}\Z", found_credit_card.token) is not None) self.assertEqual("411111", found_credit_card.bin) self.assertEqual("1111", found_credit_card.last_4) self.assertEqual("05", found_credit_card.expiration_month) self.assertEqual("2014", found_credit_card.expiration_year) self.assertEqual("05/2014", found_credit_card.expiration_date) def test_find_returns_associated_subsriptions(self): customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014" }).credit_card subscription_id = "id_" + str(random.randint(1, 1000000)) subscription = Subscription.create({ "id": subscription_id, "plan_id": "integration_trialless_plan", "payment_method_token": credit_card.token, "price": Decimal("1.00") }).subscription found_credit_card = CreditCard.find(credit_card.token) subscriptions = found_credit_card.subscriptions self.assertEqual(1, len(subscriptions)) subscription = subscriptions[0] self.assertEqual(subscription_id, subscription.id) self.assertEqual(Decimal("1.00"), subscription.price) self.assertEqual(credit_card.token, subscription.payment_method_token) def test_find_with_invalid_token(self): with self.assertRaisesRegex(NotFoundError, "payment method with token 'bad_token' not found"): CreditCard.find("bad_token") def test_from_nonce_with_unlocked_nonce(self): config = Configuration.instantiate() customer = Customer.create().customer client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer.id, }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) nonce = json.loads(response)["creditCards"][0]["nonce"] card = CreditCard.from_nonce(nonce) customer = Customer.find(customer.id) self.assertEqual(1, len(customer.credit_cards)) self.assertEqual(customer.credit_cards[0].token, card.token) def test_from_nonce_with_unlocked_nonce_pointing_to_shared_card(self): with self.assertRaisesRegex(NotFoundError, "payment method with nonce .* or not found"): config = Configuration.instantiate() client_token = TestHelper.generate_decoded_client_token() authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) self.assertEqual(201, status_code) nonce = json.loads(response)["creditCards"][0]["nonce"] CreditCard.from_nonce(nonce) def test_from_nonce_with_consumed_nonce(self): with self.assertRaisesRegex(NotFoundError, ".* consumed .*"): config = Configuration.instantiate() customer = Customer.create().customer client_token = TestHelper.generate_decoded_client_token({ "customer_id": customer.id, }) authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", } }) self.assertEqual(201, status_code) nonce = json.loads(response)["creditCards"][0]["nonce"] CreditCard.from_nonce(nonce) CreditCard.from_nonce(nonce) def test_expired_can_iterate_over_all_items(self): year = datetime.now().year - 3 customer_id = Customer.all().first.id for _ in range(110 - CreditCard.expired().maximum_size): CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "01/" + str(year) }) collection = CreditCard.expired() self.assertTrue(collection.maximum_size > 100) credit_card_tokens = [credit_card.token for credit_card in collection.items] self.assertEqual(collection.maximum_size, len(TestHelper.unique(credit_card_tokens))) self.assertEqual(set([True]), TestHelper.unique([credit_card.is_expired for credit_card in collection.items])) def test_expiring_between(self): customer_id = Customer.all().first.id for _ in range(110 - CreditCard.expiring_between(date(2010, 1, 1), date(2010, 12, 31)).maximum_size): CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100", "cardholder_name": "John Doe" }) collection = CreditCard.expiring_between(date(2010, 1, 1), date(2010, 12, 31)) self.assertTrue(collection.maximum_size > 100) credit_card_tokens = [credit_card.token for credit_card in collection.items] self.assertEqual(collection.maximum_size, len(TestHelper.unique(credit_card_tokens))) self.assertEqual(set(['2010']), TestHelper.unique([credit_card.expiration_year for credit_card in collection.items])) def test_commercial_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Commercial, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Commercial.Yes, credit_card.commercial) def test_issuing_bank(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.IssuingBank, "expiration_date": "05/2014" }) credit_card = result.credit_card self.assertEqual(CreditCardDefaults.IssuingBank, credit_card.issuing_bank) def test_country_of_issuance(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.CountryOfIssuance, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCardDefaults.CountryOfIssuance, credit_card.country_of_issuance) def test_durbin_regulated_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.DurbinRegulated, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.DurbinRegulated.Yes, credit_card.durbin_regulated) def test_debit_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Debit, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Debit.Yes, credit_card.debit) def test_healthcare_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Healthcare, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Healthcare.Yes, credit_card.healthcare) self.assertEqual("J3", credit_card.product_id) def test_payroll_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Payroll, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Payroll.Yes, credit_card.payroll) self.assertEqual("MSA", credit_card.product_id) def test_prepaid_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Prepaid, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Prepaid.Yes, credit_card.prepaid) def test_all_negative_card_type_indicators(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.No, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Debit.No, credit_card.debit) self.assertEqual(CreditCard.DurbinRegulated.No, credit_card.durbin_regulated) self.assertEqual(CreditCard.Prepaid.No, credit_card.prepaid) self.assertEqual(CreditCard.Payroll.No, credit_card.payroll) self.assertEqual(CreditCard.Commercial.No, credit_card.commercial) self.assertEqual(CreditCard.Healthcare.No, credit_card.healthcare) self.assertEqual("MSB", credit_card.product_id) def test_card_without_card_type_indicators(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.CardTypeIndicators.Unknown, "expiration_date": "05/2014", "options": {"verify_card": True} }) credit_card = result.credit_card self.assertEqual(CreditCard.Debit.Unknown, credit_card.debit) self.assertEqual(CreditCard.DurbinRegulated.Unknown, credit_card.durbin_regulated) self.assertEqual(CreditCard.Prepaid.Unknown, credit_card.prepaid) self.assertEqual(CreditCard.Payroll.Unknown, credit_card.payroll) self.assertEqual(CreditCard.Commercial.Unknown, credit_card.commercial) self.assertEqual(CreditCard.Healthcare.Unknown, credit_card.healthcare) self.assertEqual(CreditCard.IssuingBank.Unknown, credit_card.issuing_bank) self.assertEqual(CreditCard.CountryOfIssuance.Unknown, credit_card.country_of_issuance) self.assertEqual(CreditCard.ProductId.Unknown, credit_card.product_id) def test_card_with_account_type_debit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2014", "options": { "verify_card": True, "verification_merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "verification_account_type": "debit" } }) self.assertEqual(result.is_success, True) self.assertEqual("debit", result.credit_card.verifications[0]["credit_card"]["account_type"]) updated_result = CreditCard.update(result.credit_card.token, { "options": { "verify_card": True, "verification_merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "verification_account_type": "debit" } }) self.assertEqual(updated_result.is_success, True) self.assertEqual("debit", updated_result.credit_card.verifications[1]["credit_card"]["account_type"]) def test_card_with_account_type_credit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2014", "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "credit" } }) self.assertEqual(result.is_success, True) self.assertEqual("credit", result.credit_card.verifications[0]["credit_card"]["account_type"]) updated_result = CreditCard.update(result.credit_card.token, { "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "credit" } }) self.assertEqual(updated_result.is_success, True) self.assertEqual("credit", updated_result.credit_card.verifications[0]["credit_card"]["account_type"]) def test_card_with_account_type_credit_debit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2014", "options": { "verify_card": True, "verification_merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "verification_account_type": "credit" } }) self.assertEqual(result.is_success, True) self.assertEqual("credit", result.credit_card.verifications[0]["credit_card"]["account_type"]) updated_result = CreditCard.update(result.credit_card.token, { "options": { "verify_card": True, "verification_merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "verification_account_type": "debit" } }) self.assertEqual(updated_result.is_success, True) self.assertEqual("debit", updated_result.credit_card.verifications[0]["credit_card"]["account_type"]) self.assertEqual("credit", updated_result.credit_card.verifications[1]["credit_card"]["account_type"]) def test_network_tokenized_credit_card(self): credit_card = CreditCard.find("network_tokenized_credit_card") self.assertEqual(credit_card.is_network_tokenized, True) def test_non_network_tokenized_credit_card(self): customer = Customer.create().customer card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe" }).credit_card credit_card = CreditCard.find(card.token) self.assertEqual(credit_card.is_network_tokenized, False) braintree_python-4.31.0/tests/integration/test_credit_card_verification.py000066400000000000000000000312531471021343500272620ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestCreditCardVerfication(unittest.TestCase): def test_create_success(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2012" }}) self.assertTrue(result.is_success) verification = result.verification self.assertEqual("1000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, verification.processor_response_type) def test_create_failure(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.FailsSandboxVerification.MasterCard, "expiration_date": "05/2012" }}) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual("2000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.SoftDeclined, verification.processor_response_type) def test_create_returns_validation_errors(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.FailsSandboxVerification.MasterCard, "expiration_date": "05/2012" }, "options": {"amount": "-10.00"} }) self.assertFalse(result.is_success) amount_errors = result.errors.for_object("verification").for_object("options").on("amount") self.assertEqual(1, len(amount_errors)) self.assertEqual(ErrorCodes.Verification.Options.AmountCannotBeNegative, amount_errors[0].code) def test_create_with_account_type_debit(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "account_type": "debit", }, }) self.assertTrue(result.is_success) self.assertEqual("debit", result.verification.credit_card["account_type"]) def test_create_with_account_type_credit(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "account_type": "credit", }, }) self.assertTrue(result.is_success) self.assertEqual("credit", result.verification.credit_card["account_type"]) def test_create_with_unsupported_account_type(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2012" }, "options": { "account_type": "debit", }, }) self.assertFalse(result.is_success) account_type_errors = result.errors.for_object("verification").for_object("options").on("account_type") self.assertEqual(1, len(account_type_errors)) self.assertEqual(ErrorCodes.Verification.Options.AccountTypeNotSupported , account_type_errors[0].code) def test_create_with_invalid_account_type(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "account_type": "invalid", }, }) self.assertFalse(result.is_success) account_type_errors = result.errors.for_object("verification").for_object("options").on("account_type") self.assertEqual(1, len(account_type_errors)) self.assertEqual(ErrorCodes.Verification.Options.AccountTypeIsInvalid, account_type_errors[0].code) def test_create_with_external_vault(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2012" }, "external_vault": { "status": "will_vault" } }) self.assertTrue(result.is_success) verification = result.verification self.assertEqual("1000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, verification.processor_response_type) def test_create_with_risk_data(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2012" }, "risk_data": { "customer_browser": "IE7", "customer_ip": "192.168.0.1" } }) self.assertTrue(result.is_success) verification = result.verification self.assertEqual("1000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, verification.processor_response_type) def test_find_with_verification_id(self): customer = Customer.create({ "credit_card": { "number": CreditCardNumbers.FailsSandboxVerification.MasterCard, "expiration_date": "05/2012", "cardholder_name": "Tom Smith", "options": {"verify_card": True} }}) created_verification = customer.credit_card_verification found_verification = CreditCardVerification.find(created_verification.id) self.assertEqual(created_verification, found_verification) self.assertNotEqual(None, found_verification.graphql_id) def test_verification_not_found(self): self.assertRaises(NotFoundError, CreditCardVerification.find, "invalid-id") def test_card_type_indicators(self): cardholder_name = "Tom %s" % random.randint(1, 10000) Customer.create({"credit_card": { "cardholder_name": cardholder_name, "expiration_date": "10/2012", "number": CreditCardNumbers.CardTypeIndicators.Unknown, "options": {"verify_card": True} }}) found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.credit_card_cardholder_name == cardholder_name ) self.assertEqual(CreditCard.Prepaid.Unknown, found_verifications.first.credit_card['prepaid']) self.assertEqual(CreditCard.Debit.Unknown, found_verifications.first.credit_card['debit']) self.assertEqual(CreditCard.Commercial.Unknown, found_verifications.first.credit_card['commercial']) self.assertEqual(CreditCard.Healthcare.Unknown, found_verifications.first.credit_card['healthcare']) self.assertEqual(CreditCard.Payroll.Unknown, found_verifications.first.credit_card['payroll']) self.assertEqual(CreditCard.DurbinRegulated.Unknown, found_verifications.first.credit_card['durbin_regulated']) self.assertEqual(CreditCard.IssuingBank.Unknown, found_verifications.first.credit_card['issuing_bank']) self.assertEqual(CreditCard.CountryOfIssuance.Unknown, found_verifications.first.credit_card['country_of_issuance']) self.assertEqual(CreditCard.ProductId.Unknown, found_verifications.first.credit_card['product_id']) def test_create_success_network_response_code_text(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2012" }, }) self.assertTrue(result.is_success) verification = result.verification self.assertEqual("1000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, verification.processor_response_type) self.assertEqual("XX", verification.network_response_code) self.assertEqual("sample network response text", verification.network_response_text) def test_create_success_network_transaction_id(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2012" }, }) self.assertTrue(result.is_success) verification = result.verification self.assertRegex(verification.network_transaction_id, r'\d{15}') def test_verification_with_three_d_secure_authentication_id_with_nonce(self): config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key" ) gateway = BraintreeGateway(config) credit_card = { "credit_card": { "number": CreditCardNumbers.Visa, "expiration_month": "05", "expiration_year": "2029", } } nonce = TestHelper.generate_three_d_secure_nonce(gateway, credit_card) found_nonce = PaymentMethodNonce.find(nonce) three_d_secure_info = found_nonce.three_d_secure_info result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", }, "options": {"merchant_account_id": TestHelper.three_d_secure_merchant_account_id}, "payment_method_nonce": nonce, "three_d_secure_authentication_id": three_d_secure_info.three_d_secure_authentication_id }) self.assertTrue(result.is_success) verification = result.verification self.assertEqual("1000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, verification.processor_response_type) def test_verification_with_three_d_secure_pass_thru(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2029"}, "options": {"merchant_account_id": TestHelper.three_d_secure_merchant_account_id}, "three_d_secure_pass_thru": { "eci_flag": "02", "cavv": "some_cavv", "xid": "some_xid", "three_d_secure_version": "1.0.2", "authentication_response": "Y", "directory_response": "Y", "cavv_algorithm": "2", "ds_transaction_id": "some_ds_id"}}) self.assertTrue(result.is_success) verification = result.verification self.assertEqual("1000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, verification.processor_response_type) def test_verification_with_intended_transaction_source(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "cardholder_name": "John Smith", "expiration_date": "05/2029"}, "intended_transaction_source": "installment" }) self.assertTrue(result.is_success) verification = result.verification self.assertEqual("1000", verification.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, verification.processor_response_type) def test_verification_with_ani_response_codes(self): result = CreditCardVerification.create({ "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2029", } }) self.assertTrue(result.is_success) verification = result.verification self.assertEqual("1000", verification.processor_response_code) self.assertEqual("I", verification.ani_first_name_response_code) self.assertEqual("I", verification.ani_last_name_response_code) braintree_python-4.31.0/tests/integration/test_credit_card_verification_search.py000066400000000000000000000147401471021343500306110ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestVerificationSearch(unittest.TestCase): def test_advanced_search_no_results(self): collection = CreditCardVerification.search([ CreditCardVerificationSearch.credit_card_cardholder_name == "no such person"]) self.assertEqual(0, collection.maximum_size) def test_search_on_verification_id(self): customer_id = "%s" % random.randint(1, 10000) result = Customer.create({ "id": customer_id, "credit_card": { "expiration_date": "10/2018", "number": CreditCardNumbers.FailsSandboxVerification.Visa, "options": { "verify_card": True } } }) verification_id = result.credit_card_verification.id found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.id == verification_id ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(verification_id, found_verifications.first.id) def test_search_on_payment_method_token(self): customer_id = "%s" % random.randint(1, 10000) payment_method_token = customer_id + "token" result = Customer.create({ "id": customer_id, "credit_card": { "token": payment_method_token, "expiration_date": "10/2018", "number": CreditCardNumbers.Visa, "options": { "verify_card": True } } }) found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.payment_method_token == payment_method_token ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(payment_method_token, found_verifications.first.credit_card["token"]) def test_all_text_fields(self): email = "mark.a@example.com" cardholder_name = "Tom %s" % random.randint(1, 10000) customer_id = "%s" % random.randint(1, 10000) expiration_date = "10/2012" number = CreditCardNumbers.MasterCard postal_code = "44444" customer = Customer.create({ "id": customer_id, "email": email, "credit_card": { "cardholder_name": cardholder_name, "expiration_date": expiration_date, "number": number, "billing_address": { "postal_code": postal_code }, "options": { "verify_card": True } } }).customer found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.credit_card_expiration_date == expiration_date, CreditCardVerificationSearch.credit_card_cardholder_name == cardholder_name, CreditCardVerificationSearch.credit_card_number == number, CreditCardVerificationSearch.customer_email == email, CreditCardVerificationSearch.customer_id == customer_id, CreditCardVerificationSearch.billing_postal_code == postal_code ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(customer.credit_cards[0].token, found_verifications.first.credit_card["token"]) def test_multiple_value_fields(self): cardholder_name = "Tom %s" % random.randint(1, 10000) number = CreditCardNumbers.FailsSandboxVerification.MasterCard unsuccessful_result1 = Customer.create({"credit_card": { "cardholder_name": cardholder_name, "expiration_date": "10/2013", "number": number, "options": {"verify_card": True} }}) cardholder_name = "Tom %s" % random.randint(1, 10000) number = CreditCardNumbers.FailsSandboxVerification.Visa unsuccessful_result2 = Customer.create({"credit_card": { "cardholder_name": cardholder_name, "expiration_date": "10/2012", "number": number, "options": {"verify_card": True} }}) verification1 = unsuccessful_result1.credit_card_verification verification2 = unsuccessful_result2.credit_card_verification search_results = CreditCardVerification.search( CreditCardVerificationSearch.ids.in_list([ verification1.id, verification2.id]), CreditCardVerificationSearch.credit_card_card_type.in_list([ verification1.credit_card["card_type"], verification2.credit_card["card_type"]]), CreditCardVerificationSearch.status.in_list([ verification1.status, verification2.status]) ) self.assertEqual(2, search_results.maximum_size) def test_range_field(self): cardholder_name = "Tom %s" % random.randint(1, 10000) number = CreditCardNumbers.FailsSandboxVerification.MasterCard unsuccessful_result = Customer.create({"credit_card": { "cardholder_name": cardholder_name, "expiration_date": "10/2013", "number": number, "options": {"verify_card": True} }}) created_verification = unsuccessful_result.credit_card_verification created_time = created_verification.created_at before_creation = created_time - timedelta(minutes=10) after_creation = created_time + timedelta(minutes=10) found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.id == created_verification.id, CreditCardVerificationSearch.created_at.between(before_creation, after_creation)) self.assertEqual(1, found_verifications.maximum_size) way_before_creation = created_time - timedelta(minutes=10) just_before_creation = created_time - timedelta(minutes=1) found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.id == created_verification.id, CreditCardVerificationSearch.created_at.between(way_before_creation, just_before_creation)) self.assertEqual(0, found_verifications.maximum_size) found_verifications = CreditCardVerification.search( CreditCardVerificationSearch.id == created_verification.id, CreditCardVerificationSearch.created_at == created_time) self.assertEqual(1, found_verifications.maximum_size) braintree_python-4.31.0/tests/integration/test_customer.py000066400000000000000000002050271471021343500241200ustar00rootroot00000000000000# -*- coding: latin-1 -*- from tests.test_helper import * from braintree.test.nonces import Nonces class TestCustomer(unittest.TestCase): def test_all(self): collection = Customer.all() self.assertTrue(collection.maximum_size > 100) customer_ids = [c.id for c in collection.items] self.assertEqual(collection.maximum_size, len(TestHelper.unique(customer_ids))) self.assertEqual(Customer, type(collection.first)) def test_create(self): result = Customer.create({ "first_name": "Joe", "last_name": "Brown", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.1234", "international_phone": {"country_code": "1", "national_number": "3121234567"}, "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("1", customer.international_phone["country_code"]) self.assertEqual("3121234567", customer.international_phone["national_number"]) self.assertEqual("614.555.5678", customer.fax) self.assertEqual("www.email.com", customer.website) self.assertNotEqual(None, customer.id) self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", customer.id)) def test_create_unicode(self): result = Customer.create({ "first_name": "Kimi", "last_name": u"Räikkönen", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.1234", "fax": "614.555.5678", "website": "www.email.com" }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("Kimi", customer.first_name) self.assertEqual(u"Räikkönen", customer.last_name) self.assertEqual("Fake Company", customer.company) self.assertEqual("joe@email.com", customer.email) self.assertEqual("312.555.1234", customer.phone) self.assertEqual("614.555.5678", customer.fax) self.assertEqual("www.email.com", customer.website) self.assertNotEqual(None, customer.id) def test_create_with_tax_identifiers(self): result = Customer.create({ "tax_identifiers": [ {"country_code": "US", "identifier": "123456789"}, {"country_code": "GB", "identifier": "987654321"}] }) self.assertTrue(result.is_success) def test_create_with_device_data(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", "device_data": "abc123", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }) self.assertTrue(result.is_success) def test_create_with_device_session_id_and_fraud_merchant_id_sends_deprecation_warning(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") 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", "device_session_id": "abc123", "fraud_merchant_id": "456", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }) self.assertTrue(result.is_success) assert len(w) > 0 assert issubclass(w[-1].category, DeprecationWarning) def test_create_with_risk_data_security_parameters(self): result = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "options": { "verify_card": True, } }, "risk_data": { "customer_browser": "IE7", "customer_ip": "192.168.0.1" } }) self.assertTrue(result.is_success) def test_create_includes_risk_data_when_skip_advanced_fraud_checking_is_false(self): with FraudProtectionEnterpriseIntegrationMerchant(): result = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2014", "options": { "verify_card": True, "skip_advanced_fraud_checking": False }, }, }) self.assertTrue(result.is_success) verification = result.customer.credit_cards[0].verification self.assertIsInstance(verification.risk_data, RiskData) def test_create_does_not_include_risk_data_when_skip_advanced_fraud_checking_is_true(self): with FraudProtectionEnterpriseIntegrationMerchant(): result = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2014", "options": { "verify_card": True, "skip_advanced_fraud_checking": True }, }, }) self.assertTrue(result.is_success) verification = result.customer.credit_cards[0].verification self.assertIsNone(verification.risk_data) def test_create_and_update_with_verification_account_type(self): result_with_account_type_credit = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "05/2010", "options": { "verify_card": True, "verification_merchant_account_id": "hiper_brl", "verification_account_type": "credit", } }, }) update_with_account_type_credit = Customer.update(result_with_account_type_credit.customer.id, { "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "05/2010", "options": { "verification_account_type": "credit", } }, }) result_with_account_type_debit = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "05/2010", "options": { "verify_card": True, "verification_merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "verification_account_type": "debit", } }, }) update_with_account_type_debit = Customer.update(result_with_account_type_debit.customer.id, { "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "05/2010", "options": { "verification_account_type": "debit", } }, }) self.assertTrue(result_with_account_type_credit.is_success) self.assertTrue(result_with_account_type_debit.is_success) self.assertTrue(update_with_account_type_credit.is_success) self.assertTrue(update_with_account_type_debit.is_success) def test_create_using_access_token(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret", environment=Environment.Development ) code = TestHelper.create_grant(gateway, { "merchant_public_id": "integration_merchant_id", "scope": "read_write" }) result = gateway.oauth.create_token_from_code({ "code": code }) gateway = BraintreeGateway( access_token=result.credentials.access_token, environment=Environment.Development ) result = gateway.customer.create({ "first_name": "Joe", "last_name": "Brown" }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("Joe", customer.first_name) def test_create_with_unicode(self): result = Customer.create({ "first_name": u"Joe<&>", "last_name": u"G\u1F00t\u1F18s", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.1234", "fax": "614.555.5678", "website": "www.email.com" }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(u"Joe<&>", customer.first_name) self.assertEqual(u"G\u1f00t\u1F18s", customer.last_name) self.assertEqual("Fake Company", customer.company) self.assertEqual("joe@email.com", customer.email) self.assertEqual("312.555.1234", customer.phone) self.assertEqual("614.555.5678", customer.fax) self.assertEqual("www.email.com", customer.website) self.assertNotEqual(None, customer.id) self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", customer.id)) found_customer = Customer.find(customer.id) self.assertEqual(u"G\u1f00t\u1F18s", found_customer.last_name) def test_create_with_apple_pay_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.ApplePayVisa}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.apple_pay_cards)) self.assertIsInstance(customer.apple_pay_cards[0], ApplePayCard) self.assertNotEqual(customer.apple_pay_cards[0].bin, None) self.assertNotEqual(customer.apple_pay_cards[0].token, None) self.assertNotEqual(customer.apple_pay_cards[0].prepaid, None) self.assertNotEqual(customer.apple_pay_cards[0].healthcare, None) self.assertNotEqual(customer.apple_pay_cards[0].debit, None) self.assertNotEqual(customer.apple_pay_cards[0].durbin_regulated, None) self.assertNotEqual(customer.apple_pay_cards[0].commercial, None) self.assertNotEqual(customer.apple_pay_cards[0].payroll, None) self.assertNotEqual(customer.apple_pay_cards[0].issuing_bank, None) self.assertNotEqual(customer.apple_pay_cards[0].country_of_issuance, None) self.assertNotEqual(customer.apple_pay_cards[0].product_id, None) self.assertNotEqual(customer.apple_pay_cards[0].last_4, None) self.assertNotEqual(customer.apple_pay_cards[0].card_type, None) def test_create_with_three_d_secure_nonce(self): result = Customer.create({ "payment_method_nonce": Nonces.ThreeDSecureVisaFullAuthentication, "credit_card": { "options": { "verify_card": True, }, }, }) self.assertTrue(result.is_success) three_d_secure_info = result.customer.payment_methods[0].verification.three_d_secure_info self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertIsInstance(three_d_secure_info.enrolled, str) self.assertIsInstance(three_d_secure_info.cavv, str) self.assertIsInstance(three_d_secure_info.xid, str) self.assertIsInstance(three_d_secure_info.eci_flag, str) self.assertIsInstance(three_d_secure_info.three_d_secure_version, str) def test_create_with_three_d_secure_pass_thru(self): result = Customer.create({ "payment_method_nonce": Nonces.Transactable, "credit_card": { "three_d_secure_pass_thru": { "three_d_secure_version": "1.1.1", "eci_flag": "05", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": True, }, }, }) self.assertTrue(result.is_success) def test_create_with_three_d_secure_pass_thru_without_eci_flag(self): result = Customer.create({ "payment_method_nonce": Nonces.Transactable, "credit_card": { "three_d_secure_pass_thru": { "three_d_secure_version": "1.1.1", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": True, }, }, }) self.assertFalse(result.is_success) self.assertEqual("EciFlag is required.", result.message) def test_create_with_android_pay_proxy_card_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.AndroidPayCardDiscover}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.android_pay_cards)) self.assertIsInstance(customer.android_pay_cards[0], AndroidPayCard) def test_create_with_android_pay_network_token_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.AndroidPayCardMasterCard}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.android_pay_cards)) self.assertIsInstance(customer.android_pay_cards[0], AndroidPayCard) self.assertNotEqual(customer.android_pay_cards[0].bin, None) self.assertNotEqual(customer.android_pay_cards[0].token, None) self.assertNotEqual(customer.android_pay_cards[0].prepaid, None) self.assertNotEqual(customer.android_pay_cards[0].healthcare, None) self.assertNotEqual(customer.android_pay_cards[0].debit, None) self.assertNotEqual(customer.android_pay_cards[0].durbin_regulated, None) self.assertNotEqual(customer.android_pay_cards[0].commercial, None) self.assertNotEqual(customer.android_pay_cards[0].payroll, None) self.assertNotEqual(customer.android_pay_cards[0].issuing_bank, None) self.assertNotEqual(customer.android_pay_cards[0].country_of_issuance, None) self.assertNotEqual(customer.android_pay_cards[0].product_id, None) self.assertNotEqual(customer.android_pay_cards[0].last_4, None) self.assertNotEqual(customer.android_pay_cards[0].card_type, None) def test_create_with_amex_express_checkout_card_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.AmexExpressCheckoutCard}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.amex_express_checkout_cards)) self.assertIsInstance(customer.amex_express_checkout_cards[0], AmexExpressCheckoutCard) def test_create_with_venmo_account_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.VenmoAccount}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.venmo_accounts)) self.assertIsInstance(customer.venmo_accounts[0], VenmoAccount) def test_create_with_us_bank_account_nonce(self): result = Customer.create({ "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "credit_card": { "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } } }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.us_bank_accounts)) self.assertIsInstance(customer.us_bank_accounts[0], UsBankAccount) def test_create_with_paypal_billing_agreements_nonce(self): result = Customer.create({"payment_method_nonce": Nonces.PayPalBillingAgreement}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.paypal_accounts)) self.assertIsInstance(customer.paypal_accounts[0], PayPalAccount) def test_create_with_paypal_order_payment_nonce(self): http = ClientApiHttp.create() status_code, payment_method_nonce = http.get_paypal_nonce({ "intent": "order", "payment-token": "fake-paypal-payment-token", "payer-id": "fake-paypal-payer-id" }) result = Customer.create({"payment_method_nonce": payment_method_nonce}) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.paypal_accounts)) self.assertIsInstance(customer.paypal_accounts[0], PayPalAccount) def test_create_with_paypal_order_payment_nonce_and_paypal_options(self): http = ClientApiHttp.create() status_code, payment_method_nonce = http.get_paypal_nonce({ "intent": "order", "payment-token": "fake-paypal-payment-token", "payer-id": "fake-paypal-payer-id" }) result = Customer.create({ "payment_method_nonce": payment_method_nonce, "options": { "paypal": { "payee_email": "payee@example.com", "order_id": "merchant-order-id", "custom_field": "custom merchant field", "description": "merchant description", "amount": "1.23", "shipping": { "first_name": "Andrew", "last_name": "Mason", "company": "Braintree", "street_address": "456 W Main St", "extended_address": "Apt 2F", "locality": "Bartlett", "region": "IL", "postal_code": "60103", "country_name": "Mexico", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484" }, }, }, }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual(1, len(customer.paypal_accounts)) self.assertIsInstance(customer.paypal_accounts[0], PayPalAccount) def test_create_with_paypal_one_time_nonce_fails(self): result = Customer.create({"payment_method_nonce": Nonces.PayPalOneTimePayment}) self.assertFalse(result.is_success) paypal_account_errors = result.errors.for_object("customer").for_object("paypal_account").on("base") self.assertEqual(1, len(paypal_account_errors)) self.assertEqual(ErrorCodes.PayPalAccount.CannotVaultOneTimeUsePayPalAccount, paypal_account_errors[0].code) def test_create_with_no_attributes(self): result = Customer.create() self.assertTrue(result.is_success) self.assertNotEqual(None, result.customer.id) def test_create_with_special_chars(self): result = Customer.create({"first_name": "XML Chars <>&'\""}) self.assertTrue(result.is_success) self.assertEqual("XML Chars <>&'\"", result.customer.first_name) def test_create_returns_an_error_response_if_invalid(self): result = Customer.create({ "email": "@invalid.com", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "billing_address": { "country_code_alpha2": "MX", "country_code_alpha3": "USA" } } }) self.assertFalse(result.is_success) customer_email_errors = result.errors.for_object("customer").on("email") self.assertEqual(1, len(customer_email_errors)) self.assertEqual(ErrorCodes.Customer.EmailIsInvalid, customer_email_errors[0].code) billing_address_errors = result.errors.for_object("customer").for_object("credit_card").for_object("billing_address").on("base") self.assertEqual(1, len(billing_address_errors)) self.assertEqual(ErrorCodes.Address.InconsistentCountry, billing_address_errors[0].code) def test_create_customer_and_payment_method_at_the_same_time(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("Mike", customer.first_name) self.assertEqual("Jones", customer.last_name) credit_card = customer.credit_cards[0] self.assertEqual("411111", credit_card.bin) self.assertEqual("1111", credit_card.last_4) self.assertEqual("05/2010", credit_card.expiration_date) def test_create_for_raw_apple_pay(self): result = Customer.create({ "first_name": "Rickey", "last_name": "Crabapple", "apple_pay_card": { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "eci_indicator": "5", "cryptogram": "01010101010101010101", "cardholder_name": "John Doe", "billing_address": { "postal_code": 83704 } } }) customer = result.customer self.assertEqual("Rickey", customer.first_name) self.assertEqual("Crabapple", customer.last_name) self.assertTrue(result.is_success) apple_pay_card = result.customer.apple_pay_cards[0] self.assertEqual("411111", apple_pay_card.bin) self.assertEqual("1111", apple_pay_card.last_4) self.assertEqual("2014", apple_pay_card.expiration_year) self.assertEqual("05", apple_pay_card.expiration_month) self.assertEqual(apple_pay_card.billing_address["postal_code"], "83704") def test_create_for_raw_apple_pay_with_invalid_params(self): result = Customer.create({ "first_name": "Rickey", "last_name": "Crabapple", "apple_pay_card": { "number": "4111111111111111", "expiration_year": "2014", "expiration_month": "01", "eci_indicator": "5", "cryptogram": "01010101010101010101", "cardholder_name": "John Doe", "billing_address": { "street_address": "head 100 yds south once you hear the beehive", "postal_code": '$$$$', "country_code_alpha2": "UX", } } }) # errors = result.errors.for_object("apple_pay").on("billing_address") self.assertFalse(result.is_success) postal_errors = result.errors.for_object("apple_pay").for_object("billing_address").on("postal_code") country_errors = result.errors.for_object("apple_pay").for_object("billing_address").on("country_code_alpha2") self.assertEqual(1, len(postal_errors)) self.assertEqual(1, len(country_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, country_errors[0].code) self.assertEqual(ErrorCodes.Address.PostalCodeInvalidCharacters, postal_errors[0].code) def test_create_for_raw_android_pay_card(self): result = Customer.create({ "first_name": "Rickey", "last_name": "Crabapple", "android_pay_card": { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "google_transaction_id": "dontbeevil", "billing_address": { "postal_code": 83704 } } }) customer = result.customer self.assertEqual("Rickey", customer.first_name) self.assertEqual("Crabapple", customer.last_name) self.assertTrue(result.is_success) android_pay_card = result.customer.android_pay_cards[0] self.assertEqual("411111", android_pay_card.bin) self.assertEqual("1111", android_pay_card.last_4) self.assertEqual("2014", android_pay_card.expiration_year) self.assertEqual("05", android_pay_card.expiration_month) self.assertEqual("dontbeevil", android_pay_card.google_transaction_id) self.assertEqual(android_pay_card.billing_address["postal_code"], "83704") def test_create_for_raw_android_pay_card_with_invalid_params(self): result = Customer.create({ "first_name": "Rickey", "last_name": "Crabapple", "android_pay_card": { "number": "4111111111111111", "expiration_year": "2014", "expiration_month": "01", "google_transaction_id": "dontbeevil", "billing_address": { "street_address": "head 100 yds south once you hear the beehive", "postal_code": '$$$$', "country_code_alpha2": "UX", } } }) errors = result.errors.for_object("android_pay_card").on("billing_address") self.assertFalse(result.is_success) postal_errors = result.errors.for_object("android_pay_card").for_object("billing_address").on("postal_code") country_errors = result.errors.for_object("android_pay_card").for_object("billing_address").on("country_code_alpha2") self.assertEqual(1, len(postal_errors)) self.assertEqual(1, len(country_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, country_errors[0].code) self.assertEqual(ErrorCodes.Address.PostalCodeInvalidCharacters, postal_errors[0].code) def test_create_for_raw_android_pay_network_token(self): result = Customer.create({ "first_name": "Rickey", "last_name": "Crabapple", "android_pay_network_token": { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cryptogram": "01010101010101010101", "eci_indicator": "5", "google_transaction_id": "dontbeevil", "billing_address": { "postal_code": 83704 } } }) customer = result.customer self.assertEqual("Rickey", customer.first_name) self.assertEqual("Crabapple", customer.last_name) self.assertTrue(result.is_success) android_pay_network_token = result.customer.android_pay_cards[0] self.assertEqual("411111", android_pay_network_token.bin) self.assertEqual("1111", android_pay_network_token.last_4) self.assertEqual("2014", android_pay_network_token.expiration_year) self.assertEqual("05", android_pay_network_token.expiration_month) self.assertEqual("dontbeevil", android_pay_network_token.google_transaction_id) self.assertEqual(android_pay_network_token.billing_address["postal_code"], "83704") def test_create_for_raw_android_pay_network_token_with_invalid_params(self): result = Customer.create({ "first_name": "Rickey", "last_name": "Crabapple", "android_pay_network_token": { "number": "4111111111111111", "expiration_year": "2014", "expiration_month": "01", "google_transaction_id": "dontbeevil", "cryptogram": "01010101010101010101", "cardholder_name": "John Doe", "billing_address": { "street_address": "head 100 yds south once you hear the beehive", "postal_code": '$$$$', "country_code_alpha2": "UX", } } }) errors = result.errors.for_object("android_pay_network_token").on("billing_address") self.assertFalse(result.is_success) postal_errors = result.errors.for_object("android_pay_network_token").for_object("billing_address").on("postal_code") country_errors = result.errors.for_object("android_pay_network_token").for_object("billing_address").on("country_code_alpha2") self.assertEqual(1, len(postal_errors)) self.assertEqual(1, len(country_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, country_errors[0].code) self.assertEqual(ErrorCodes.Address.PostalCodeInvalidCharacters, postal_errors[0].code) def test_create_customer_and_verify_payment_method(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4000111111111115", "expiration_date": "05/2010", "cvv": "100", "options": {"verify_card": True} } }) self.assertFalse(result.is_success) self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, result.credit_card_verification.status) def test_create_customer_and_verify_payment_method_with_verification_amount(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100", "options": {"verify_card": True, "verification_amount": "6.00"} } }) self.assertTrue(result.is_success) def test_create_customer_with_check_duplicate_payment_method(self): attributes = { "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4000111111111115", "expiration_date": "05/2010", "cvv": "100", "options": {"fail_on_duplicate_payment_method": True} } } Customer.create(attributes) result = Customer.create(attributes) self.assertFalse(result.is_success) self.assertEqual("Duplicate card exists in the vault.", result.message) card_number_errors = result.errors.for_object("customer").for_object("credit_card").on("number") self.assertEqual(1, len(card_number_errors)) self.assertEqual(ErrorCodes.CreditCard.DuplicateCardExists, card_number_errors[0].code) def test_create_customer_with_check_duplicate_payment_method_for_customer(self): attributes = { "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4000111111111115", "expiration_date": "05/2010", "cvv": "100", } } customer = Customer.create(attributes).customer result = Customer.update(customer.id, { "credit_card": { "expiration_date": "12/12", "number": "4000111111111115", "options": {"fail_on_duplicate_payment_method_for_customer": True} } }) self.assertFalse(result.is_success) self.assertEqual("Duplicate card exists in the vault for the customer.", result.message) card_number_errors = result.errors.for_object("customer").for_object("credit_card").on("number") self.assertEqual(1, len(card_number_errors)) self.assertEqual(ErrorCodes.CreditCard.DuplicateCardExistsForCustomer, card_number_errors[0].code) def test_create_customer_with_payment_method_and_billing_address(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100", "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_code_alpha2": "US", "country_code_alpha3": "USA", "country_code_numeric": "840", "country_name": "United States of America" } } }) self.assertTrue(result.is_success) customer = result.customer self.assertEqual("Mike", customer.first_name) self.assertEqual("Jones", customer.last_name) address = customer.credit_cards[0].billing_address self.assertEqual("123 Abc Way", address.street_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60622", address.postal_code) self.assertEqual("US", address.country_code_alpha2) self.assertEqual("USA", address.country_code_alpha3) self.assertEqual("840", address.country_code_numeric) self.assertEqual("United States of America", address.country_name) def test_create_with_customer_fields(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "custom_fields": { "store_me": "custom value" } }) self.assertTrue(result.is_success) self.assertEqual("custom value", result.customer.custom_fields["store_me"]) def test_create_returns_nested_errors(self): result = Customer.create({ "email": "invalid", "credit_card": { "number": "invalid", "billing_address": { "country_name": "invalid" } } }) self.assertFalse(result.is_success) email_errors = result.errors.for_object("customer").on("email") self.assertEqual(1, len(email_errors)) self.assertEqual(ErrorCodes.Customer.EmailIsInvalid, email_errors[0].code) card_number_errors = result.errors.for_object("customer").for_object("credit_card").on("number") self.assertEqual(1, len(card_number_errors)) self.assertEqual(ErrorCodes.CreditCard.NumberHasInvalidLength, card_number_errors[0].code) country_name_errors = result.errors.for_object("customer").for_object("credit_card").for_object("billing_address").on("country_name") self.assertEqual(1, len(country_name_errors)) self.assertEqual(ErrorCodes.Address.CountryNameIsNotAccepted, country_name_errors[0].code) def test_create_returns_errors_if_custom_fields_are_not_registered(self): result = Customer.create({ "first_name": "Jack", "last_name": "Kennedy", "custom_fields": { "spouse_name": "Jacqueline" } }) self.assertFalse(result.is_success) custom_fields_errors = result.errors.for_object("customer").on("custom_fields") self.assertEqual(1, len(custom_fields_errors)) self.assertEqual(ErrorCodes.Customer.CustomFieldIsInvalid, custom_fields_errors[0].code) def test_create_with_payment_method_nonce(self): config = Configuration.instantiate() authorization_fingerprint = json.loads(TestHelper.generate_decoded_client_token())["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) _, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) nonce = json.loads(response)["creditCards"][0]["nonce"] result = Customer.create({ "credit_card": { "payment_method_nonce": nonce } }) self.assertTrue(result.is_success) self.assertEqual("411111", result.customer.credit_cards[0].bin) def test_delete_with_valid_customer(self): customer = Customer.create().customer result = Customer.delete(customer.id) self.assertTrue(result.is_success) def test_delete_with_invalid_customer(self): with self.assertRaises(NotFoundError): customer = Customer.create().customer Customer.delete(customer.id) Customer.delete(customer.id) def test_delete_payment_method_with_path_traversal(self): try: customer = Customer.create().customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe" }).credit_card Customer.delete("../payment_methods/any/{}".format(credit_card.token)) except NotFoundError: pass payment_method = PaymentMethod.find(credit_card.token) self.assertNotEqual(None, payment_method) self.assertEqual(credit_card.token, payment_method.token) self.assertEqual(credit_card.customer_id, payment_method.customer_id) self.assertEqual("John Doe", payment_method.cardholder_name) def test_find_with_valid_customer(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Cool" }).customer found_customer = Customer.find(customer.id) self.assertEqual(customer.id, found_customer.id) self.assertEqual(customer.first_name, found_customer.first_name) self.assertEqual(customer.last_name, found_customer.last_name) self.assertNotEqual(None, customer.graphql_id) def test_find_customer_with_us_bank_account(self): customer = Customer.create({ "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "credit_card": { "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } } }).customer found_customer = Customer.find(customer.id) self.assertEqual(customer.id, found_customer.id) self.assertEqual(customer.first_name, found_customer.first_name) self.assertEqual(customer.last_name, found_customer.last_name) self.assertEqual(1, len(found_customer.us_bank_accounts)) self.assertIsInstance(found_customer.us_bank_accounts[0], UsBankAccount) def test_find_with_invalid_customer(self): with self.assertRaisesRegex(NotFoundError, "customer with id 'badid' not found"): Customer.find("badid") def test_find_customer_with_all_filterable_associations_filtered_out(self): customer = Customer.create({ "custom_fields": { "store_me": "custom value" } }).customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America" } }).credit_card subscription_id = "id_" + str(random.randint(1, 1000000)) subscription = Subscription.create({ "id": subscription_id, "plan_id": "integration_trialless_plan", "payment_method_token": credit_card.token, "price": Decimal("1.00") }).subscription found_customer = Customer.find(customer.id, "customernoassociations") self.assertEqual(len(found_customer.credit_cards), 0) self.assertEqual(len(found_customer.payment_methods), 0) self.assertEqual(len(found_customer.addresses), 0) self.assertEqual(len(found_customer.custom_fields), 0) def test_find_customer_with_nested_filterable_associations_filtered_out(self): customer = Customer.create({ "custom_fields": { "store_me": "custom value" } }).customer credit_card = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2014", "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America" } }).credit_card subscription_id = "id_" + str(random.randint(1, 1000000)) subscription = Subscription.create({ "id": subscription_id, "plan_id": "integration_trialless_plan", "payment_method_token": credit_card.token, "price": Decimal("1.00") }).subscription found_customer = Customer.find(customer.id, "customertoplevelassociations") self.assertEqual(len(found_customer.credit_cards), 1) self.assertEqual(len(found_customer.credit_cards[0].subscriptions), 0) self.assertEqual(len(found_customer.payment_methods), 1) self.assertEqual(len(found_customer.payment_methods[0].subscriptions), 0) self.assertEqual(len(found_customer.addresses), 1) self.assertEqual(len(found_customer.custom_fields), 1) def test_update_with_valid_options(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.5555", "fax": "614.555.5555", "website": "www.email.com" }).customer result = Customer.update(customer.id, { "first_name": "Joe", "last_name": "Brown", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.1234", "international_phone": {"country_code": "1", "national_number": "3121234567"}, "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("1", customer.international_phone["country_code"]) self.assertEqual("3121234567", customer.international_phone["national_number"]) self.assertEqual("614.555.5678", customer.fax) self.assertEqual("www.email.com", customer.website) self.assertNotEqual(None, customer.id) self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", customer.id)) def test_update_with_default_payment_method(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", }).customer token1 = str(random.randint(1, 1000000)) payment_method1 = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.TransactableVisa, "token": token1 }).payment_method payment_method1 = PaymentMethod.find(payment_method1.token) self.assertTrue(payment_method1.default) token2 = str(random.randint(1, 1000000)) payment_method2 = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.TransactableMasterCard, "token": token2 }).payment_method Customer.update(customer.id, { "default_payment_method_token": payment_method2.token }) payment_method2 = PaymentMethod.find(payment_method2.token) self.assertTrue(payment_method2.default) def test_update_with_default_payment_method_in_options(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", }).customer token1 = str(random.randint(1, 1000000)) payment_method1 = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.TransactableVisa, "token": token1 }).payment_method payment_method1 = PaymentMethod.find(payment_method1.token) self.assertTrue(payment_method1.default) token2 = str(random.randint(1, 1000000)) payment_method2 = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.TransactableMasterCard, "token": token2 }).payment_method Customer.update(customer.id, { "credit_card": { "options": { "update_existing_token": token2, "make_default": True } } }) payment_method2 = PaymentMethod.find(payment_method2.token) self.assertTrue(payment_method2.default) def test_update_with_nested_values(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": "4111111111111111", "expiration_date": "10/10", "billing_address": { "postal_code": "11111" } } }).customer credit_card = customer.credit_cards[0] address = credit_card.billing_address updated_customer = Customer.update(customer.id, { "first_name": "Joe", "last_name": "Brown", "credit_card": { "expiration_date": "12/12", "options": { "update_existing_token": credit_card.token }, "billing_address": { "postal_code": "44444", "country_code_alpha2": "US", "country_code_alpha3": "USA", "country_code_numeric": "840", "country_name": "United States of America", "options": { "update_existing": True } } } }).customer updated_credit_card = CreditCard.find(credit_card.token) updated_address = Address.find(customer.id, address.id) self.assertEqual("Joe", updated_customer.first_name) self.assertEqual("Brown", updated_customer.last_name) self.assertEqual("12/2012", updated_credit_card.expiration_date) self.assertEqual("44444", updated_address.postal_code) self.assertEqual("US", updated_address.country_code_alpha2) self.assertEqual("USA", updated_address.country_code_alpha3) self.assertEqual("840", updated_address.country_code_numeric) self.assertEqual("United States of America", updated_address.country_name) def test_update_with_nested_billing_address_id(self): customer = Customer.create().customer address = Address.create({ "customer_id": customer.id, "postal_code": "11111" }).address updated_customer = Customer.update(customer.id, { "credit_card": { "number": "4111111111111111", "expiration_date": "12/12", "billing_address_id": address.id } }).customer credit_card = updated_customer.credit_cards[0] self.assertEqual(address.id, credit_card.billing_address.id) self.assertEqual("11111", credit_card.billing_address.postal_code) def test_update_with_invalid_options(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", "company": "Fake Company", "email": "joe@email.com", "phone": "312.555.5555", "fax": "614.555.5555", "website": "www.email.com" }).customer result = Customer.update(customer.id, { "email": "@email.com", }) self.assertFalse(result.is_success) email_errors = result.errors.for_object("customer").on("email") self.assertEqual(1, len(email_errors)) self.assertEqual(ErrorCodes.Customer.EmailIsInvalid, email_errors[0].code) def test_update_with_paypal_future_payments_nonce(self): customer = Customer.create().customer result = Customer.update(customer.id, { "payment_method_nonce": Nonces.PayPalBillingAgreement }) self.assertTrue(result.is_success) customer = result.customer self.assertNotEqual(None, customer.paypal_accounts[0]) def test_update_with_invalid_three_d_secure_pass_thru_params(self): customer = Customer.create().customer result = Customer.update(customer.id, { "payment_method_nonce": Nonces.Transactable, "credit_card": { "three_d_secure_pass_thru": { "eci_flag": "05", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": True, }, }, }) self.assertFalse(result.is_success) self.assertEqual("ThreeDSecureVersion is required.", result.message) def test_update_with_valid_three_d_secure_pass_thru_params(self): customer = Customer.create().customer result = Customer.update(customer.id, { "payment_method_nonce": Nonces.Transactable, "credit_card": { "three_d_secure_pass_thru": { "eci_flag": "05", "cavv": "some-cavv", "three_d_secure_version": "1.2.0", "xid": "some-xid" }, "options": { "verify_card": True, }, }, }) self.assertTrue(result.is_success) def test_update_with_paypal_one_time_nonce_fails(self): customer = Customer.create().customer result = Customer.update(customer.id, { "payment_method_nonce": Nonces.PayPalOneTimePayment }) self.assertFalse(result.is_success) paypal_account_errors = result.errors.for_object("customer").for_object("paypal_account").on("base") self.assertEqual(1, len(paypal_account_errors)) self.assertEqual(ErrorCodes.PayPalAccount.CannotVaultOneTimeUsePayPalAccount, paypal_account_errors[0].code) def test_update_with_paypal_order_nonce(self): customer = Customer.create().customer http = ClientApiHttp.create() status_code, payment_method_nonce = http.get_paypal_nonce({ "intent": "order", "payment-token": "fake-paypal-payment-token", "payer-id": "fake-paypal-payer-id" }) result = Customer.update(customer.id, { "payment_method_nonce": payment_method_nonce, "options": { "paypal": { "payee_email": "payee@example.com", "order_id": "merchant-order-id", "custom_field": "custom merchant field", "description": "merchant description", "amount": "1.23", "shipping": { "first_name": "Andrew", "last_name": "Mason", "company": "Braintree", "street_address": "456 W Main St", "extended_address": "Apt 2F", "locality": "Bartlett", "region": "IL", "postal_code": "60103", "country_name": "Mexico", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484" }, }, }, }) self.assertTrue(result.is_success) customer = result.customer self.assertNotEqual(None, customer.paypal_accounts[0]) self.assertEqual(1, len(customer.paypal_accounts)) self.assertIsInstance(customer.paypal_accounts[0], PayPalAccount) def test_update_with_nested_verification_amount(self): customer = Customer.create({ "first_name": "Joe", "last_name": "Brown", "credit_card": { "number": "4111111111111111", "expiration_date": "10/10", "billing_address": { "postal_code": "11111" } } }).customer result = Customer.update(customer.id, { "credit_card": { "number": "4111111111111111", "expiration_date": "10/10", "options": { "verify_card": True, "verification_amount": "2.00" }, } }) self.assertTrue(result.is_success) def test_update_includes_risk_data_when_skip_advanced_fraud_checking_is_false(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer = Customer.create().customer result = Customer.update(customer.id, { "credit_card": { "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe", "options": { "verify_card": True, "skip_advanced_fraud_checking": False } } }) self.assertTrue(result.is_success) verification = result.customer.credit_cards[0].verification self.assertIsInstance(verification.risk_data, RiskData) def test_update_does_not_include_risk_data_when_skip_advanced_fraud_checking_is_true(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer = Customer.create().customer result = Customer.update(customer.id, { "credit_card": { "number": "4111111111111111", "expiration_date": "05/2014", "cvv": "100", "cardholder_name": "John Doe", "options": { "verify_card": True, "skip_advanced_fraud_checking": True } } }) self.assertTrue(result.is_success) verification = result.customer.credit_cards[0].verification self.assertIsNone(verification.risk_data) def test_update_works_for_raw_apple_pay(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer = Customer.create().customer secure_token = TestHelper.random_token_block(None) result = Customer.update(customer.id, { "apple_pay_card": { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "eci_indicator": "0", "cryptogram": "01010101010101010101", "cardholder_name": "John Doe", "token": secure_token, "options": { "make_default": True }, "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "phone_number": "312.555.1234", "country_code_alpha2": "US", "country_code_alpha3": "USA", "country_code_numeric": "840", "country_name": "United States of America" } }, }) self.assertTrue(result.is_success) self.assertEqual(secure_token, result.customer.payment_methods[0].token) self.assertNotEqual(0, len(result.customer.apple_pay_cards)) apple_pay_card = result.customer.apple_pay_cards[0] self.assertTrue(apple_pay_card.default) self.assertEqual(apple_pay_card.expiration_month, "05") self.assertEqual(apple_pay_card.expiration_year, "2014") self.assertEqual(apple_pay_card.cardholder_name, "John Doe") self.assertEqual(apple_pay_card.bin, "411111") self.assertEqual(apple_pay_card.billing_address["street_address"], "123 Abc Way") self.assertEqual(apple_pay_card.billing_address["locality"], "Chicago") self.assertEqual(apple_pay_card.billing_address["region"], "Illinois") self.assertEqual(apple_pay_card.billing_address["postal_code"], "60622") self.assertEqual(apple_pay_card.billing_address["phone_number"], "312.555.1234") self.assertEqual(apple_pay_card.billing_address["country_code_alpha2"], "US") self.assertEqual(apple_pay_card.billing_address["country_code_alpha3"], "USA") self.assertEqual(apple_pay_card.billing_address["country_code_numeric"], "840") self.assertEqual(apple_pay_card.billing_address["country_name"], "United States of America") def test_update_works_for_raw_android_pay_card(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer = Customer.create().customer secure_token = TestHelper.random_token_block(None) result = Customer.update(customer.id, { "android_pay_card": { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "google_transaction_id": "iliketurtles", "token": secure_token, "options": { "make_default": True }, "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "phone_number": "312.555.1234", "country_code_alpha2": "US", "country_code_alpha3": "USA", "country_code_numeric": "840", "country_name": "United States of America" } }, }) self.assertTrue(result.is_success) self.assertEqual(secure_token, result.customer.payment_methods[0].token) self.assertNotEqual(0, len(result.customer.android_pay_cards)) android_pay_card = result.customer.android_pay_cards[0] self.assertTrue(android_pay_card.default) self.assertEqual(android_pay_card.expiration_month, "05") self.assertEqual(android_pay_card.expiration_year, "2014") self.assertEqual(android_pay_card.google_transaction_id, "iliketurtles") self.assertEqual(android_pay_card.bin, "411111") self.assertEqual(android_pay_card.billing_address["street_address"], "123 Abc Way") self.assertEqual(android_pay_card.billing_address["locality"], "Chicago") self.assertEqual(android_pay_card.billing_address["region"], "Illinois") self.assertEqual(android_pay_card.billing_address["postal_code"], "60622") self.assertEqual(android_pay_card.billing_address["phone_number"], "312.555.1234") self.assertEqual(android_pay_card.billing_address["country_code_alpha2"], "US") self.assertEqual(android_pay_card.billing_address["country_code_alpha3"], "USA") self.assertEqual(android_pay_card.billing_address["country_code_numeric"], "840") self.assertEqual(android_pay_card.billing_address["country_name"], "United States of America") def test_update_for_raw_android_pay_card_with_invalid_params(self): customer = Customer.create().customer secure_token = TestHelper.random_token_block(None) result = Customer.update(customer.id, { "first_name": "Rickey", "last_name": "Crabapple", "android_pay_card": { "number": "4111111111111111", "expiration_year": "2014", "expiration_month": "01", "google_transaction_id": "dontbeevil", "billing_address": { "street_address": "head 100 yds south once you hear the beehive", "postal_code": '$$$$', "country_code_alpha2": "UX", } } }) errors = result.errors.for_object("android_pay_card").on("billing_address") self.assertFalse(result.is_success) postal_errors = result.errors.for_object("android_pay_card").for_object("billing_address").on("postal_code") country_errors = result.errors.for_object("android_pay_card").for_object("billing_address").on("country_code_alpha2") self.assertEqual(1, len(postal_errors)) self.assertEqual(1, len(country_errors)) self.assertEqual(ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, country_errors[0].code) self.assertEqual(ErrorCodes.Address.PostalCodeInvalidCharacters, postal_errors[0].code) def test_update_works_for_raw_android_pay_network_token(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer = Customer.create().customer secure_token = TestHelper.random_token_block(None) result = Customer.update(customer.id, { "android_pay_network_token": { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cryptogram": "01010101010101010101", "eci_indicator": "05", "google_transaction_id": "iliketurtles", "token": secure_token, "options": { "make_default": True }, "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "phone_number": "312.555.1234", "country_code_alpha2": "US", "country_code_alpha3": "USA", "country_code_numeric": "840", "country_name": "United States of America" } }, }) self.assertTrue(result.is_success) self.assertEqual(secure_token, result.customer.payment_methods[0].token) self.assertNotEqual(0, len(result.customer.android_pay_cards)) android_pay_network_token = result.customer.android_pay_cards[0] self.assertTrue(android_pay_network_token.default) self.assertEqual(android_pay_network_token.expiration_month, "05") self.assertEqual(android_pay_network_token.expiration_year, "2014") self.assertEqual(android_pay_network_token.google_transaction_id, "iliketurtles") self.assertEqual(android_pay_network_token.bin, "411111") self.assertEqual(android_pay_network_token.billing_address["street_address"], "123 Abc Way") self.assertEqual(android_pay_network_token.billing_address["locality"], "Chicago") self.assertEqual(android_pay_network_token.billing_address["region"], "Illinois") self.assertEqual(android_pay_network_token.billing_address["postal_code"], "60622") self.assertEqual(android_pay_network_token.billing_address["phone_number"], "312.555.1234") self.assertEqual(android_pay_network_token.billing_address["country_code_alpha2"], "US") self.assertEqual(android_pay_network_token.billing_address["country_code_alpha3"], "USA") self.assertEqual(android_pay_network_token.billing_address["country_code_numeric"], "840") self.assertEqual(android_pay_network_token.billing_address["country_name"], "United States of America") def test_update_with_tax_identifiers(self): customer = Customer.create({ "tax_identifiers": [ {"country_code": "US", "identifier": "123456789"}, {"country_code": "GB", "identifier": "987654321"}] }).customer result = Customer.update(customer.id, { "tax_identifiers": [{ "country_code": "GB", "identifier": "567891234" }] }) self.assertTrue(result.is_success) def test_customer_payment_methods(self): customer = Customer("gateway", { "credit_cards": [{"token": "credit_card"}], "paypal_accounts": [{"token": "paypal_account"}], "apple_pay_cards": [{"token": "apple_pay_card"}], "android_pay_cards": [{"token": "android_pay_card"}], "us_bank_accounts": [{"token": "us_bank_account"}] }) payment_method_tokens = [ pm.token for pm in customer.payment_methods ] self.assertEqual(sorted(payment_method_tokens), ["android_pay_card", "apple_pay_card", "credit_card", "paypal_account", "us_bank_account"]) braintree_python-4.31.0/tests/integration/test_customer_search.py000066400000000000000000000125241471021343500254430ustar00rootroot00000000000000from tests.test_helper import * class TestCustomerSearch(unittest.TestCase): def test_advanced_search_no_results(self): collection = Transaction.search([ TransactionSearch.billing_first_name == "no_such_person" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_finds_duplicate_cards_given_payment_method_token(self): credit_card_dict = { "number": "63049580000009", "expiration_date": "05/2010" } jim_dict = { "first_name": "Jim", "credit_card": credit_card_dict } joe_dict = { "first_name": "Joe", "credit_card": credit_card_dict } jim = Customer.create(jim_dict).customer joe = Customer.create(joe_dict).customer collection = Customer.search( CustomerSearch.payment_method_token_with_duplicates == jim.credit_cards[0].token, ) customer_ids = [customer.id for customer in collection.items] self.assertTrue(jim.id in customer_ids) self.assertTrue(joe.id in customer_ids) def test_advanced_search_searches_all_text_fields(self): token = "creditcard%s" % random.randint(1, 100000) customer = Customer.create({ "first_name": "Timmy", "last_name": "O'Toole", "company": "O'Toole and Son(s)", "email": "timmy@example.com", "fax": "3145551234", "phone": "5551231234", "website": "http://example.com", "credit_card": { "cardholder_name": "Tim Toole", "number": "4111111111111111", "expiration_date": "05/2010", "token": token, "billing_address": { "first_name": "Thomas", "last_name": "Otool", "street_address": "1 E Main St", "extended_address": "Suite 3", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_name": "United States of America" } } }).customer search_criteria = { "first_name": "Timmy", "last_name": "O'Toole", "company": "O'Toole and Son(s)", "email": "timmy@example.com", "phone": "5551231234", "fax": "3145551234", "website": "http://example.com", "address_first_name": "Thomas", "address_last_name": "Otool", "address_street_address": "1 E Main St", "address_postal_code": "60622", "address_extended_address": "Suite 3", "address_locality": "Chicago", "address_region": "Illinois", "address_country_name": "United States of America", "payment_method_token": token, "cardholder_name": "Tim Toole", "credit_card_number": "4111111111111111", "credit_card_expiration_date": "05/2010" } criteria = [getattr(CustomerSearch, search_field) == value for search_field, value in search_criteria.items()] criteria.append(CustomerSearch.id == customer.id) collection = Customer.search(criteria) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) for search_field, value in search_criteria.items(): collection = Customer.search( CustomerSearch.id == customer.id, getattr(CustomerSearch, search_field) == value ) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) def test_advanced_search_range_node_created_at(self): customer = Customer.create().customer past = customer.created_at - timedelta(minutes=10) future = customer.created_at + timedelta(minutes=10) collection = Customer.search( CustomerSearch.id == customer.id, CustomerSearch.created_at.between(past, future) ) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) collection = Customer.search( CustomerSearch.id == customer.id, CustomerSearch.created_at <= future ) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) collection = Customer.search( CustomerSearch.id == customer.id, CustomerSearch.created_at >= past ) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) def test_search_on_paypal_account_email(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "options": {"validate": False} }) self.assertEqual(202, status_code) customer = Customer.create({"payment_method_nonce": nonce}).customer collection = Customer.search( CustomerSearch.paypal_account_email == "jane.doe@example.com", CustomerSearch.id == customer.id ) self.assertEqual(1, collection.maximum_size) self.assertEqual(customer.id, collection.first.id) braintree_python-4.31.0/tests/integration/test_disbursement.py000066400000000000000000000017131471021343500247570ustar00rootroot00000000000000from tests.test_helper import * from datetime import date class TestDisbursement(unittest.TestCase): def test_disbursement_finds_transactions(self): disbursement = Disbursement(Configuration.gateway(), { "merchant_account": { "id": "sub_merchant_account", "status": "active", "master_merchant_account": { "id": "master_merchant_account", "status": "active" }, }, "id": "123456", "exception_message": "invalid_account_number", "amount": "100.00", "disbursement_date": date(2013, 4, 10), "follow_up_action": "update", "transaction_ids": ["sub_merchant_transaction"] }) transactions = disbursement.transactions() self.assertEqual(1, transactions.maximum_size) self.assertEqual("sub_merchant_transaction", transactions.first.id) braintree_python-4.31.0/tests/integration/test_discounts.py000066400000000000000000000023521471021343500242660ustar00rootroot00000000000000from tests.test_helper import * class TestDiscounts(unittest.TestCase): def test_all_returns_all_discounts(self): new_id = str(random.randint(1, 1000000)) attributes = { "amount": "100.00", "description": "some description", "id": new_id, "kind": "discount", "name": "python_discount", "never_expires": False, "number_of_billing_cycles": 1 } Configuration.instantiate().http().post(Configuration.instantiate().base_merchant_path() + "/modifications/create_modification_for_tests", {"modification": attributes}) discounts = Discount.all() for discount in discounts: if discount.id == new_id: break else: discount = None self.assertNotEqual(None, discount) self.assertEqual(Decimal("100.00"), discount.amount) self.assertEqual("some description", discount.description) self.assertEqual(new_id, discount.id) self.assertEqual("discount", discount.kind) self.assertEqual("python_discount", discount.name) self.assertEqual(False, discount.never_expires) self.assertEqual(1, discount.number_of_billing_cycles) braintree_python-4.31.0/tests/integration/test_dispute_search.py000066400000000000000000000147271471021343500252660ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestDisputeSearch(unittest.TestCase): def create_sample_disputed_transaction(self): customer = Customer.create({ "first_name": "Jen", "last_name": "Smith", "company": "Braintree", "email": "jen@example.com", "phone": "312.555.1234", "fax": "614.555.5678", "website": "www.example.com", }).customer return Transaction.sale({ "amount": "100.00", "credit_card": { "number": CreditCardNumbers.Disputes.Chargeback, "expiration_date": "12/2019", }, "customer_id": customer.id, "options": { "submit_for_settlement": True, }, }).transaction def test_advanced_search_no_results(self): collection = Dispute.search([ DisputeSearch.id == "non_existent_dispute" ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEqual(0, len(disputes)) def test_advanced_search_returns_single_dispute_by_customer_id(self): transaction = self.create_sample_disputed_transaction() collection = Dispute.search([ DisputeSearch.customer_id == transaction.customer_details.id ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEqual(1, len(disputes)) dispute = disputes[0] self.assertEqual(dispute.id, transaction.disputes[0].id) self.assertEqual(dispute.status, Dispute.Status.Open) def test_advanced_search_returns_single_dispute_by_id(self): collection = Dispute.search([ DisputeSearch.id == "open_dispute" ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEqual(1, len(disputes)) dispute = disputes[0] self.assertEqual(dispute.id, "open_dispute") self.assertEqual(dispute.status, Dispute.Status.Open) def test_advanced_search_returns_disputes_by_multiple_reasons(self): collection = Dispute.search([ DisputeSearch.reason.in_list([ braintree.Dispute.Reason.ProductUnsatisfactory, braintree.Dispute.Reason.Retrieval ]) ]) disputes = [dispute for dispute in collection.disputes.items] self.assertGreaterEqual(len(disputes), 2) def test_advanced_search_returns_disputes_by_chargeback_protection_level(self): collection = Dispute.search([ DisputeSearch.chargeback_protection_level.in_list([ braintree.Dispute.ChargebackProtectionLevel.Effortless, ]) ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEqual(len(disputes) > 0, True) for dispute in disputes: # NEXT_MAJOR_VERSION Remove this assertion when chargeback_protection_level is removed from the SDK self.assertEqual(dispute.chargeback_protection_level, braintree.Dispute.ChargebackProtectionLevel.Effortless) self.assertEqual(dispute.protection_level, braintree.Dispute.ProtectionLevel.EffortlessCBP) def test_advanced_search_returns_disputes_by_pre_dispute_program(self): collection = Dispute.search([ DisputeSearch.pre_dispute_program.in_list([ braintree.Dispute.PreDisputeProgram.VisaRdr, ]) ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEqual(len(disputes), 1) self.assertEqual(disputes[0].pre_dispute_program, braintree.Dispute.PreDisputeProgram.VisaRdr) def test_advanced_search_returns_disputes_with_no_pre_dispute_program(self): collection = Dispute.search([ DisputeSearch.pre_dispute_program == braintree.Dispute.PreDisputeProgram.NONE ]) disputes = [dispute for dispute in collection.disputes.items] pre_dispute_programs = set([dispute.pre_dispute_program for dispute in disputes]) self.assertGreater(len(disputes), 1) self.assertEqual(len(pre_dispute_programs), 1) self.assertIn(braintree.Dispute.PreDisputeProgram.NONE, pre_dispute_programs) def test_advanced_search_returns_disputes_by_date_range(self): collection = Dispute.search([ DisputeSearch.received_date.between("03/03/2014", "03/05/2014") ]) disputes = [dispute for dispute in collection.disputes.items] self.assertGreaterEqual(len(disputes), 1) self.assertEqual(disputes[0].received_date, date(2014, 3, 4)) def test_advanced_search_returns_disputes_by_disbursement_date_range(self): transaction = self.create_sample_disputed_transaction() disbursement_date = transaction.disputes[0].status_history[0].disbursement_date collection = Dispute.search([ DisputeSearch.disbursement_date.between(disbursement_date, disbursement_date) ]) disputes = [dispute for dispute in collection.disputes.items] self.assertGreaterEqual(len(disputes), 1) self.assertEqual(disputes[0].status_history[0].disbursement_date, disbursement_date) def test_advanced_search_returns_disputes_by_effective_date_range(self): transaction = self.create_sample_disputed_transaction() effective_date = transaction.disputes[0].status_history[0].effective_date collection = Dispute.search([ DisputeSearch.effective_date.between(effective_date, effective_date) ]) disputes = [dispute for dispute in collection.disputes.items] self.assertGreaterEqual(len(disputes), 1) self.assertEqual(disputes[0].status_history[0].effective_date, effective_date) def test_advanced_search_returns_disputes_by_amount_and_status(self): collection = Dispute.search([ DisputeSearch.amount_disputed.between("1.00", "100.00"), DisputeSearch.id == "open_dispute" ]) disputes = [dispute for dispute in collection.disputes.items] self.assertEqual(1, len(disputes)) def test_advanced_search_can_take_one_criteria(self): collection = Dispute.search( DisputeSearch.id == "non_existent_dispute" ) disputes = [dispute for dispute in collection.disputes.items] self.assertEqual(0, len(disputes)) braintree_python-4.31.0/tests/integration/test_disputes.py000066400000000000000000000353211471021343500241150ustar00rootroot00000000000000import re import time import datetime from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestDisputes(unittest.TestCase): def create_evidence_document(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/bt_logo.png") png_file = open(file_path, "rb") return DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": png_file }).document_upload def create_sample_dispute(self): return Transaction.sale({ "amount": "100.00", "credit_card": { "number": CreditCardNumbers.Disputes.Chargeback, "expiration_date": "12/2019" } }).transaction.disputes[0] def test_accept_changes_dispute_status_to_accepted(self): dispute = self.create_sample_dispute() result = Dispute.accept(dispute.id) self.assertTrue(result.is_success) updated_dispute = Dispute.find(dispute.id) self.assertEqual(updated_dispute.status, Dispute.Status.Accepted) dispute_from_transaction = Transaction.find(dispute.transaction.id).disputes[0] self.assertEqual(dispute_from_transaction.status, Dispute.Status.Accepted) def test_accept_errors_when_dispute_not_open(self): result = Dispute.accept("wells_dispute") self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyAcceptOpenDispute) self.assertEqual(result.errors.for_object("dispute")[0].message, "Disputes can only be accepted when they are in an Open state") def test_accept_raises_error_when_dispute_not_found(self): with self.assertRaisesRegex(NotFoundError, "dispute with id 'invalid-id' not found"): dispute = Dispute.accept("invalid-id") def test_add_file_evidence_adds_evidence(self): dispute = self.create_sample_dispute() document = self.create_evidence_document() result = Dispute.add_file_evidence(dispute.id, document.id) self.assertTrue(result.is_success) updated_dispute = Dispute.find(dispute.id) self.assertEqual(updated_dispute.evidence[0].id, result.evidence.id) def test_add_file_evidence_adds_category_file_evidence(self): dispute = self.create_sample_dispute() document = self.create_evidence_document() result = Dispute.add_file_evidence(dispute.id, { "document_id": document.id, "category": "GENERAL" }) self.assertTrue(result.is_success) self.assertEqual(result.evidence.category, "GENERAL") def test_add_file_evidence_raises_error_when_dispute_not_found(self): with self.assertRaisesRegex(NotFoundError, "dispute with id 'unknown_dispute_id' not found"): dispute = Dispute.add_file_evidence("unknown_dispute_id", "text evidence") def test_add_file_evidence_raises_error_when_dispute_not_open(self): dispute = self.create_sample_dispute() document = self.create_evidence_document() Dispute.accept(dispute.id) result = Dispute.add_file_evidence(dispute.id, document.id) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyAddEvidenceToOpenDispute) self.assertEqual(result.errors.for_object("dispute")[0].message, "Evidence can only be attached to disputes that are in an Open state") def test_categorized_file_evidence_for_text_only_category(self): dispute = self.create_sample_dispute() document = self.create_evidence_document() result = Dispute.add_file_evidence(dispute.id, { "document_id": document.id, "category": "DEVICE_ID" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.EvidenceCategoryTextOnly) self.assertEqual(result.errors.for_object("dispute")[0].message, "Only text evidence can be provided for this category") def test_categorized_file_evidence_with_unsupported_category(self): dispute = self.create_sample_dispute() document = self.create_evidence_document() result = Dispute.add_file_evidence(dispute.id, { "document_id": document.id, "category": "DOESNOTEXIST" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyCreateEvidenceWithValidCategory) self.assertEqual(result.errors.for_object("dispute")[0].message, "The category you supplied on the evidence record is not valid") def test_add_text_evidence_adds_text_evidence(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, "text evidence") evidence = result.evidence self.assertTrue(result.is_success) self.assertEqual(evidence.comment, "text evidence") self.assertIsNotNone(evidence.created_at) self.assertTrue(re.match("^\w{16,}$", evidence.id)) self.assertIsNone(evidence.sent_to_processor_at) self.assertIsNone(evidence.url) self.assertIsNone(evidence.category) self.assertIsNone(evidence.sequence_number) def test_add_text_evidence_adds_category_and_sequence_number_text_evidence(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "PROOF_OF_FULFILLMENT", "category": "DEVICE_ID", "sequence_number": "0" }) self.assertTrue(result.is_success) evidence = result.evidence self.assertEqual(evidence.comment, "PROOF_OF_FULFILLMENT") self.assertEqual(evidence.category, "DEVICE_ID") self.assertEqual(evidence.sequence_number, 0) def test_add_text_evidence_raises_error_when_dispute_not_found(self): with self.assertRaisesRegex(NotFoundError, "Dispute with ID 'unknown_dispute_id' not found"): dispute = Dispute.add_text_evidence("unknown_dispute_id", "text evidence") def test_add_text_evidence_raises_error_when_dispute_not_open(self): dispute = self.create_sample_dispute() Dispute.accept(dispute.id) result = Dispute.add_text_evidence(dispute.id, "text evidence") self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyAddEvidenceToOpenDispute) self.assertEqual(result.errors.for_object("dispute")[0].message, "Evidence can only be attached to disputes that are in an Open state") def test_add_text_evidence_shows_new_record_in_find(self): dispute = self.create_sample_dispute() evidence = Dispute.add_text_evidence(dispute.id, "text evidence").evidence refreshed_dispute = Dispute.find(dispute.id) self.assertEqual(refreshed_dispute.evidence[0].id, evidence.id) self.assertEqual(refreshed_dispute.evidence[0].comment, "text evidence") def test_categorized_text_evidence_with_unsupported_category(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "evidence", "category": "DOESNOTEXIST" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyCreateEvidenceWithValidCategory) self.assertEqual(result.errors.for_object("dispute")[0].message, "The category you supplied on the evidence record is not valid") def test_categorized_text_evidence_with_file_category(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "evidence", "category": "MERCHANT_WEBSITE_OR_APP_ACCESS" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.EvidenceCategoryDocumentOnly) self.assertEqual(result.errors.for_object("dispute")[0].message, "Only document evidence can be provided for this category") def test_categorized_text_evidence_with_invalid_date_time_format(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "not a date", "category": "DOWNLOAD_DATE_TIME" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.EvidenceContentDateInvalid) def test_categorized_text_evidence_with_valid_date_time_format(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "2018-10-20T18:00:00-0500", "category": "DOWNLOAD_DATE_TIME" }) self.assertTrue(result.is_success) def test_add_text_evidence_adds_category_and_shipping_tracking_carrier_name(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "UPS", "category": "CARRIER_NAME", "sequence_number": "0" }) self.assertTrue(result.is_success) evidence = result.evidence self.assertEqual(evidence.comment, "UPS") self.assertEqual(evidence.category, "CARRIER_NAME") self.assertEqual(evidence.sequence_number, 0) def test_add_text_evidence_adds_category_and_shipping_tracking_tracking_number(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "3", "category": "TRACKING_NUMBER", "sequence_number": "0" }) self.assertTrue(result.is_success) evidence = result.evidence self.assertEqual(evidence.comment, "3") self.assertEqual(evidence.category, "TRACKING_NUMBER") self.assertEqual(evidence.sequence_number, 0) def test_add_text_evidence_adds_category_and_shipping_tracking_tracking_url(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "https://example.com/tracking-number/abc12345", "category": "TRACKING_URL", "sequence_number": "1" }) self.assertTrue(result.is_success) evidence = result.evidence self.assertEqual(evidence.comment, "https://example.com/tracking-number/abc12345") self.assertEqual(evidence.category, "TRACKING_URL") self.assertEqual(evidence.sequence_number, 1) def test_finalize_changes_dispute_status_to_disputed(self): dispute = self.create_sample_dispute() result = Dispute.finalize(dispute.id) self.assertTrue(result.is_success) updated_dispute = Dispute.find(dispute.id) self.assertEqual(updated_dispute.status, Dispute.Status.Disputed) def test_finalize_errors_when_dispute_not_open(self): result = Dispute.finalize("wells_dispute") self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyFinalizeOpenDispute) self.assertEqual(result.errors.for_object("dispute")[0].message, "Disputes can only be finalized when they are in an Open state") def test_finalize_when_digital_goods_missing(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "device_id", "category": "DEVICE_ID" }) self.assertTrue(result.is_success) result = dispute.finalize(dispute.id) self.assertFalse(result.is_success) error_codes = [error.code for error in result.errors.for_object("dispute")] self.assertIn(ErrorCodes.Dispute.DigitalGoodsMissingDownloadDate, error_codes) self.assertIn(ErrorCodes.Dispute.DigitalGoodsMissingEvidence, error_codes) def test_finalize_when_missing_non_disputed_payments_date(self): dispute = self.create_sample_dispute() result = Dispute.add_text_evidence(dispute.id, { "content": "123", "category": "PRIOR_NON_DISPUTED_TRANSACTION_ARN" }) self.assertTrue(result.is_success) result = dispute.finalize(dispute.id) self.assertFalse(result.is_success) error_codes = [error.code for error in result.errors.for_object("dispute")] self.assertIn(ErrorCodes.Dispute.NonDisputedPriorTransactionEvidenceMissingDate, error_codes) def test_finalize_raises_error_when_dispute_not_found(self): with self.assertRaisesRegex(NotFoundError, "dispute with id 'invalid-id' not found"): dispute = Dispute.finalize("invalid-id") def test_find_returns_dispute_with_given_id(self): dispute = Dispute.find("open_dispute") self.assertEqual(dispute.amount_disputed, 31.0) self.assertEqual(dispute.amount_won, 0.0) self.assertEqual(dispute.id, "open_dispute") self.assertEqual(dispute.status, Dispute.Status.Open) self.assertEqual(dispute.transaction.id, "open_disputed_transaction") self.assertEqual(None, dispute.transaction.installment_count) self.assertNotEqual(None, dispute.graphql_id) def test_find_raises_error_when_dispute_not_found(self): with self.assertRaisesRegex(NotFoundError, "dispute with id 'invalid-id' not found"): dispute = Dispute.find("invalid-id") def test_delete_customer_with_path_traversal(self): try: customer = Customer.create({"first_name":"Waldo"}).customer dispute = self.create_sample_dispute() Dispute.remove_evidence(dispute.id, "../../../customers/{}".format(customer.id)) except NotFoundError: pass found_customer = Customer.find(customer.id) self.assertNotEqual(None, found_customer) self.assertEqual("Waldo", found_customer.first_name) def test_remove_evidence_removes_evidence_from_the_dispute(self): dispute = self.create_sample_dispute() evidence = Dispute.add_text_evidence(dispute.id, "text evidence").evidence result = Dispute.remove_evidence(dispute.id, evidence.id) self.assertTrue(result.is_success) def test_remove_evidence_raises_error_when_dispute_or_evidence_not_found(self): with self.assertRaisesRegex(NotFoundError, "evidence with id 'unknown_evidence_id' for dispute with id 'unknown_dispute_id' not found"): Dispute.remove_evidence("unknown_dispute_id", "unknown_evidence_id") def test_remove_evidence_errors_when_dispute_not_open(self): dispute = self.create_sample_dispute() evidence = Dispute.add_text_evidence(dispute.id, "text evidence").evidence Dispute.accept(dispute.id) result = Dispute.remove_evidence(dispute.id, evidence.id) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("dispute")[0].code, ErrorCodes.Dispute.CanOnlyRemoveEvidenceFromOpenDispute) self.assertEqual(result.errors.for_object("dispute")[0].message, "Evidence can only be removed from disputes that are in an Open state") braintree_python-4.31.0/tests/integration/test_document_upload.py000066400000000000000000000114521471021343500254360ustar00rootroot00000000000000import os from tests.test_helper import * from braintree.test.nonces import Nonces class TestDocumentUpload(unittest.TestCase): def setUp(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/bt_logo.png") self.png_file = open(file_path, "rb") def test_create_returns_successful_result_if_valid(self): result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": self.png_file }) self.assertTrue(result.is_success) self.assertTrue(result.document_upload.id != None) self.assertEqual(result.document_upload.content_type, "image/png") self.assertEqual(result.document_upload.kind, braintree.DocumentUpload.Kind.EvidenceDocument) self.assertEqual(result.document_upload.name, "bt_logo.png") self.assertEqual(result.document_upload.size, 2443) def test_create_returns_error_with_unsupported_file_type(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/gif_extension_bt_logo.gif") gif_file = open(file_path, "rb") result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": gif_file }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.FileTypeIsInvalid) def test_create_returns_error_with_malformed_file(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/malformed_pdf.pdf") bad_pdf_file = open(file_path, "rb") result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": bad_pdf_file }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.FileIsMalformedOrEncrypted) def test_create_returns_error_with_invalid_kind(self): result = DocumentUpload.create({ "kind": "invalid_kind", "file": self.png_file }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.KindIsInvalid) def test_create_returns_error_when_file_is_over_4mb(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/large_file.png") try: f = open(file_path, 'w+') for i in range(1048577 * 4): f.write('a') f.close() large_file = open(file_path, 'rb') result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": large_file }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.FileIsTooLarge) finally: os.remove(file_path) def test_create_returns_error_when_file_is_empty(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/empty_file.png") try: f = open(file_path, 'w') f.close() empty_file = open(file_path, 'rb') result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": empty_file }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.FileIsEmpty) finally: os.remove(file_path) def test_create_returns_error_with_too_long_file(self): file_path = os.path.join(os.path.dirname(__file__), "..", "fixtures/too_long.pdf") too_long_pdf = open(file_path, "rb") result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": too_long_pdf }) self.assertEqual(result.errors.for_object("document_upload")[0].code, ErrorCodes.DocumentUpload.FileIsTooLong) def test_create_returns_invalid_keys_errors_with_invalid_signature(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: invalid_key'"): result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "invalid_key": "do not add" }) def test_create_throws_error_when_not_valid_file(self): with self.assertRaisesRegex(ValueError, "file must be a file handle"): result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": "not_a_file" }) def test_create_throws_error_when_none_file(self): with self.assertRaisesRegex(ValueError, "file must be a file handle"): result = DocumentUpload.create({ "kind": braintree.DocumentUpload.Kind.EvidenceDocument, "file": None }) braintree_python-4.31.0/tests/integration/test_exchange_rate_quote.py000066400000000000000000000115501471021343500262650ustar00rootroot00000000000000from tests.test_helper import * from braintree.exchange_rate_quote_request import ExchangeRateQuoteRequest class TestExchangeRateQuote(unittest.TestCase): @staticmethod def get_gateway(): config = Configuration("development", "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key") return BraintreeGateway(config) def test_exchange_rate_quote_with_full_graphql(self): attribute1 = {"base_currency":"USD", "quote_currency":"EUR", "base_amount":"12.19", "markup":"12.14"} attribute2 = {"base_currency":"EUR", "quote_currency":"CAD", "base_amount":"15.16", "markup":"2.64"} request = ExchangeRateQuoteRequest().add_exchange_rate_quote_input( attribute1).done().add_exchange_rate_quote_input(attribute2).done() result = self.get_gateway().exchange_rate_quote.generate(request) self.assertTrue(result.is_success) quotes = result.exchange_rate_quote_payload.get_quotes() self.assertEqual(2, len(quotes)) quote1 = quotes[0] self.assertEqual("12.19", str(quote1.base_amount.value)) self.assertEqual("USD", quote1.base_amount.currency_code) self.assertEqual("12.16", str(quote1.quote_amount.value)) self.assertEqual("EUR", quote1.quote_amount.currency_code) self.assertEqual("0.997316360864", quote1.exchange_rate) self.assertEqual("0.01", quote1.trade_rate) self.assertEqual("2021-06-16T02:00:00.000000Z", quote1.expires_at) self.assertEqual("2021-06-16T00:00:00.000000Z", quote1.refreshes_at) self.assertEqual("ZXhjaGFuZ2VyYXRlcXVvdGVfMDEyM0FCQw", quote1.id) quote2 = quotes[1] self.assertEqual("15.16", str(quote2.base_amount.value)) self.assertEqual("EUR", quote2.base_amount.currency_code) self.assertEqual("23.30", str(quote2.quote_amount.value)) self.assertEqual("CAD", quote2.quote_amount.currency_code) self.assertEqual("1.536744692129366", quote2.exchange_rate) self.assertIsNone(quote2.trade_rate) self.assertEqual("2021-06-16T02:00:00.000000Z", quote2.expires_at) self.assertEqual("2021-06-16T00:00:00.000000Z", quote2.refreshes_at) self.assertEqual("ZXhjaGFuZ2VyYXRlcXVvdGVfQUJDMDEyMw", quote2.id) def test_exchange_rate_quote_with_graphqul_quote_currency_validation_error(self): attribute1 = {"base_currency":"USD", "base_amount":"12.19", "markup":"12.14"} attribute2 = {"base_currency":"EUR", "quote_currency":"CAD", "base_amount":"15.16", "markup":"2.64"} request = ExchangeRateQuoteRequest().add_exchange_rate_quote_input( attribute1).done().add_exchange_rate_quote_input(attribute2).done() result = self.get_gateway().exchange_rate_quote.generate(request) self.assertFalse(result.is_success) self.assertTrue("'quoteCurrency'" in result.message) def test_exchange_rate_quote_with_graphql_base_currency_validation_error(self): attribute1 = {"base_currency":"USD", "quote_currency":"EUR", "base_amount":"12.19", "markup":"12.14"} attribute2 = {"quote_currency":"CAD", "base_amount":"15.16", "markup":"2.64"} request = ExchangeRateQuoteRequest().add_exchange_rate_quote_input( attribute1).done().add_exchange_rate_quote_input(attribute2).done() result = self.get_gateway().exchange_rate_quote.generate(request) self.assertFalse(result.is_success) self.assertTrue("'baseCurrency'" in result.message) def test_exchange_rate_quote_with_graphql_without_base_amount(self): attribute1 = {"base_currency":"USD", "quote_currency":"EUR"} attribute2 = {"base_currency":"EUR", "quote_currency":"CAD"} request = ExchangeRateQuoteRequest().add_exchange_rate_quote_input( attribute1).done().add_exchange_rate_quote_input(attribute2).done() result = self.get_gateway().exchange_rate_quote.generate(request) self.assertTrue(result.is_success) def test_exchange_rate_quote_with_graphql_without_base_and_quote_currency(self): attribute1 = {"base_amount":"12.19", "markup":"12.14"} request = ExchangeRateQuoteRequest().add_exchange_rate_quote_input( attribute1).done() result = self.get_gateway().exchange_rate_quote.generate(request) self.assertFalse(result.is_success) self.assertTrue("'baseCurrency'" in result.message)braintree_python-4.31.0/tests/integration/test_graphql_client.py000066400000000000000000000032121471021343500252430ustar00rootroot00000000000000from unittest import TestCase from braintree.configuration import Configuration from braintree.environment import Environment class TestGraphQLClient(TestCase): @staticmethod def get_graphql_client(environment): config = Configuration(environment, "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key") return config.graphql_client() def test_graphql_makes_valid_queries_without_variables(self): definition = ''' query { ping } ''' graphql_client = self.get_graphql_client(Environment.Development) response = graphql_client.query(definition) self.assertTrue("data" in response) self.assertTrue("ping" in response["data"]) self.assertTrue("pong" == response["data"]["ping"]) def test_graphql_makes_valid_queries_with_variables(self): definition = ''' mutation CreateClientToken($input: CreateClientTokenInput!) { createClientToken(input: $input) { clientToken } } ''' variables = { "input": { "clientToken": { "merchantAccountId": "ABC123" } } } graphql_client = self.get_graphql_client(Environment.Development) response = graphql_client.query(definition, variables) self.assertTrue("data" in response) self.assertTrue("createClientToken" in response["data"]) self.assertTrue("clientToken" in response["data"]["createClientToken"]) braintree_python-4.31.0/tests/integration/test_http.py000066400000000000000000000106331471021343500232330ustar00rootroot00000000000000from tests.test_helper import * from distutils.version import LooseVersion import platform import braintree import requests class TestHttp(unittest.TestCase): if LooseVersion(requests.__version__) >= LooseVersion('1.0.0'): SSLError = requests.exceptions.SSLError else: SSLError = requests.models.SSLError @staticmethod def get_http(environment): config = Configuration(environment, "merchant_id", public_key="public_key", private_key="private_key") return config.http() def test_successful_connection_sandbox(self): with self.assertRaises(Exception): http = self.get_http(Environment.Sandbox) http.get("/") def test_successful_connection_production(self): with self.assertRaises(Exception): http = self.get_http(Environment.Production) http.get("/") def test_wrapping_http_exceptions(self): config = Configuration( Environment("test", "localhost", "1", False, None, Environment.Production.ssl_certificate), "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key", wrap_http_exceptions=True ) gateway = braintree.braintree_gateway.BraintreeGateway(config) try: gateway.transaction.find("my_id") except braintree.exceptions.unexpected_error.UnexpectedError: correct_exception = True except Exception: correct_exception = False self.assertTrue(correct_exception) def test_unsuccessful_connection_to_good_ssl_server_with_wrong_cert(self): if platform.system() == "Darwin": return #any endpoint that returns valid XML with a status of 3xx or less and serves SSL environment = Environment("test", "github.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: pass else: self.fail("Expected to receive an SSL error but no exception was raised") def test_timeouts(self): config = Configuration( Environment.Development, "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key", wrap_http_exceptions=True, timeout=0.001 ) gateway = braintree.braintree_gateway.BraintreeGateway(config) try: gateway.transaction.find("my_id") except braintree.exceptions.http.timeout_error.TimeoutError: correct_exception = True except Exception: correct_exception = False self.assertTrue(correct_exception) def test_sessions_include_proxy_environments(self): proxies = {'https': 'http://i-clearly-dont-work', 'http': 'https://i-clearly-dont-work'} os.environ['HTTP_PROXY'] = proxies['http'] os.environ['HTTPS_PROXY'] = proxies['https'] self.assertEqual(requests.utils.getproxies(), proxies) config = Configuration( Environment.Development, "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.plan.all() os.environ.clear() assert False, "The proxy is invalid this request should not be successful." except Exception as e: os.environ.clear() assert 'Cannot connect to proxy' in str(e) braintree_python-4.31.0/tests/integration/test_masterpass.py000066400000000000000000000105711471021343500244370ustar00rootroot00000000000000from tests.test_helper import * class TestMasterpass(unittest.TestCase): def test_create_from_nonce(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.MasterpassVisa }) self.assertTrue(result.is_success) masterpass_card = result.payment_method self.assertIsNotNone(masterpass_card.billing_address) self.assertIsNotNone(masterpass_card.bin) self.assertIsNotNone(masterpass_card.card_type) self.assertIsNotNone(masterpass_card.cardholder_name) self.assertIsNotNone(masterpass_card.commercial) self.assertIsNotNone(masterpass_card.country_of_issuance) self.assertIsNotNone(masterpass_card.created_at) self.assertIsNotNone(masterpass_card.customer_id) self.assertIsNotNone(masterpass_card.customer_location) self.assertIsNotNone(masterpass_card.debit) self.assertIsNotNone(masterpass_card.default) self.assertIsNotNone(masterpass_card.durbin_regulated) self.assertIsNotNone(masterpass_card.expiration_date) self.assertIsNotNone(masterpass_card.expiration_month) self.assertIsNotNone(masterpass_card.expiration_year) self.assertIsNotNone(masterpass_card.expired) self.assertIsNotNone(masterpass_card.healthcare) self.assertIsNotNone(masterpass_card.image_url) self.assertIsNotNone(masterpass_card.issuing_bank) self.assertIsNotNone(masterpass_card.last_4) self.assertIsNotNone(masterpass_card.masked_number) self.assertIsNotNone(masterpass_card.payroll) self.assertIsNotNone(masterpass_card.prepaid) self.assertIsNotNone(masterpass_card.product_id) self.assertIsNotNone(masterpass_card.subscriptions) self.assertIsNotNone(masterpass_card.token) self.assertIsNotNone(masterpass_card.unique_number_identifier) self.assertIsNotNone(masterpass_card.updated_at) customer = Customer.find(customer.id) self.assertEqual(len(customer.masterpass_cards), 1) self.assertEqual(result.payment_method.token, customer.masterpass_cards[0].token) def test_search_for_transaction(self): result = Transaction.sale({ "payment_method_nonce": Nonces.MasterpassVisa, "amount": "1.23" }) self.assertTrue(result.is_success) transaction = result.transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == PaymentInstrumentType.MasterpassCard ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_create_transaction_from_nonce_and_vault(self): customer = Customer.create().customer result = Transaction.sale({ "payment_method_nonce": Nonces.MasterpassVisa, "customer_id": customer.id, "amount": "1.23", "options": { "store_in_vault": "true" } }) self.assertTrue(result.is_success) masterpass_card_details = result.transaction.masterpass_card_details self.assertIsNotNone(masterpass_card_details.bin) self.assertIsNotNone(masterpass_card_details.card_type) self.assertIsNotNone(masterpass_card_details.cardholder_name) self.assertIsNotNone(masterpass_card_details.commercial) self.assertIsNotNone(masterpass_card_details.country_of_issuance) self.assertIsNotNone(masterpass_card_details.debit) self.assertIsNotNone(masterpass_card_details.durbin_regulated) self.assertIsNotNone(masterpass_card_details.expiration_date) self.assertIsNotNone(masterpass_card_details.expiration_year) self.assertIsNotNone(masterpass_card_details.expiration_month) self.assertIsNotNone(masterpass_card_details.healthcare) self.assertIsNotNone(masterpass_card_details.image_url) self.assertIsNotNone(masterpass_card_details.issuing_bank) self.assertIsNotNone(masterpass_card_details.last_4) self.assertIsNotNone(masterpass_card_details.payroll) self.assertIsNotNone(masterpass_card_details.prepaid) self.assertIsNotNone(masterpass_card_details.product_id) self.assertIsNotNone(masterpass_card_details.token) braintree_python-4.31.0/tests/integration/test_merchant.py000066400000000000000000000152361471021343500240610ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.nonces import Nonces class TestMerchantGateway(unittest.TestCase): def setUp(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) def test_create_merchant(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["credit_card", "paypal"] }) merchant = result.merchant self.assertIsNotNone(merchant.id) self.assertEqual(merchant.company_name, "name@email.com") self.assertEqual(merchant.email, "name@email.com") self.assertEqual(merchant.country_code_alpha3, "GBR") self.assertEqual(merchant.country_code_alpha2, "GB") self.assertEqual(merchant.country_code_numeric, "826") self.assertEqual(merchant.country_name, "United Kingdom") self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) def test_returns_error_with_invalid_payment_methods(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["fake_money"] }) self.assertFalse(result.is_success) self.assertIn("One or more payment methods passed are not accepted.", result.message) payment_method_errors = result.errors.for_object("merchant").on("payment_methods") self.assertEqual(1, len(payment_method_errors)) self.assertEqual(payment_method_errors[0].code, ErrorCodes.Merchant.PaymentMethodsAreInvalid) def test_create_paypal_only_merchant_that_accepts_multiple_currencies(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["paypal"], "currencies": ["GBP", "USD"], "paypal_account": { "client_id": "fake_client_id", "client_secret": "fake_client_secret" } }) merchant = result.merchant self.assertIsNotNone(merchant.id) self.assertEqual(merchant.company_name, "name@email.com") self.assertEqual(merchant.email, "name@email.com") self.assertEqual(merchant.country_code_alpha3, "GBR") self.assertEqual(merchant.country_code_alpha2, "GB") self.assertEqual(merchant.country_code_numeric, "826") self.assertEqual(merchant.country_name, "United Kingdom") self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) merchant_accounts = merchant.merchant_accounts self.assertEqual(2, len(merchant_accounts)) usd_merchant_account = [ma for ma in merchant_accounts if ma.id == "USD"][0] self.assertFalse(usd_merchant_account.default) self.assertEqual(usd_merchant_account.currency_iso_code, "USD") gbp_merchant_account = [ma for ma in merchant_accounts if ma.id == "GBP"][0] self.assertTrue(gbp_merchant_account.default) self.assertEqual(gbp_merchant_account.currency_iso_code, "GBP") def test_create_eu_merchant_that_accepts_multiple_currencies(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["credit_card", "paypal"], "currencies": ["GBP", "USD"], "paypal_account": { "client_id": "fake_client_id", "client_secret": "fake_client_secret" } }) merchant = result.merchant self.assertIsNotNone(merchant.id) self.assertEqual(merchant.email, "name@email.com") self.assertEqual(merchant.country_code_alpha3, "GBR") self.assertEqual(merchant.country_code_alpha2, "GB") self.assertEqual(merchant.country_code_numeric, "826") self.assertEqual(merchant.country_name, "United Kingdom") self.assertEqual(merchant.company_name, "name@email.com") self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) merchant_accounts = merchant.merchant_accounts self.assertEqual(2, len(merchant_accounts)) usd_merchant_account = [ma for ma in merchant_accounts if ma.id == "USD"][0] self.assertFalse(usd_merchant_account.default) self.assertEqual(usd_merchant_account.currency_iso_code, "USD") gbp_merchant_account = [ma for ma in merchant_accounts if ma.id == "GBP"][0] self.assertTrue(gbp_merchant_account.default) self.assertEqual(gbp_merchant_account.currency_iso_code, "GBP") def test_returns_error_if_invalid_currency_is_passed(self): result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["credit_card"], "currencies": ["USD", "FAKE"], "paypal_account": { "client_id": "paypal_client_id", "client_secret": "paypal_client_secret" } }) self.assertFalse(result.is_success) currencies_errors = result.errors.for_object("merchant").on("currencies") self.assertEqual(1, len(currencies_errors)) self.assertEqual(ErrorCodes.Merchant.CurrenciesAreInvalid, currencies_errors[0].code) braintree_python-4.31.0/tests/integration/test_merchant_account.py000066400000000000000000000650611471021343500255760ustar00rootroot00000000000000from tests.test_helper import * class TestMerchantAccount(unittest.TestCase): VALID_APPLICATION_PARAMS = { "individual": { "first_name": "Joe", "last_name": "Bloggs", "email": "joe@bloggs.com", "phone": "555-123-1234", "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": "423456789", "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_application_with_valid_params_and_no_id(self): result = MerchantAccount.create(self.VALID_APPLICATION_PARAMS) self.assertTrue(result.is_success) self.assertEqual(MerchantAccount.Status.Pending, result.merchant_account.status) self.assertEqual("sandbox_master_merchant_account", result.merchant_account.master_merchant_account.id) def test_create_allows_an_id_to_pass(self): params_with_id = self.VALID_APPLICATION_PARAMS.copy() rand = str(random.randint(1, 1000000)) params_with_id['id'] = 'sub_merchant_account_id' + rand result = MerchantAccount.create(params_with_id) self.assertTrue(result.is_success) self.assertEqual(MerchantAccount.Status.Pending, result.merchant_account.status) self.assertEqual(params_with_id['id'], result.merchant_account.id) self.assertEqual("sandbox_master_merchant_account", result.merchant_account.master_merchant_account.id) def test_create_handles_unsuccessful_results(self): result = MerchantAccount.create({}) self.assertFalse(result.is_success) merchant_account_id_errors = result.errors.for_object("merchant_account").on("master_merchant_account_id") self.assertEqual(1, len(merchant_account_id_errors)) self.assertEqual(ErrorCodes.MerchantAccount.MasterMerchantAccountIdIsRequired, merchant_account_id_errors[0].code) def test_create_requires_all_fields(self): result = MerchantAccount.create( {"master_merchant_account_id": "sandbox_master_merchant_account"} ) self.assertFalse(result.is_success) tos_errors = result.errors.for_object("merchant_account").on("tos_accepted") self.assertEqual(ErrorCodes.MerchantAccount.TosAcceptedIsRequired , tos_errors[0].code) def test_create_funding_destination_accepts_a_bank(self): params = self.VALID_APPLICATION_PARAMS.copy() params['funding']['destination'] = MerchantAccount.FundingDestination.Bank result = MerchantAccount.create(params) self.assertTrue(result.is_success) def test_create_funding_destination_accepts_an_email(self): params = self.VALID_APPLICATION_PARAMS.copy() params['funding']['destination'] = MerchantAccount.FundingDestination.Email params['funding']['email'] = "junkman@hotmail.com" result = MerchantAccount.create(params) self.assertTrue(result.is_success) def test_create_funding_destination_accepts_a_mobile_phone(self): params = self.VALID_APPLICATION_PARAMS.copy() params['funding']['destination'] = MerchantAccount.FundingDestination.MobilePhone params['funding']['mobile_phone'] = "1112223333" result = MerchantAccount.create(params) self.assertTrue(result.is_success) def test_update_all_merchant_account_fields(self): UPDATE_PARAMS = { "individual": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone": "312-555-1234", "address": { "street_address": "123 Fake St", "postal_code": "60622", "locality": "Chicago", "region": "IL", }, "date_of_birth": "1970-01-01", "ssn": "987-65-4321", }, "business": { "dba_name": "James's Bloggs", "legal_name": "James's Junkyard", "tax_id": "987651324", "address": { "street_address": "456 Fake St", "postal_code": "48104", "locality": "Ann Arbor", "region": "MI", }, }, "funding": { "routing_number": "071000013", "account_number": "666666789", "destination": MerchantAccount.FundingDestination.Email, "email": "check@this.com", "mobile_phone": "9998887777", "descriptor": "Joes Bloggs MI", } } result = MerchantAccount.update("sandbox_sub_merchant_account", UPDATE_PARAMS) self.assertTrue(result.is_success) self.assertEqual(result.merchant_account.status, "active") self.assertEqual(result.merchant_account.id, "sandbox_sub_merchant_account") self.assertEqual(result.merchant_account.master_merchant_account.id, "sandbox_master_merchant_account") self.assertEqual(result.merchant_account.individual_details.first_name, "John") self.assertEqual(result.merchant_account.individual_details.last_name, "Doe") self.assertEqual(result.merchant_account.individual_details.email, "john.doe@example.com") self.assertEqual(result.merchant_account.individual_details.date_of_birth, "1970-01-01") self.assertEqual(result.merchant_account.individual_details.phone, "3125551234") self.assertEqual(result.merchant_account.individual_details.address_details.street_address, "123 Fake St") self.assertEqual(result.merchant_account.individual_details.address_details.locality, "Chicago") self.assertEqual(result.merchant_account.individual_details.address_details.region, "IL") self.assertEqual(result.merchant_account.individual_details.address_details.postal_code, "60622") self.assertEqual(result.merchant_account.business_details.dba_name, "James's Bloggs") self.assertEqual(result.merchant_account.business_details.legal_name, "James's Junkyard") self.assertEqual(result.merchant_account.business_details.tax_id, "987651324") self.assertEqual(result.merchant_account.business_details.address_details.street_address, "456 Fake St") self.assertEqual(result.merchant_account.business_details.address_details.postal_code, "48104") self.assertEqual(result.merchant_account.business_details.address_details.locality, "Ann Arbor") self.assertEqual(result.merchant_account.business_details.address_details.region, "MI") self.assertEqual(result.merchant_account.funding_details.routing_number, "071000013") self.assertEqual(result.merchant_account.funding_details.account_number_last_4, "6789") self.assertEqual(result.merchant_account.funding_details.destination, MerchantAccount.FundingDestination.Email) self.assertEqual(result.merchant_account.funding_details.email, "check@this.com") self.assertEqual(result.merchant_account.funding_details.mobile_phone, "9998887777") self.assertEqual(result.merchant_account.funding_details.descriptor, "Joes Bloggs MI") def test_update_does_not_require_all_fields(self): result = MerchantAccount.update("sandbox_sub_merchant_account", { "individual": { "first_name": "Jose" } }) self.assertTrue(result.is_success) def test_update_handles_validation_errors_for_blank_fields(self): params = { "individual": { "first_name": "", "last_name": "", "email": "", "phone": "", "date_of_birth": "", "ssn": "", "address": { "street_address": "", "postal_code": "", "locality": "", "region": "", }, }, "business": { "legal_name": "", "dba_name": "", "tax_id": "" }, "funding": { "destination": "", "routing_number": "", "account_number": "" } } result = MerchantAccount.update("sandbox_sub_merchant_account", params) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("first_name")[0].code, ErrorCodes.MerchantAccount.Individual.FirstNameIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("last_name")[0].code, ErrorCodes.MerchantAccount.Individual.LastNameIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("date_of_birth")[0].code, ErrorCodes.MerchantAccount.Individual.DateOfBirthIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("email")[0].code, ErrorCodes.MerchantAccount.Individual.EmailAddressIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Individual.Address.StreetAddressIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Individual.Address.PostalCodeIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("locality")[0].code, ErrorCodes.MerchantAccount.Individual.Address.LocalityIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Individual.Address.RegionIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("destination")[0].code, ErrorCodes.MerchantAccount.Funding.DestinationIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("first_name")[0].code, ErrorCodes.MerchantAccount.Individual.FirstNameIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("last_name")[0].code, ErrorCodes.MerchantAccount.Individual.LastNameIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("date_of_birth")[0].code, ErrorCodes.MerchantAccount.Individual.DateOfBirthIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("email")[0].code, ErrorCodes.MerchantAccount.Individual.EmailAddressIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Individual.Address.StreetAddressIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Individual.Address.PostalCodeIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("locality")[0].code, ErrorCodes.MerchantAccount.Individual.Address.LocalityIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Individual.Address.RegionIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("destination")[0].code, ErrorCodes.MerchantAccount.Funding.DestinationIsRequired) self.assertEqual(0, len(result.errors.for_object("merchant_account").on("base"))) def test_update_handles_validation_errors_for_invalid_fields(self): params = { "individual": { "first_name": "<>", "last_name": "<>", "email": "bad", "phone": "999", "address": { "street_address": "nope", "postal_code": "1", "region": "QQ", }, "date_of_birth": "hah", "ssn": "12345", }, "business": { "legal_name": "``{}", "dba_name": "{}``", "tax_id": "bad", "address": { "street_address": "nope", "postal_code": "1", "region": "QQ", }, }, "funding": { "destination": "MY WALLET", "routing_number": "LEATHER", "account_number": "BACK POCKET", "email": "BILLFOLD", "mobile_phone": "TRIFOLD" }, } result = MerchantAccount.update("sandbox_sub_merchant_account", params) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("first_name")[0].code, ErrorCodes.MerchantAccount.Individual.FirstNameIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("last_name")[0].code, ErrorCodes.MerchantAccount.Individual.LastNameIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("email")[0].code, ErrorCodes.MerchantAccount.Individual.EmailAddressIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("phone")[0].code, ErrorCodes.MerchantAccount.Individual.PhoneIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Individual.Address.StreetAddressIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Individual.Address.PostalCodeIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Individual.Address.RegionIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("individual").on("ssn")[0].code, ErrorCodes.MerchantAccount.Individual.SsnIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("legal_name")[0].code, ErrorCodes.MerchantAccount.Business.LegalNameIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("dba_name")[0].code, ErrorCodes.MerchantAccount.Business.DbaNameIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("tax_id")[0].code, ErrorCodes.MerchantAccount.Business.TaxIdIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").for_object("address").on("street_address")[0].code, ErrorCodes.MerchantAccount.Business.Address.StreetAddressIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").for_object("address").on("postal_code")[0].code, ErrorCodes.MerchantAccount.Business.Address.PostalCodeIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").for_object("address").on("region")[0].code, ErrorCodes.MerchantAccount.Business.Address.RegionIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("destination")[0].code, ErrorCodes.MerchantAccount.Funding.DestinationIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("routing_number")[0].code, ErrorCodes.MerchantAccount.Funding.RoutingNumberIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("account_number")[0].code, ErrorCodes.MerchantAccount.Funding.AccountNumberIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("email")[0].code, ErrorCodes.MerchantAccount.Funding.EmailAddressIsInvalid) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("mobile_phone")[0].code, ErrorCodes.MerchantAccount.Funding.MobilePhoneIsInvalid) self.assertEqual(0, len(result.errors.for_object("merchant_account").on("base"))) def test_update_handles_validation_errors_for_business_fields(self): result = MerchantAccount.update("sandbox_sub_merchant_account", { "business": { "legal_name": "", "tax_id": "111223333" } } ) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("legal_name")[0].code, ErrorCodes.MerchantAccount.Business.LegalNameIsRequiredWithTaxId) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("tax_id")[0].code, ErrorCodes.MerchantAccount.Business.TaxIdMustBeBlank) result = MerchantAccount.update("sandbox_sub_merchant_account", { "business": { "legal_name": "legal name", "tax_id": "" } } ) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("business").on("tax_id")[0].code, ErrorCodes.MerchantAccount.Business.TaxIdIsRequiredWithLegalName) def test_update_handles_validation_errors_for_funding_fields(self): result = MerchantAccount.update("sandbox_sub_merchant_account", { "funding": { "destination": MerchantAccount.FundingDestination.Bank, "routing_number": "", "account_number": "" } } ) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("routing_number")[0].code, ErrorCodes.MerchantAccount.Funding.RoutingNumberIsRequired) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("account_number")[0].code, ErrorCodes.MerchantAccount.Funding.AccountNumberIsRequired) result = MerchantAccount.update("sandbox_sub_merchant_account", { "funding": { "destination": MerchantAccount.FundingDestination.Email, "email": "" } } ) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("email")[0].code, ErrorCodes.MerchantAccount.Funding.EmailAddressIsRequired) result = MerchantAccount.update("sandbox_sub_merchant_account", { "funding": { "destination": MerchantAccount.FundingDestination.MobilePhone, "mobile_phone": "" } } ) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant_account").for_object("funding").on("mobile_phone")[0].code, ErrorCodes.MerchantAccount.Funding.MobilePhoneIsRequired) def test_find(self): result = MerchantAccount.create(self.VALID_APPLICATION_PARAMS) self.assertTrue(result.is_success) merchant_account_id = result.merchant_account.id MerchantAccount.find(merchant_account_id) def test_retrieves_master_merchant_account_currency_iso_code(self): merchant_account = MerchantAccount.find("sandbox_master_merchant_account") self.assertEqual(merchant_account.currency_iso_code, "USD") def test_return_all_merchant_accounts(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) code = TestHelper.create_grant(gateway, { "merchant_public_id": "integration_merchant_id", "scope": "read_write" }) result = gateway.oauth.create_token_from_code({ "code": code }) gateway = BraintreeGateway( access_token=result.credentials.access_token, environment=Environment.Development ) result = gateway.merchant_account.all() merchant_accounts = [ma for ma in result.merchant_accounts.items] self.assertTrue(len(merchant_accounts) > 20) def test_returns_merchant_account_with_correct_attributes(self): gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token ) result = gateway.merchant_account.all() merchant_accounts = [ma for ma in result.merchant_accounts.items] self.assertEqual(len(merchant_accounts), 1) merchant_account = merchant_accounts[0] self.assertEqual(merchant_account.currency_iso_code, "GBP") self.assertEqual(merchant_account.status, MerchantAccount.Status.Active) self.assertTrue(merchant_account.default) def test_find_404(self): with self.assertRaises(NotFoundError): MerchantAccount.find("not_a_real_id") def test_merchant_account_create_for_currency(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, ) result = gateway.merchant_account.create_for_currency({ "currency": "USD", "id": "custom_id" }) self.assertTrue(result.is_success) self.assertEqual(result.merchant_account.currency_iso_code, "USD") self.assertEqual(result.merchant_account.id, "custom_id") def test_merchant_account_create_for_currency_handles_invalid_currency(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, ) result = gateway.merchant_account.create_for_currency({ "currency": "DOES_NOT_COMPUTE" }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant").on("currency")[0].code, ErrorCodes.Merchant.CurrencyIsInvalid) def test_merchant_account_create_for_currency_handles_currency_requirement(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, ) result = gateway.merchant_account.create_for_currency({}) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant").on("currency")[0].code, ErrorCodes.Merchant.CurrencyIsRequired) def test_merchant_account_create_for_currency_merchant_account_already_existing_for_currency(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, ) result = gateway.merchant_account.create_for_currency({ "currency": "GBP", }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant").on("currency")[0].code, ErrorCodes.Merchant.MerchantAccountExistsForCurrency) def test_merchant_account_create_for_currency_merchant_account_already_existing_for_id(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) result = self.gateway.merchant.create({ "email": "name@email.com", "country_code_alpha3": "GBR", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, ) result = gateway.merchant_account.create_for_currency({ "currency": "GBP", "id": result.merchant.merchant_accounts[0].id }) self.assertFalse(result.is_success) self.assertEqual(result.errors.for_object("merchant").on("id")[0].code, ErrorCodes.Merchant.MerchantAccountExistsForId) braintree_python-4.31.0/tests/integration/test_oauth.py000066400000000000000000000155441471021343500234020ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.nonces import Nonces import sys import urllib.parse as urlparse class TestOAuthGateway(unittest.TestCase): def setUp(self): self.gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret" ) def test_create_token_from_code(self): code = TestHelper.create_grant(self.gateway, { "merchant_public_id": "integration_merchant_id", "scope": "read_write" }) result = self.gateway.oauth.create_token_from_code({ "code": code }) self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.refresh_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) def test_create_token_from_code_with_bad_parameters(self): result = self.gateway.oauth.create_token_from_code({ "code": "bad_code", "scope": "read_write" }) self.assertFalse(result.is_success) self.assertIn(result.message, "Invalid grant: code not found") credentials_code_errors = result.errors.for_object("credentials").on("code") self.assertEqual(1, len(credentials_code_errors)) self.assertEqual(ErrorCodes.OAuth.InvalidGrant, credentials_code_errors[0].code) def test_create_token_from_code_returns_helpful_error_with_bad_credentials(self): gateway = BraintreeGateway( access_token="access_token$development$integration_merchant_id$fb27c79dd", ) with self.assertRaises(ConfigurationError) as error: gateway.oauth.create_token_from_code({ "code": "some_code", "scope": "read_write" }) config_error = error.exception self.assertIn("client_id and client_secret are required", str(config_error)) def test_create_token_from_refresh_token(self): code = TestHelper.create_grant(self.gateway, { "merchant_public_id": "integration_merchant_id", "scope": "read_write" }) refresh_token = self.gateway.oauth.create_token_from_code({ "code": code, "scope": "read_write" }).credentials.refresh_token result = self.gateway.oauth.create_token_from_refresh_token({ "refresh_token": refresh_token }) self.assertTrue(result.is_success) credentials = result.credentials self.assertIsNotNone(credentials.access_token) self.assertIsNotNone(credentials.refresh_token) self.assertIsNotNone(credentials.expires_at) self.assertEqual("bearer", credentials.token_type) def test_revoke_access_token(self): code = TestHelper.create_grant(self.gateway, { "merchant_public_id": "integration_merchant_id", "scope": "read_write" }) access_token = self.gateway.oauth.create_token_from_code({ "code": code, "scope": "read_write" }).credentials.access_token result = self.gateway.oauth.revoke_access_token(access_token) self.assertTrue(result.is_success) with self.assertRaises(AuthenticationError): gateway = BraintreeGateway(access_token=access_token) gateway.customer.create() def test_connect_url(self): connect_url = self.gateway.oauth.connect_url({ "merchant_id": "integration_merchant_id", "redirect_uri": "http://bar.example.com", "scope": "read_write", "state": "baz_state", "landing_page": "login", "login_only": "true", "user": { "country": "USA", "email": "foo@example.com", "first_name": "Bob", "last_name": "Jones", "phone": "555-555-5555", "dob_year": "1970", "dob_month": "01", "dob_day": "01", "street_address": "222 W Merchandise Mart", "locality": "Chicago", "region": "IL", "postal_code": "60606" }, "business": { "name": "14 Ladders", "registered_as": "14.0 Ladders", "industry": "Ladders", "description": "We sell the best ladders", "street_address": "111 N Canal", "locality": "Chicago", "region": "IL", "postal_code": "60606", "country": "USA", "annual_volume_amount": "1000000", "average_transaction_amount": "100", "maximum_transaction_amount": "10000", "ship_physical_goods": "true", "fulfillment_completed_in": 7, "currency": "USD", "website": "http://example.com" }, "payment_methods": ["credit_card", "paypal"] }) query_string = urlparse.urlparse(connect_url)[4] params = urlparse.parse_qs(query_string) self.assertEqual(params["merchant_id"], ["integration_merchant_id"]) self.assertEqual(params["client_id"], ["client_id$development$integration_client_id"]) self.assertEqual(params["redirect_uri"], ["http://bar.example.com"]) self.assertEqual(params["scope"], ["read_write"]) self.assertEqual(params["state"], ["baz_state"]) self.assertEqual(params["landing_page"], ["login"]) self.assertEqual(params["login_only"], ["true"]) self.assertEqual(params["user[country]"], ["USA"]) self.assertEqual(params["business[name]"], ["14 Ladders"]) self.assertEqual(params["payment_methods[]"], ["credit_card", "paypal"]) def test_connect_url_limits_payment_methods(self): connect_url = self.gateway.oauth.connect_url({ "merchant_id": "integration_merchant_id", "redirect_uri": "http://bar.example.com", "scope": "read_write", "state": "baz_state", "payment_methods": ["credit_card"] }) query_string = urlparse.urlparse(connect_url)[4] params = urlparse.parse_qs(query_string) self.assertEqual(params["merchant_id"], ["integration_merchant_id"]) self.assertEqual(params["client_id"], ["client_id$development$integration_client_id"]) self.assertEqual(params["redirect_uri"], ["http://bar.example.com"]) self.assertEqual(params["payment_methods[]"], ["credit_card"]) def test_connect_url_doesnt_modify_options(self): options = {"payment_methods": ["credit_card"]} connect_url = self.gateway.oauth.connect_url(options) self.assertEqual(options, {"payment_methods": ["credit_card"]}) braintree_python-4.31.0/tests/integration/test_package_tracking.py000066400000000000000000000136001471021343500255260ustar00rootroot00000000000000import json from tests.test_helper import * from braintree.transaction import Transaction class PackageTracking(unittest.TestCase): def setUp(self): # Create successful transaction to obtain id result = Transaction.sale({ "amount": "100", "options": { "submit_for_settlement": True }, "paypal_account": { "payer_id": "fake-payer-id", "payment_id": "fake-payment-id", }, }) self.transaction = result.transaction def test_package_tracking_returns_error_when_transaction_id_is_not_present(self): with self.assertRaisesRegex(NotFoundError, "transaction with id ' ' not found"): Transaction.package_tracking(" ") def test_package_tracking_returns_api_error_when_carrier_is_not_present(self): # Create package without carrier package_result = Transaction.package_tracking( self.transaction.id, { "notify_payer": True, "tracking_number": "1Z5338FF0107231059", "line_items": [ { "product_code": "ABC 01", "name": "Best Product Ever", "quantity": "1", "description": "Best Description Ever", }, ], }) self.assertFalse(package_result.is_success) self.assertEqual(package_result.message, 'Carrier name is required.') def test_package_tracking_returns_api_error_when_tracking_number_is_not_present(self): # Create package without tracking_number package_result = Transaction.package_tracking( self.transaction.id, { "notify_payer": True, "carrier": "UPS", "line_items": [ ], }) self.assertFalse(package_result.is_success) self.assertEqual(package_result.message, 'Tracking number is required.') def test_package_tracking_adds_information_and_returns_valid_response(self): # Create first package with 2 products package_result_1 = Transaction.package_tracking( self.transaction.id, { "carrier": "UPS", "notify_payer": True, "tracking_number": "1Z5338FF0107231059", "line_items": [ { "product_code": "ABC 01", "name": "Best Product Ever", "quantity": "1", "description": "Best Description Ever", "upc_type": "UPC-A", "upc_code": "9248093u5", "image_url": "https://example.com/image.png" }, { "product_code": "ABC 02", "name": "Second best product ever", "quantity": "2", "description": "Second best description ever", "upc_type": "UPC-B", "upc_code": "0586967ABD", "image_url": "https://example.com/image2.png" } ], }) self.assertTrue(package_result_1.is_success) self.assertIsNotNone(package_result_1.transaction.packages[0]) self.assertEqual("UPS", package_result_1.transaction.packages[0].carrier) self.assertEqual("1Z5338FF0107231059", package_result_1.transaction.packages[0].tracking_number) self.assertIsNone(package_result_1.transaction.packages[0].paypal_tracker_id) # Create second package with 1 more product package_result_2 = Transaction.package_tracking( self.transaction.id, { "carrier": "FEDEX", "notify_payer": True, "tracking_number": "08594809767HGH0L", "line_items": [ { "product_code": "ABC 03", "name": "Worst Product Ever", "quantity": "25", "description": "Worst Description Ever", } ], }) self.assertTrue(package_result_2.is_success) self.assertIsNotNone(package_result_2.transaction.packages[1]) self.assertEqual("FEDEX", package_result_2.transaction.packages[1].carrier) self.assertEqual("08594809767HGH0L", package_result_2.transaction.packages[1].tracking_number) self.assertIsNone(package_result_2.transaction.packages[1].paypal_tracker_id) transaction_found = Transaction.find(package_result_2.transaction.id) self.assertTrue(2, len(transaction_found.packages)) self.assertIsNotNone(transaction_found.packages[0].id) self.assertEqual("UPS", transaction_found.packages[0].carrier) self.assertEqual("1Z5338FF0107231059", transaction_found.packages[0].tracking_number) # In test environment, since we do not have jobstream setup paypal tracker id is going to be nil, this is just to assert that we could access it self.assertIsNone(transaction_found.packages[0].paypal_tracker_id) self.assertIsNotNone(transaction_found.packages[1].id) self.assertEqual("FEDEX", transaction_found.packages[1].carrier) self.assertEqual("08594809767HGH0L", transaction_found.packages[1].tracking_number) self.assertIsNone(transaction_found.packages[1].paypal_tracker_id) def test_package_tracking_render_paypal_tracker_id(self): #find transaction with existing tracker created transaction_found = Transaction.find("package_tracking_tx") self.assertEqual("paypal_tracker_id_1", transaction_found.packages[0].paypal_tracker_id) self.assertEqual("paypal_tracker_id_2", transaction_found.packages[1].paypal_tracker_id) braintree_python-4.31.0/tests/integration/test_payment_method.py000066400000000000000000002221641471021343500252750ustar00rootroot00000000000000import time from datetime import datetime from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers from braintree.test.nonces import Nonces class TestPaymentMethod(unittest.TestCase): def test_create_with_three_d_secure_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.ThreeDSecureVisaFullAuthentication, "options": { "verify_card": "true", } }) self.assertTrue(result.is_success) three_d_secure_info = result.payment_method.verification.three_d_secure_info self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertIsInstance(three_d_secure_info.enrolled, str) self.assertIsInstance(three_d_secure_info.cavv, str) self.assertIsInstance(three_d_secure_info.xid, str) self.assertIsInstance(three_d_secure_info.eci_flag, str) self.assertIsInstance(three_d_secure_info.three_d_secure_version, str) def test_create_with_three_d_secure_pass_thru(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.Transactable, "three_d_secure_pass_thru": { "three_d_secure_version": "1.1.0", "eci_flag": "05", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": "true", } }) self.assertTrue(result.is_success) def test_create_with_three_d_secure_pass_thru_without_eci_flag(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.Transactable, "three_d_secure_pass_thru": { "three_d_secure_version": "1.1.0", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": "true", } }) self.assertFalse(result.is_success) self.assertEqual("EciFlag is required.", result.message) def test_create_with_paypal_billing_agreements_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalBillingAgreement }) self.assertTrue(result.is_success) created_account = result.payment_method self.assertEqual(PayPalAccount, created_account.__class__) self.assertEqual("jane.doe@paypal.com", created_account.email) self.assertNotEqual(created_account.image_url, None) found_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(created_account.token, found_account.token) self.assertEqual(created_account.customer_id, found_account.customer_id) def test_create_with_paypal_order_payment_nonce_and_paypal_options(self): customer_id = Customer.create().customer.id http = ClientApiHttp.create() status_code, payment_method_nonce = http.get_paypal_nonce({ "intent": "order", "payment-token": "fake-paypal-payment-token", "payer-id": "fake-paypal-payer-id" }) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": payment_method_nonce, "options": { "paypal": { "payee_email": "payee@example.com", "order_id": "merchant-order-id", "custom_field": "custom merchant field", "description": "merchant description", "amount": "1.23", "shipping": { "first_name": "Andrew", "last_name": "Mason", "company": "Braintree", "street_address": "456 W Main St", "extended_address": "Apt 2F", "locality": "Bartlett", "region": "IL", "postal_code": "60103", "country_name": "Mexico", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484" }, }, }, }) self.assertTrue(result.is_success) created_account = result.payment_method self.assertEqual(PayPalAccount, created_account.__class__) self.assertEqual("bt_buyer_us@paypal.com", created_account.email) self.assertNotEqual(created_account.image_url, None) self.assertNotEqual(created_account.payer_id, None) found_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(created_account.token, found_account.token) self.assertEqual(created_account.customer_id, found_account.customer_id) self.assertEqual(created_account.payer_id, found_account.payer_id) def test_create_with_paypal_refresh_token(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "paypal_refresh_token": "PAYPAL_REFRESH_TOKEN", }) self.assertTrue(result.is_success) created_account = result.payment_method self.assertEqual(PayPalAccount, created_account.__class__) self.assertEqual("B_FAKE_ID", created_account.billing_agreement_id) self.assertNotEqual(created_account.payer_id, None) found_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(created_account.token, found_account.token) self.assertEqual(created_account.customer_id, found_account.customer_id) self.assertEqual(created_account.billing_agreement_id, found_account.billing_agreement_id) self.assertEqual(created_account.payer_id, found_account.payer_id) def test_create_returns_validation_failures(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "options": {"validate": False} }) self.assertEqual(202, status_code) result = PaymentMethod.create({ "payment_method_nonce": nonce }) self.assertFalse(result.is_success) paypal_error_codes = [ error.code for error in result.errors.for_object("paypal_account").on("base") ] self.assertTrue(ErrorCodes.PayPalAccount.ConsentCodeOrAccessTokenIsRequired in paypal_error_codes) customer_error_codes = [ error.code for error in result.errors.for_object("paypal_account").on("customer_id") ] self.assertTrue(ErrorCodes.PayPalAccount.CustomerIdIsRequiredForVaulting in customer_error_codes) def test_create_and_make_default(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2014", }) self.assertTrue(credit_card_result.is_success) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment, "options": {"make_default": True}, }) self.assertTrue(result.is_success) self.assertTrue(result.payment_method.default) def test_create_and_set_token(self): customer_id = Customer.create().customer.id token = str(random.randint(1, 1000000)) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment, "token": token }) self.assertTrue(result.is_success) self.assertEqual(token, result.payment_method.token) def test_create_with_paypal_one_time_nonce_fails(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalOneTimePayment }) self.assertFalse(result.is_success) base_errors = result.errors.for_object("paypal_account").on("base") self.assertEqual(1, len(base_errors)) self.assertEqual(ErrorCodes.PayPalAccount.CannotVaultOneTimeUsePayPalAccount, base_errors[0].code) def test_create_with_credit_card_nonce(self): http = ClientApiHttp.create() status_code, nonce = http.get_credit_card_nonce({ "number": "4111111111111111", "expirationMonth": "12", "expirationYear": "2020", "options": {"validate": False} }) self.assertEqual(202, status_code) customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce }) self.assertTrue(result.is_success) created_credit_card = result.payment_method self.assertEqual(CreditCard, created_credit_card.__class__) self.assertEqual("411111", created_credit_card.bin) found_credit_card = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_credit_card) self.assertEqual(found_credit_card.token, created_credit_card.token) self.assertEqual(found_credit_card.customer_id, created_credit_card.customer_id) def test_create_with_fake_apple_pay_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.ApplePayMasterCard }) self.assertTrue(result.is_success) apple_pay_card = result.payment_method self.assertIsInstance(apple_pay_card, ApplePayCard) self.assertNotEqual(apple_pay_card.bin, None) self.assertNotEqual(apple_pay_card.token, None) self.assertNotEqual(apple_pay_card.prepaid, None) self.assertNotEqual(apple_pay_card.healthcare, None) self.assertNotEqual(apple_pay_card.debit, None) self.assertNotEqual(apple_pay_card.durbin_regulated, None) self.assertNotEqual(apple_pay_card.commercial, None) self.assertNotEqual(apple_pay_card.payroll, None) self.assertNotEqual(apple_pay_card.issuing_bank, None) self.assertNotEqual(apple_pay_card.country_of_issuance, None) self.assertNotEqual(apple_pay_card.product_id, None) self.assertNotEqual(apple_pay_card.last_4, None) self.assertNotEqual(apple_pay_card.card_type, 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_apple_pay_mpan_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.ApplePayMpan }) self.assertTrue(result.is_success) apple_pay_card = result.payment_method self.assertIsInstance(apple_pay_card, ApplePayCard) self.assertNotEqual(apple_pay_card.bin, None) self.assertNotEqual(apple_pay_card.token, None) self.assertNotEqual(apple_pay_card.prepaid, None) self.assertNotEqual(apple_pay_card.healthcare, None) self.assertNotEqual(apple_pay_card.debit, None) self.assertNotEqual(apple_pay_card.durbin_regulated, None) self.assertNotEqual(apple_pay_card.commercial, None) self.assertNotEqual(apple_pay_card.payroll, None) self.assertNotEqual(apple_pay_card.issuing_bank, None) self.assertNotEqual(apple_pay_card.country_of_issuance, None) self.assertNotEqual(apple_pay_card.product_id, None) self.assertNotEqual(apple_pay_card.last_4, None) self.assertNotEqual(apple_pay_card.card_type, None) self.assertNotEqual(apple_pay_card.merchant_token_identifier, None) self.assertNotEqual(apple_pay_card.source_card_last4, None) self.assertEqual(apple_pay_card.customer_id, customer_id) self.assertEqual(ApplePayCard.CardType.Visa, apple_pay_card.card_type) self.assertEqual("Visa 8886", apple_pay_card.payment_instrument_name) self.assertEqual("Visa 8886", apple_pay_card.source_description) self.assertTrue(apple_pay_card.default) self.assertIn("apple_pay", apple_pay_card.image_url) self.assertTrue(int(apple_pay_card.expiration_month) > 0) self.assertTrue(int(apple_pay_card.expiration_year) > 0) def test_create_with_fake_android_pay_proxy_card_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.AndroidPayCardDiscover }) self.assertTrue(result.is_success) android_pay_card = result.payment_method self.assertIsInstance(android_pay_card, AndroidPayCard) self.assertNotEqual(android_pay_card.token, None) self.assertEqual(customer_id, android_pay_card.customer_id) self.assertEqual(CreditCard.CardType.Discover, android_pay_card.virtual_card_type) self.assertEqual("1117", android_pay_card.virtual_card_last_4) self.assertEqual("Discover 1111", android_pay_card.source_description) self.assertEqual(CreditCard.CardType.Discover, android_pay_card.source_card_type) self.assertEqual("1111", android_pay_card.source_card_last_4) self.assertEqual("1117", android_pay_card.last_4) self.assertEqual(CreditCard.CardType.Discover, android_pay_card.card_type) self.assertTrue(android_pay_card.default) self.assertIn("android_pay", android_pay_card.image_url) self.assertTrue(int(android_pay_card.expiration_month) > 0) self.assertTrue(int(android_pay_card.expiration_year) > 0) self.assertIsInstance(android_pay_card.created_at, datetime) self.assertIsInstance(android_pay_card.updated_at, datetime) self.assertEqual("601111", android_pay_card.bin) self.assertEqual("google_transaction_id", android_pay_card.google_transaction_id) self.assertFalse(android_pay_card.is_network_tokenized) def test_create_with_fake_android_pay_network_token_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.AndroidPayCardMasterCard }) self.assertTrue(result.is_success) android_pay_card = result.payment_method self.assertIsInstance(android_pay_card, AndroidPayCard) self.assertNotEqual(android_pay_card.token, None) self.assertEqual(customer_id, android_pay_card.customer_id) self.assertEqual(CreditCard.CardType.MasterCard, android_pay_card.virtual_card_type) self.assertEqual("4444", android_pay_card.virtual_card_last_4) self.assertEqual("MasterCard 4444", android_pay_card.source_description) self.assertEqual(CreditCard.CardType.MasterCard, android_pay_card.source_card_type) self.assertEqual("4444", android_pay_card.source_card_last_4) self.assertEqual("4444", android_pay_card.last_4) self.assertEqual(CreditCard.CardType.MasterCard, android_pay_card.card_type) self.assertTrue(android_pay_card.default) self.assertIn("android_pay", android_pay_card.image_url) self.assertTrue(int(android_pay_card.expiration_month) > 0) self.assertTrue(int(android_pay_card.expiration_year) > 0) self.assertIsInstance(android_pay_card.created_at, datetime) self.assertIsInstance(android_pay_card.updated_at, datetime) self.assertEqual("555555", android_pay_card.bin) self.assertEqual("google_transaction_id", android_pay_card.google_transaction_id) self.assertTrue(android_pay_card.is_network_tokenized) self.assertNotEqual(android_pay_card.bin, None) self.assertNotEqual(android_pay_card.token, None) self.assertNotEqual(android_pay_card.prepaid, None) self.assertNotEqual(android_pay_card.healthcare, None) self.assertNotEqual(android_pay_card.debit, None) self.assertNotEqual(android_pay_card.durbin_regulated, None) self.assertNotEqual(android_pay_card.commercial, None) self.assertNotEqual(android_pay_card.payroll, None) self.assertNotEqual(android_pay_card.issuing_bank, None) self.assertNotEqual(android_pay_card.country_of_issuance, None) self.assertNotEqual(android_pay_card.product_id, None) self.assertNotEqual(android_pay_card.last_4, None) self.assertNotEqual(android_pay_card.card_type, None) def test_create_with_fake_amex_express_checkout_card_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.AmexExpressCheckoutCard }) self.assertTrue(result.is_success) amex_express_checkout_card = result.payment_method self.assertIsInstance(amex_express_checkout_card, AmexExpressCheckoutCard) self.assertNotEqual(amex_express_checkout_card.token, None) self.assertTrue(amex_express_checkout_card.default) self.assertEqual("American Express", amex_express_checkout_card.card_type) self.assertRegex(amex_express_checkout_card.bin, r"\A\d{6}\Z") self.assertRegex(amex_express_checkout_card.expiration_month, r"\A\d{2}\Z") self.assertRegex(amex_express_checkout_card.expiration_year, r"\A\d{4}\Z") self.assertRegex(amex_express_checkout_card.card_member_number, r"\A\d{4}\Z") self.assertRegex(amex_express_checkout_card.card_member_expiry_date, r"\A\d{2}/\d{2}\Z") self.assertRegex(amex_express_checkout_card.source_description, r"\AAmEx \d{4}\Z") self.assertRegex(amex_express_checkout_card.image_url, r"\.png") self.assertEqual(customer_id, amex_express_checkout_card.customer_id) def test_create_with_venmo_account_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.VenmoAccount, }) self.assertTrue(result.is_success) venmo_account = result.payment_method self.assertIsInstance(venmo_account, VenmoAccount) self.assertTrue(venmo_account.default) self.assertIsNotNone(venmo_account.token) self.assertEqual("venmojoe", venmo_account.username) self.assertEqual("1234567891234567891", venmo_account.venmo_user_id) self.assertEqual("Venmo Account: venmojoe", venmo_account.source_description) self.assertRegex(venmo_account.image_url, r"\.png") self.assertEqual(customer_id, venmo_account.customer_id) def test_create_with_abstract_payment_method_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.AbstractTransactable }) self.assertTrue(result.is_success) payment_method = result.payment_method self.assertNotEqual(None, payment_method) self.assertNotEqual(None, payment_method.token) self.assertEqual(customer_id, payment_method.customer_id) def test_create_with_custom_card_verification_amount(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id client_token = json.loads(TestHelper.generate_decoded_client_token()) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, nonce = http.get_credit_card_nonce({ "number": "4000111111111115", "expirationMonth": "11", "expirationYear": "2099" }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce, "options": { "verify_card": "true", "verification_amount": "1.02" } }) self.assertFalse(result.is_success) verification = result.credit_card_verification self.assertEqual(CreditCardVerification.Status.ProcessorDeclined, verification.status) def test_create_respects_verify_card_and_verification_merchant_account_id_when_outside_nonce(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id client_token = json.loads(TestHelper.generate_decoded_client_token()) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) status_code, nonce = http.get_credit_card_nonce({ "number": "4000111111111115", "expirationMonth": "11", "expirationYear": "2099" }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "options": { "verify_card": "true", "verification_merchant_account_id": TestHelper.non_default_merchant_account_id } }) self.assertFalse(result.is_success) self.assertTrue(result.credit_card_verification.status == Transaction.Status.ProcessorDeclined) self.assertTrue(result.credit_card_verification.processor_response_code == "2000") self.assertTrue(result.credit_card_verification.processor_response_text == "Do Not Honor") self.assertTrue(result.credit_card_verification.merchant_account_id == TestHelper.non_default_merchant_account_id) def test_create_includes_risk_data_when_skip_advanced_fraud_checking_is_false(self): with FraudProtectionEnterpriseIntegrationMerchant(): 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": "4111111111111111", "expirationMonth": "11", "expirationYear": "2099", }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce, "options": { "verify_card": True, "skip_advanced_fraud_checking": False }, }) self.assertTrue(result.is_success) verification = result.payment_method.verification self.assertIsInstance(verification.risk_data, RiskData) def test_create_does_not_include_risk_data_when_skip_advanced_fraud_checking_is_true(self): with FraudProtectionEnterpriseIntegrationMerchant(): 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": "4111111111111111", "expirationMonth": "11", "expirationYear": "2099", }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce, "options": { "verify_card": True, "skip_advanced_fraud_checking": True }, }) self.assertTrue(result.is_success) verification = result.payment_method.verification self.assertIsNone(verification.risk_data) 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_respects_fail_on_duplicate_payment_method_for_customer_when_included_outside_of_the_nonce(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2012" }) self.assertTrue(credit_card_result.is_success) config = Configuration.instantiate() 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": "4111111111111111", "expiration_date": "05/2014" }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "options": { "fail_on_duplicate_payment_method_for_customer": "true" } }) self.assertFalse(result.is_success) self.assertTrue(result.errors.deep_errors[0].code == "81763") 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", "international_phone": {"country_code": "1", "national_number": "3121234567"} } }) 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") self.assertEqual("1", found_credit_card.billing_address.international_phone["country_code"]) self.assertEqual("3121234567", found_credit_card.billing_address.international_phone["national_number"]) 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", "fail_on_duplicate_payment_method_for_customer": "true", "verification_merchant_account_id": "not_a_real_merchant_account_id" } }) self.assertTrue(result.is_success) def test_create_for_paypal_ignores_passed_billing_address_id(self): nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code" }) customer_id = Customer.create().customer.id result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "billing_address_id": "address_id" }) self.assertTrue(result.is_success) self.assertTrue(isinstance(result.payment_method, PayPalAccount)) self.assertFalse(result.payment_method.image_url is None) token = result.payment_method.token found_paypal_account = PayPalAccount.find(token) self.assertFalse(found_paypal_account is None) def test_create_for_paypal_ignores_passed_billing_address_params(self): nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "PAYPAL_CONSENT_CODE" }) customer_id = Customer.create().customer.id result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id, "billing_address": { "street_address": "123 Abc Way" } }) self.assertTrue(result.is_success) self.assertTrue(isinstance(result.payment_method, PayPalAccount)) self.assertFalse(result.payment_method.image_url is None) token = result.payment_method.token found_paypal_account = PayPalAccount.find(token) self.assertFalse(found_paypal_account is None) def test_create_payment_method_with_account_type_debit(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id client_token = json.loads(TestHelper.generate_decoded_client_token()) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing", }) status_code, nonce = http.get_credit_card_nonce({ "number": CreditCardNumbers.Hiper, "expirationMonth": "11", "expirationYear": "2099", }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce, "options": { "verify_card": "true", "verification_merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "verification_amount": "1.02", "verification_account_type": "debit", }, }) self.assertTrue(result.is_success) self.assertEqual("debit", result.payment_method.verifications[0]["credit_card"]["account_type"]) def test_create_payment_method_with_account_type_credit(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id client_token = json.loads(TestHelper.generate_decoded_client_token()) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing", }) status_code, nonce = http.get_credit_card_nonce({ "number": CreditCardNumbers.Hiper, "expirationMonth": "11", "expirationYear": "2099", }) self.assertTrue(status_code == 201) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": nonce, "options": { "verify_card": "true", "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_amount": "1.02", "verification_account_type": "credit", }, }) self.assertTrue(result.is_success) self.assertEqual("credit", result.payment_method.verifications[0]["credit_card"]["account_type"]) def test_create_credit_card_with_account_type_debit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", "options": { "verification_merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "verification_account_type": "debit", "verify_card": True, } }) self.assertTrue(result.is_success) self.assertEqual("debit", result.credit_card.verifications[0]["credit_card"]["account_type"]) def test_create_credit_card_with_account_type_credit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", "options": { "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_account_type": "credit", "verify_card": True, } }) self.assertTrue(result.is_success) self.assertEqual("credit", result.credit_card.verifications[0]["credit_card"]["account_type"]) def test_create_with_usupported_merchant_account(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", "options": { "verification_account_type": "debit", "verify_card": True, } }) self.assertFalse(result.is_success) errors = result.errors.for_object("credit_card").for_object("options").on("verification_account_type") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.CreditCard.VerificationAccountTypeNotSupported, errors[0].code) def test_create_with_invalid_account_type(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Hiper, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", "options": { "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_account_type": "invalid", "verify_card": True, } }) self.assertFalse(result.is_success) errors = result.errors.for_object("credit_card").for_object("options").on("verification_account_type") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.CreditCard.VerificationAccountTypeIsInvald, errors[0].code) def test_find_returns_an_abstract_payment_method(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.AbstractTransactable }) self.assertTrue(result.is_success) found_payment_method = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_payment_method) self.assertEqual(found_payment_method.token, result.payment_method.token) def test_find_returns_a_paypal_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) found_account = PaymentMethod.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(PayPalAccount, found_account.__class__) self.assertTrue(found_account.email) def test_find_returns_a_credit_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe" }) self.assertTrue(result.is_success) found_credit_card = PaymentMethod.find(result.credit_card.token) self.assertNotEqual(None, found_credit_card) self.assertEqual(CreditCard, found_credit_card.__class__) self.assertEqual("411111", found_credit_card.bin) def test_find_returns_an_android_pay_card(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.AndroidPayCard }) self.assertTrue(result.is_success) android_pay_card = result.payment_method found_android_pay_card = PaymentMethod.find(android_pay_card.token) self.assertNotEqual(None, found_android_pay_card) self.assertEqual(AndroidPayCard, found_android_pay_card.__class__) self.assertEqual(found_android_pay_card.token, android_pay_card.token) def test_find_returns_an_apple_pay_mpan_card(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.ApplePayMpan }) self.assertTrue(result.is_success) apple_pay_card = result.payment_method found_apple_pay_card = PaymentMethod.find(apple_pay_card.token) self.assertIsNotNone(found_apple_pay_card) self.assertEqual(ApplePayCard, found_apple_pay_card.__class__) self.assertEqual(found_apple_pay_card.token, apple_pay_card.token) self.assertEqual(apple_pay_card.merchant_token_identifier, "DNITHE302308980427388297") self.assertEqual(apple_pay_card.source_card_last4, "2006") def test_delete_customer_with_path_traversal(self): try: customer = Customer.create({"first_name":"Waldo"}).customer PaymentMethod.delete("../../customers/{}".format(customer.id)) except NotFoundError: pass found_customer = Customer.find(customer.id) self.assertNotEqual(None, found_customer) self.assertEqual("Waldo", found_customer.first_name) def test_delete_deletes_a_credit_card(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe" }) self.assertTrue(result.is_success) delete_result = PaymentMethod.delete(result.credit_card.token) self.assertTrue(delete_result.is_success) self.assertRaises(NotFoundError, PaymentMethod.find, result.credit_card.token) def test_delete_deletes_a_paypal_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) delete_result = PaymentMethod.delete(result.payment_method.token, {"revoke_all_grants": False}) self.assertTrue(delete_result.is_success) self.assertRaises(NotFoundError, PaymentMethod.find, result.payment_method.token) def test_update_credit_cards_updates_the_credit_card(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Original Holder", "customer_id": customer_id, "cvv": "123", "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.MasterCard, "expiration_date": "06/2013" }) self.assertTrue(update_result.is_success) self.assertTrue(update_result.payment_method.token == credit_card_result.credit_card.token) updated_credit_card = update_result.payment_method self.assertTrue(updated_credit_card.bin == CreditCardNumbers.MasterCard[:6]) self.assertTrue(updated_credit_card.last_4 == CreditCardNumbers.MasterCard[-4:]) self.assertTrue(updated_credit_card.expiration_date == "06/2013") def test_update_with_three_d_secure_pass_thru(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", "three_d_secure_pass_thru": { "three_d_secure_version": "1.1.0", "eci_flag": "05", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": "true", } }) self.assertTrue(update_result.is_success) def test_create_with_three_d_secure_pass_thru_without_eci_flag(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", "three_d_secure_pass_thru": { "three_d_secure_version": "1.1.0", "cavv": "some-cavv", "xid": "some-xid" }, "options": { "verify_card": "true", } }) self.assertFalse(update_result.is_success) self.assertEqual("EciFlag is required.", update_result.message) def test_update_credit_cards_with_account_type_credit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", }) update_result = PaymentMethod.update(result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.Hiper, "expiration_date": "06/2013", "options": { "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_account_type": "credit", "verify_card": True, } }) self.assertTrue(update_result.is_success) self.assertEqual("credit", update_result.payment_method.verification.credit_card["account_type"]) def test_update_credit_cards_with_account_type_debit(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", }) update_result = PaymentMethod.update(result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.Hiper, "expiration_date": "06/2013", "options": { "verification_merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "verification_account_type": "debit", "verify_card": True, } }) self.assertTrue(update_result.is_success) self.assertEqual("debit", update_result.payment_method.verification.credit_card["account_type"]) def test_update_credit_cards_with_invalid_account_type(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", }) update_result = PaymentMethod.update(result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.Hiper, "expiration_date": "06/2013", "options": { "verification_merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "verification_account_type": "invalid", "verify_card": True, } }) self.assertFalse(update_result.is_success) errors = update_result.errors.for_object("credit_card").for_object("options").on("verification_account_type") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.CreditCard.VerificationAccountTypeIsInvald, errors[0].code) def test_update_credit_cards_with_unsupported_merchant_account(self): customer = Customer.create().customer result = CreditCard.create({ "customer_id": customer.id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "cvv": "100", "cardholder_name": "John Doe", }) update_result = PaymentMethod.update(result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.Visa, "expiration_date": "06/2013", "options": { "verification_account_type": "debit", "verify_card": True, } }) self.assertFalse(update_result.is_success) errors = update_result.errors.for_object("credit_card").for_object("options").on("verification_account_type") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.CreditCard.VerificationAccountTypeNotSupported, errors[0].code) def test_update_creates_a_new_billing_address_by_default(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012", "billing_address": { "street_address": "123 Nigeria Ave" } }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "billing_address": { "region": "IL", "international_phone": {"country_code": "1", "national_number": "3121234567"} } }) self.assertTrue(update_result.is_success) updated_credit_card = update_result.payment_method self.assertTrue(updated_credit_card.billing_address.region == "IL") self.assertEqual("1", updated_credit_card.billing_address.international_phone["country_code"]) self.assertEqual("3121234567", updated_credit_card.billing_address.international_phone["national_number"]) self.assertTrue(updated_credit_card.billing_address.street_address is None) self.assertFalse(updated_credit_card.billing_address.id == credit_card_result.credit_card.billing_address.id) def test_update_updates_the_billing_address_if_option_is_specified(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012", "billing_address": { "street_address": "123 Nigeria Ave" } }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "billing_address": { "region": "IL", "options": { "update_existing": "true" } } }) self.assertTrue(update_result.is_success) updated_credit_card = update_result.payment_method self.assertTrue(updated_credit_card.billing_address.region == "IL") self.assertTrue(updated_credit_card.billing_address.street_address == "123 Nigeria Ave") self.assertTrue(updated_credit_card.billing_address.id == credit_card_result.credit_card.billing_address.id) def test_update_updates_the_country_via_codes(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012", "billing_address": { "street_address": "123 Nigeria Ave" } }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "billing_address": { "country_name": "American Samoa", "country_code_alpha2": "AS", "country_code_alpha3": "ASM", "country_code_numeric": "016", "options": { "update_existing": "true" } } }) self.assertTrue(update_result.is_success) updated_credit_card = update_result.payment_method self.assertTrue(updated_credit_card.billing_address.country_name == "American Samoa") self.assertTrue(updated_credit_card.billing_address.country_code_alpha2 == "AS") self.assertTrue(updated_credit_card.billing_address.country_code_alpha3 == "ASM") self.assertTrue(updated_credit_card.billing_address.country_code_numeric == "016") def test_update_can_pass_expiration_month_and_expiration_year(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "number": CreditCardNumbers.MasterCard, "expiration_month": "07", "expiration_year": "2011" }) self.assertTrue(update_result.is_success) self.assertTrue(update_result.payment_method.token == credit_card_result.credit_card.token) updated_credit_card = update_result.payment_method self.assertTrue(updated_credit_card.expiration_month == "07") self.assertTrue(updated_credit_card.expiration_year == "2011") self.assertTrue(updated_credit_card.expiration_date == "07/2011") def test_update_verifies_the_update_if_options_verify_card_is_true(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Original Holder", "customer_id": customer_id, "cvv": "123", "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "cardholder_name": "New Holder", "cvv": "456", "number": CreditCardNumbers.FailsSandboxVerification.MasterCard, "expiration_date": "06/2013", "options": { "verify_card": "true" } }) self.assertFalse(update_result.is_success) self.assertTrue(update_result.credit_card_verification.status == CreditCardVerification.Status.ProcessorDeclined) self.assertTrue(update_result.credit_card_verification.gateway_rejection_reason is None) def test_update_can_pass_custom_verification_amount(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Card Holder", "customer_id": customer_id, "cvv": "123", "number": CreditCardNumbers.Visa, "expiration_date": "05/2020" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "payment_method_nonce": Nonces.ProcessorDeclinedMasterCard, "options": { "verify_card": "true", "verification_amount": "2.34" } }) self.assertFalse(update_result.is_success) self.assertTrue(update_result.credit_card_verification.status == CreditCardVerification.Status.ProcessorDeclined) self.assertTrue(update_result.credit_card_verification.gateway_rejection_reason is None) def test_update_includes_risk_data_when_skip_advanced_fraud_checking_is_false(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Card Holder", "customer_id": customer_id, "cvv": "123", "number": "4111111111111111", "expiration_date": "05/2020" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "expiration_date": "10/2020", "options": { "verify_card": True, "skip_advanced_fraud_checking": False }, }) self.assertTrue(update_result.is_success) verification = update_result.payment_method.verification self.assertIsInstance(verification.risk_data, RiskData) def test_update_does_not_include_risk_data_when_skip_advanced_fraud_checking_is_true(self): with FraudProtectionEnterpriseIntegrationMerchant(): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Card Holder", "customer_id": customer_id, "cvv": "123", "number": "4111111111111111", "expiration_date": "05/2020" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "expiration_date": "10/2020", "options": { "verify_card": True, "skip_advanced_fraud_checking": True }, }) self.assertTrue(update_result.is_success) verification = update_result.payment_method.verification self.assertIsNone(verification.risk_data) def test_update_can_update_the_billing_address(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Original Holder", "customer_id": customer_id, "cvv": "123", "number": CreditCardNumbers.Visa, "expiration_date": "05/2012", "billing_address": { "first_name": "Old First Name", "last_name": "Old Last Name", "company": "Old Company", "street_address": "123 Old St", "extended_address": "Apt Old", "locality": "Old City", "region": "Old State", "postal_code": "12345", "country_name": "Canada" } }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "options": {"verify_card": "false"}, "billing_address": { "first_name": "New First Name", "last_name": "New Last Name", "company": "New Company", "street_address": "123 New St", "extended_address": "Apt New", "locality": "New City", "region": "New State", "postal_code": "56789", "country_name": "United States of America" } }) self.assertTrue(update_result.is_success) address = update_result.payment_method.billing_address self.assertTrue(address.first_name == "New First Name") self.assertTrue(address.last_name == "New Last Name") self.assertTrue(address.company == "New Company") self.assertTrue(address.street_address == "123 New St") self.assertTrue(address.extended_address == "Apt New") self.assertTrue(address.locality == "New City") self.assertTrue(address.region == "New State") self.assertTrue(address.postal_code == "56789") self.assertTrue(address.country_name == "United States of America") def test_update_returns_an_error_response_if_invalid(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "cardholder_name": "Original Holder", "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" }) update_result = PaymentMethod.update(credit_card_result.credit_card.token, { "cardholder_name": "New Holder", "number": "invalid", "expiration_date": "05/2014", }) self.assertFalse(update_result.is_success) number_errors = update_result.errors.for_object("credit_card").on("number") self.assertEqual(1, len(number_errors)) self.assertEqual("Credit card number must be 12-19 digits.", number_errors[0].message) def test_update_can_update_the_default(self): customer_id = Customer.create().customer.id card1 = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }).credit_card card2 = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }).credit_card self.assertTrue(card1.default) self.assertFalse(card2.default) PaymentMethod.update(card2.token, { "options": {"make_default": True} }) self.assertFalse(CreditCard.find(card1.token).default) self.assertTrue(CreditCard.find(card2.token).default) def test_update_updates_a_paypal_accounts_token(self): customer_id = Customer.create().customer.id original_token = "paypal-account-" + str(int(time.time())) nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code", "token": original_token }) original_result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id }) updated_token = "UPDATED_TOKEN-" + str(random.randint(0, 100000000)) PaymentMethod.update( original_token, {"token": updated_token} ) updated_paypal_account = PayPalAccount.find(updated_token) self.assertTrue(updated_paypal_account.email == original_result.payment_method.email) self.assertRaises(NotFoundError, PaymentMethod.find, original_token) def test_update_can_make_a_paypal_account_the_default_payment_method(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "options": {"make_default": "true"} }) self.assertTrue(credit_card_result.is_success) nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code" }) original_token = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id }).payment_method.token PaymentMethod.update( original_token, {"options": {"make_default": "true"}} ) updated_paypal_account = PayPalAccount.find(original_token) self.assertTrue(updated_paypal_account.default) def test_update_fails_to_updates_a_paypal_accounts_token_with(self): customer_id = Customer.create().customer.id first_token = "paypal-account-" + str(random.randint(0, 100000000)) second_token = "paypal-account-" + str(random.randint(0, 100000000)) first_nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code", "token": first_token }) PaymentMethod.create({ "payment_method_nonce": first_nonce, "customer_id": customer_id }) second_nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code", "token": second_token }) PaymentMethod.create({ "payment_method_nonce": second_nonce, "customer_id": customer_id }) updated_result = PaymentMethod.update( first_token, {"token": second_token} ) self.assertFalse(updated_result.is_success) errors = updated_result.errors.deep_errors self.assertEqual(1, len(errors)) self.assertEqual("92906", errors[0].code) def test_update_respects_fail_on_duplicate_payment_method_for_customer_when_included_outside_of_the_nonce(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2012" }) self.assertTrue(credit_card_result.is_success) credit_card_result_2 = CreditCard.create({ "customer_id": customer_id, "number": "4000111111111115", "expiration_date": "05/2012" }) self.assertTrue(credit_card_result_2.is_success) update_result = PaymentMethod.update(credit_card_result_2.credit_card.token, { "cardholder_name": "New Holder", "number": "4111111111111111", "expiration_date": "05/2014", "options": { "fail_on_duplicate_payment_method_for_customer": "true" } }) self.assertFalse(update_result.is_success) self.assertTrue(update_result.errors.deep_errors[0].code == "81763") def test_payment_method_grant_raises_on_non_existent_tokens(self): granting_gateway, _ = TestHelper.create_payment_method_grant_fixtures() self.assertRaises(NotFoundError, granting_gateway.payment_method.grant, "non-existant-token", False) def test_payment_method_grant_returns_one_time_nonce(self): """ Payment method grant returns a nonce that is transactable by a partner merchant exactly once """ granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, { "allow_vaulting": False }); self.assertTrue(grant_result.is_success) result = Transaction.sale({ "payment_method_nonce": grant_result.payment_method_nonce.nonce, "amount": TransactionAmounts.Authorize }) self.assertTrue(result.is_success) result = Transaction.sale({ "payment_method_nonce": grant_result.payment_method_nonce.nonce, "amount": TransactionAmounts.Authorize }) self.assertFalse(result.is_success) def test_payment_method_grant_returns_a_nonce_that_is_not_vaultable(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, False) customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": grant_result.payment_method_nonce.nonce }) self.assertFalse(result.is_success) def test_payment_method_grant_returns_a_nonce_that_is_vaultable(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, { "allow_vaulting": True }) customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": grant_result.payment_method_nonce.nonce }) self.assertTrue(result.is_success) def test_payment_method_revoke_renders_a_granted_nonce_unusable(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token) revoke_result = granting_gateway.payment_method.revoke(credit_card.token) self.assertTrue(revoke_result.is_success) result = Transaction.sale({ "payment_method_nonce": grant_result.payment_method_nonce.nonce, "amount": TransactionAmounts.Authorize }) self.assertFalse(result.is_success) def test_payment_method_revoke_raises_on_non_existent_tokens(self): granting_gateway, _ = TestHelper.create_payment_method_grant_fixtures() self.assertRaises(NotFoundError, granting_gateway.payment_method.revoke, "non-existant-token") def test_vault_sepa_direct_debit_payment_method_with_fake_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "payment_method_nonce": Nonces.SepaDirectDebit, "customer_id": customer_id, }) self.assertTrue(result.is_success) def test_delete_sepa_direct_debit_payment_method(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "payment_method_nonce": Nonces.SepaDirectDebit, "customer_id": customer_id, }) self.assertTrue(result.is_success) delete_result = PaymentMethod.delete(result.payment_method.token) self.assertRaises(NotFoundError, PaymentMethod.find, result.payment_method.token) braintree_python-4.31.0/tests/integration/test_payment_method_nonce.py000066400000000000000000000301621471021343500264520ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.nonces import Nonces from datetime import date class TestPaymentMethodNonce(unittest.TestCase): indian_payment_token = "india_visa_credit" european_payment_token = "european_visa_credit" indian_merchant_token = "india_three_d_secure_merchant_account" european_merchant_token = "european_three_d_secure_merchant_account" amount_threshold_for_rbi = 2000 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_nonce_from_payment_method_with_invalid_params(self): nonce_request = { "merchant_account_id": self.indian_merchant_token, "authentication_insight": True, "invalid_keys": "foo" } params = {"payment_method_nonce": nonce_request} with self.assertRaises(KeyError): PaymentMethodNonce.create(self.indian_payment_token, params) def test_create_nonce_with_auth_insight_regulation_environment_unavailable(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "05/2014", }) auth_insight_result = self._request_authentication_insights(self.indian_merchant_token, credit_card_result.credit_card.token) self.assertEqual("unavailable", auth_insight_result["regulation_environment"]) def test_create_nonce_with_auth_insight_regulation_environment_unregulated(self): auth_insight_result = self._request_authentication_insights(self.european_merchant_token, self.indian_payment_token) self.assertEqual("unregulated", auth_insight_result["regulation_environment"]) def test_create_nonce_with_auth_insight_regulation_environment_psd2(self): auth_insight_result = self._request_authentication_insights(self.european_merchant_token, self.european_payment_token) self.assertEqual("psd2", auth_insight_result["regulation_environment"]) def test_create_nonce_with_auth_insight_regulation_environment_rbi(self): auth_insight_result = self._request_authentication_insights(self.indian_merchant_token, self.indian_payment_token, self.amount_threshold_for_rbi) self.assertEqual("rbi", auth_insight_result["regulation_environment"]) def test_create_nonce_with_auth_insight_sca_indicator_unavailable(self): auth_insight_result = self._request_authentication_insights(self.indian_merchant_token, self.indian_payment_token) self.assertEqual("unavailable", auth_insight_result["sca_indicator"]) def test_create_nonce_with_auth_insight_sca_indicator_sca_required(self): auth_insight_result = self._request_authentication_insights(self.indian_merchant_token, self.indian_payment_token, self.amount_threshold_for_rbi + 1) self.assertEqual("sca_required", auth_insight_result["sca_indicator"]) def test_create_nonce_with_auth_insight_sca_indicator_sca_optional(self): auth_insight_result = self._request_authentication_insights(self.indian_merchant_token, self.indian_payment_token, self.amount_threshold_for_rbi, False, None) self.assertEqual("sca_optional", auth_insight_result["sca_indicator"]) def test_create_nonce_with_auth_insight_sca_indicator_sca_required_with_recurring_customer_consent_and_max_amount(self): auth_insight_result = self._request_authentication_insights(self.indian_merchant_token, self.indian_payment_token, self.amount_threshold_for_rbi, True, 1000) self.assertEqual("sca_required", auth_insight_result["sca_indicator"]) def test_create_raises_not_found_when_404(self): self.assertRaises(NotFoundError, PaymentMethodNonce.create, "not-a-token") def test_find_nonce_shows_details(self): config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key" ) gateway = BraintreeGateway(config) nonce = PaymentMethodNonce.find("fake-valid-visa-nonce") self.assertEqual("401288", nonce.details["bin"]) def test_find_nonce_shows_3ds_details(self): config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key" ) gateway = BraintreeGateway(config) nonce = "fake-three-d-secure-visa-full-authentication-nonce" found_nonce = PaymentMethodNonce.find(nonce) three_d_secure_info = found_nonce.three_d_secure_info self.assertEqual("CreditCard", found_nonce.type) self.assertEqual(nonce, found_nonce.nonce) self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertIsInstance(three_d_secure_info.enrolled, str) self.assertIsInstance(three_d_secure_info.cavv, str) self.assertIsInstance(three_d_secure_info.xid, str) self.assertIsInstance(three_d_secure_info.eci_flag, str) self.assertIsInstance(three_d_secure_info.three_d_secure_version, str) self.assertIsInstance(three_d_secure_info.three_d_secure_authentication_id, str) def test_find_nonce_shows_paypal_details(self): found_nonce = PaymentMethodNonce.find("fake-google-pay-paypal-nonce") self.assertNotEqual(None, found_nonce.details["payer_info"]["first_name"]) self.assertNotEqual(None, found_nonce.details["payer_info"]["last_name"]) self.assertNotEqual(None, found_nonce.details["payer_info"]["email"]) self.assertNotEqual(None, found_nonce.details["payer_info"]["payer_id"]) def test_find_nonce_shows_venmo_details(self): found_nonce = PaymentMethodNonce.find("fake-venmo-account-nonce") self.assertEqual("99", found_nonce.details["last_two"]) self.assertEqual("venmojoe", found_nonce.details["username"]) self.assertEqual("1234567891234567891", found_nonce.details["venmo_user_id"]) def test_find_nonce_shows_sepa_direct_debit_details(self): found_nonce = PaymentMethodNonce.find(Nonces.SepaDirectDebit) self.assertEqual("1234", found_nonce.details["last_4"]) self.assertEqual("RECURRENT", found_nonce.details["mandate_type"]) self.assertEqual("a-fake-bank-reference-token", found_nonce.details["bank_reference_token"]) self.assertEqual("a-fake-mp-customer-id", found_nonce.details["merchant_or_partner_customer_id"]) def test_find_nonce_shows_meta_checkout_card_details(self): found_nonce = PaymentMethodNonce.find(Nonces.MetaCheckoutCard) self.assertEqual("401288", found_nonce.details["bin"]) self.assertEqual("81", found_nonce.details["last_two"]) self.assertEqual("1881", found_nonce.details["last_four"]) self.assertEqual("Visa", found_nonce.details["card_type"]) self.assertEqual("Meta Checkout Card Cardholder", found_nonce.details["cardholder_name"]) self.assertEqual(str(date.today().year + 1), found_nonce.details["expiration_year"]) self.assertEqual("12", found_nonce.details["expiration_month"]) def test_find_nonce_shows_meta_checkout_token_details(self): found_nonce = PaymentMethodNonce.find(Nonces.MetaCheckoutToken) self.assertEqual("401288", found_nonce.details["bin"]) self.assertEqual("81", found_nonce.details["last_two"]) self.assertEqual("1881", found_nonce.details["last_four"]) self.assertEqual("Visa", found_nonce.details["card_type"]) self.assertEqual("Meta Checkout Token Cardholder", found_nonce.details["cardholder_name"]) self.assertEqual(str(date.today().year + 1), found_nonce.details["expiration_year"]) self.assertEqual("12", found_nonce.details["expiration_month"]) def test_exposes_null_3ds_info_if_none_exists(self): http = ClientApiHttp.create() _, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "access-token": "access-token", "options": {"validate": False} }) found_nonce = PaymentMethodNonce.find(nonce) self.assertEqual(nonce, found_nonce.nonce) self.assertEqual(None, found_nonce.three_d_secure_info) def test_find_raises_not_found_when_404(self): self.assertRaises(NotFoundError, PaymentMethodNonce.find, "not-a-nonce") def test_bin_data_has_commercial(self): found_nonce = PaymentMethodNonce.find("fake-valid-commercial-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.Commercial.Yes, bin_data.commercial) def test_bin_data_has_country_of_issuance(self): found_nonce = PaymentMethodNonce.find("fake-valid-country-of-issuance-cad-nonce") bin_data = found_nonce.bin_data self.assertEqual("CAN", bin_data.country_of_issuance) def test_bin_data_debit(self): found_nonce = PaymentMethodNonce.find("fake-valid-debit-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.Debit.Yes, bin_data.debit) def test_bin_data_durbin_regulated(self): found_nonce = PaymentMethodNonce.find("fake-valid-durbin-regulated-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.DurbinRegulated.Yes, bin_data.durbin_regulated) def test_bin_data_issuing_bank(self): found_nonce = PaymentMethodNonce.find("fake-valid-issuing-bank-network-only-nonce") bin_data = found_nonce.bin_data self.assertEqual("NETWORK ONLY", bin_data.issuing_bank) def test_bin_data_payroll(self): found_nonce = PaymentMethodNonce.find("fake-valid-payroll-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.Payroll.Yes, bin_data.payroll) def test_bin_data_prepaid(self): found_nonce = PaymentMethodNonce.find("fake-valid-prepaid-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.Prepaid.Yes, bin_data.prepaid) def test_bin_data_unknown_values(self): found_nonce = PaymentMethodNonce.find("fake-valid-unknown-indicators-nonce") bin_data = found_nonce.bin_data self.assertEqual(CreditCard.Commercial.Unknown, bin_data.commercial) self.assertEqual(CreditCard.CountryOfIssuance.Unknown, bin_data.country_of_issuance) self.assertEqual(CreditCard.Debit.Unknown, bin_data.debit) self.assertEqual(CreditCard.DurbinRegulated.Unknown, bin_data.durbin_regulated) self.assertEqual(CreditCard.Healthcare.Unknown, bin_data.healthcare) self.assertEqual(CreditCard.IssuingBank.Unknown, bin_data.issuing_bank) self.assertEqual(CreditCard.Payroll.Unknown, bin_data.payroll) self.assertEqual(CreditCard.Prepaid.Unknown, bin_data.prepaid) self.assertEqual(CreditCard.ProductId.Unknown, bin_data.product_id) def _request_authentication_insights(self, merchant_account_id, payment_method_token, amount = None, recurring_customer_consent = None, recurring_max_amount = None): nonce_request = { "merchant_account_id": merchant_account_id, "authentication_insight": True, "authentication_insight_options": { "amount": amount, "recurring_customer_consent": recurring_customer_consent, "recurring_max_amount": recurring_max_amount, } } result = PaymentMethodNonce.create(payment_method_token, {"payment_method_nonce": nonce_request}) return result.payment_method_nonce.authentication_insight braintree_python-4.31.0/tests/integration/test_payment_method_us_bank_account.py000066400000000000000000000343571471021343500305200ustar00rootroot00000000000000from tests.test_helper import * from braintree.us_bank_account_verification import UsBankAccountVerification class PaymentMethodWithUsBankAccountTest(unittest.TestCase): def test_create_with_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertIsInstance(us_bank_account, UsBankAccount) self.assertEqual(us_bank_account.routing_number, "021000021") self.assertEqual(us_bank_account.last_4, "1234") self.assertEqual(us_bank_account.account_type, "checking") self.assertEqual(us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", us_bank_account.bank_name)) self.assertEqual(us_bank_account.default, True) self.assertEqual(us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(us_bank_account.ach_mandate.accepted_at, datetime) self.assertEqual(us_bank_account.verified, True) self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, "verified") self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.IndependentCheck) def test_create_with_verification(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.UsBankAccount, "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck, } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertIsInstance(us_bank_account, UsBankAccount) self.assertEqual(us_bank_account.routing_number, "123456789") self.assertEqual(us_bank_account.last_4, "0000") self.assertEqual(us_bank_account.account_type, "checking") self.assertEqual(us_bank_account.account_holder_name, "Dan Schulman") self.assertEqual(us_bank_account.bank_name, "Wells Fargo") self.assertEqual(us_bank_account.default, True) self.assertEqual(us_bank_account.ach_mandate.text, "example mandate text") self.assertIsInstance(us_bank_account.ach_mandate.accepted_at, datetime) self.assertEqual(us_bank_account.verified, True) self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.NetworkCheck) self.assertEqual(verification.processor_response_code, "1000") def test_create_with_verification_add_ons(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.UsBankAccount, "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck, "verification_add_ons": UsBankAccountVerification.VerificationAddOns.CustomerVerification, } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertIsInstance(us_bank_account, UsBankAccount) self.assertEqual(us_bank_account.routing_number, "123456789") self.assertEqual(us_bank_account.last_4, "0000") self.assertEqual(us_bank_account.account_type, "checking") self.assertEqual(us_bank_account.account_holder_name, "Dan Schulman") self.assertEqual(us_bank_account.bank_name, "Wells Fargo") self.assertEqual(us_bank_account.default, True) self.assertEqual(us_bank_account.ach_mandate.text, "example mandate text") self.assertIsInstance(us_bank_account.ach_mandate.accepted_at, datetime) self.assertEqual(us_bank_account.verified, True) self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.NetworkCheck) self.assertEqual(verification.processor_response_code, "1000") def test_returns_additional_processor_response_for_failed_verifications(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce("021000021", "1000000005"), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck, } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertIsInstance(us_bank_account, UsBankAccount) self.assertEqual(us_bank_account.routing_number, "021000021") self.assertEqual(us_bank_account.last_4, "0005") self.assertEqual(us_bank_account.account_type, "checking") self.assertEqual(us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", us_bank_account.bank_name)) self.assertEqual(us_bank_account.default, True) self.assertEqual(us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(us_bank_account.ach_mandate.accepted_at, datetime) self.assertEqual(us_bank_account.verified, False) self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.ProcessorDeclined) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.NetworkCheck) self.assertEqual(verification.processor_response_code, "2061") self.assertEqual(verification.additional_processor_response, "Invalid routing number") def test_create_fails_with_invalid_us_bank_account_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_invalid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } }) self.assertFalse(result.is_success) error_code = result.errors.for_object("payment_method").on("payment_method_nonce")[0].code self.assertEqual(ErrorCodes.PaymentMethod.PaymentMethodNonceUnknown, error_code) def test_update_payment_method_with_verification(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce("021000021", "1000000000"), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.IndependentCheck) result = PaymentMethod.update(us_bank_account.token, { "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck, } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertEqual(len(us_bank_account.verifications), 2) class PaymentMethodWithUsBankAccountCompliantMerchantTest(unittest.TestCase): def setUp(self): braintree.Configuration.configure( braintree.Environment.Development, "integration2_merchant_id", "integration2_public_key", "integration2_private_key" ) def tearDown(self): braintree.Configuration.configure( braintree.Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) def test_create_with_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertIsInstance(us_bank_account, UsBankAccount) self.assertEqual(us_bank_account.routing_number, "021000021") self.assertEqual(us_bank_account.last_4, "1234") self.assertEqual(us_bank_account.account_type, "checking") self.assertEqual(us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", us_bank_account.bank_name)) self.assertEqual(us_bank_account.default, True) self.assertEqual(us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(us_bank_account.ach_mandate.accepted_at, datetime) self.assertEqual(us_bank_account.verified, False) self.assertEqual(len(us_bank_account.verifications), 0) def test_create_with_verification(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce("021000021", "1000000000"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertIsInstance(us_bank_account, UsBankAccount) self.assertEqual(us_bank_account.routing_number, "021000021") self.assertEqual(us_bank_account.last_4, "0000") self.assertEqual(us_bank_account.account_type, "checking") self.assertEqual(us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", us_bank_account.bank_name)) self.assertEqual(us_bank_account.default, True) self.assertEqual(us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(us_bank_account.ach_mandate.accepted_at, datetime) self.assertEqual(us_bank_account.verified, True) self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) def test_create_fails_with_invalid_us_bank_account_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_invalid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck, } }) self.assertFalse(result.is_success) error_code = result.errors.for_object("payment_method").on("payment_method_nonce")[0].code self.assertEqual(ErrorCodes.PaymentMethod.PaymentMethodNonceUnknown, error_code) def test_update_payment_method_with_verification(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce("021000021", "1000000000"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.IndependentCheck } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.IndependentCheck) result = PaymentMethod.update(us_bank_account.token, { "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.NetworkCheck, } }) self.assertTrue(result.is_success) us_bank_account = result.payment_method self.assertEqual(len(us_bank_account.verifications), 2) braintree_python-4.31.0/tests/integration/test_paypal_account.py000066400000000000000000000153171471021343500252620ustar00rootroot00000000000000from tests.test_helper import * import time from braintree.test.nonces import Nonces class TestPayPalAccount(unittest.TestCase): def test_find_returns_paypal_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalBillingAgreement }) self.assertTrue(result.is_success) found_account = PayPalAccount.find(result.payment_method.token) self.assertNotEqual(None, found_account) self.assertEqual(found_account.__class__, PayPalAccount) self.assertEqual(found_account.token, result.payment_method.token) self.assertNotEqual(None, found_account.image_url) self.assertNotEqual(None, found_account.created_at) self.assertNotEqual(None, found_account.updated_at) self.assertIsNone(found_account.funding_source_description) self.assertFalse(hasattr(found_account, "edit_paypal_vault_id")) self.assertIsNone(found_account.revoked_at) def test_find_raises_on_not_found_token(self): self.assertRaises(NotFoundError, PayPalAccount.find, "non-existant-token") def test_find_will_not_return_credit_card(self): credit_card = CreditCard.create({ "customer_id": Customer.create().customer.id, "number": "4111111111111111", "expiration_date": "12/2099" }).credit_card self.assertRaises(NotFoundError, PayPalAccount.find, credit_card.token) def test_find_returns_subscriptions_associated_with_a_paypal_account(self): customer_id = Customer.create().customer.id payment_method_token = "paypal-account-" + str(int(time.time())) nonce = TestHelper.nonce_for_paypal_account({ "consent_code": "consent-code", "token": payment_method_token }) result = PaymentMethod.create({ "payment_method_nonce": nonce, "customer_id": customer_id }) self.assertTrue(result.is_success) token = result.payment_method.token subscription1 = Subscription.create({ "payment_method_token": token, "plan_id": TestHelper.trialless_plan["id"] }).subscription subscription2 = Subscription.create({ "payment_method_token": token, "plan_id": TestHelper.trialless_plan["id"] }).subscription paypal_account = PayPalAccount.find(result.payment_method.token) self.assertTrue(subscription1.id in [s.id for s in paypal_account.subscriptions]) self.assertTrue(subscription2.id in [s.id for s in paypal_account.subscriptions]) def test_find_retuns_billing_agreement_id_with_a_paypal_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "payment_method_nonce": Nonces.PayPalBillingAgreement, "customer_id": customer_id }) self.assertTrue(result.is_success) paypal_account = PayPalAccount.find(result.payment_method.token) self.assertNotEqual(None, paypal_account.billing_agreement_id) def test_delete_customer_with_path_traversal(self): try: customer = Customer.create({"first_name":"Waldo"}).customer PayPalAccount.delete("../../{}".format(customer.id)) except NotFoundError: pass found_customer = Customer.find(customer.id) self.assertNotEqual(None, found_customer) self.assertEqual("Waldo", found_customer.first_name) def test_delete_deletes_paypal_account(self): result = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": Nonces.PayPalBillingAgreement }) self.assertTrue(result.is_success) paypal_account_token = result.payment_method.token delete_result = PayPalAccount.delete(paypal_account_token) self.assertTrue(delete_result.is_success) self.assertRaises(NotFoundError, PayPalAccount.find, paypal_account_token) def test_delete_raises_on_not_found(self): self.assertRaises(NotFoundError, PayPalAccount.delete, "non-existant-token") def test_delete_delete_wont_delete_credit_card(self): credit_card = CreditCard.create({ "customer_id": Customer.create().customer.id, "number": "4111111111111111", "expiration_date": "12/2099" }).credit_card self.assertRaises(NotFoundError, PayPalAccount.delete, credit_card.token) def test_update_can_update_token_and_default(self): customer_id = Customer.create().customer.id CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "12/2099" }) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) old_token = result.payment_method.token new_token = "new-token-%s" % int(round(time.time() * 1000)) result = PayPalAccount.update(old_token, { "token": new_token, "options": {"make_default": True} }) self.assertTrue(result.is_success) updated_account = PayPalAccount.find(new_token) self.assertEqual(updated_account.default, True) def test_update_returns_validation_errors(self): payment_method_token = "payment-token-%s" % int(round(time.time() * 1000)) customer_id = Customer.create().customer.id CreditCard.create({ "token": payment_method_token, "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "12/2099" }) result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.PayPalFuturePayment }) self.assertTrue(result.is_success) old_token = result.payment_method.token result = PayPalAccount.update(old_token, { "token": payment_method_token, }) self.assertFalse(result.is_success) token_errors = result.errors.for_object("paypal_account").on("token") self.assertEqual(1, len(token_errors)) self.assertEqual(ErrorCodes.PayPalAccount.TokenIsInUse, token_errors[0].code) result = PayPalAccount.update(old_token, { "token": payment_method_token, }) self.assertFalse(result.is_success) token_errors = result.errors.for_object("paypal_account").on("token") self.assertEqual(1, len(token_errors)) self.assertEqual(ErrorCodes.PayPalAccount.TokenIsInUse, token_errors[0].code) braintree_python-4.31.0/tests/integration/test_plan.py000066400000000000000000000131471471021343500232110ustar00rootroot00000000000000 from tests.test_helper import * class TestPlan(unittest.TestCase): def test_all_returns_empty_list(self): Configuration.configure( Environment.Development, "test_merchant_id", "test_public_key", "test_private_key" ) plans = Plan.all() self.assertEqual([], plans) Configuration.configure( Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) def test_all_returns_all_the_plans(self): plan_token = str(random.randint(1, 1000000)) attributes = { "id": plan_token, "billing_day_of_month": 1, "billing_frequency": 1, "currency_iso_code": "USD", "description": "some description", "name": "python test plan", "number_of_billing_cycles": 1, "price": "1.00", } Configuration.instantiate().http().post(Configuration.instantiate().base_merchant_path() + "/plans/create_plan_for_tests", {"plan": attributes}) add_on_attributes = { "amount": "100.00", "description": "some description", "plan_id": plan_token, "kind": "add_on", "name": "python_add_on", "never_expires": False, "number_of_billing_cycles": 1 } Configuration.instantiate().http().post(Configuration.instantiate().base_merchant_path() + "/modifications/create_modification_for_tests", {"modification": add_on_attributes}) discount_attributes = { "amount": "100.00", "description": "some description", "plan_id": plan_token, "kind": "discount", "name": "python_discount", "never_expires": False, "number_of_billing_cycles": 1 } Configuration.instantiate().http().post(Configuration.instantiate().base_merchant_path() + "/modifications/create_modification_for_tests", {"modification": discount_attributes}) plans = Plan.all() for plan in plans: if plan.id == plan_token: actual_plan = plan self.assertNotEqual(None, actual_plan) self.assertEqual(1, attributes["billing_day_of_month"]) self.assertEqual(1, attributes["billing_frequency"]) self.assertEqual("USD", attributes["currency_iso_code"]) self.assertEqual("some description", attributes["description"]) self.assertEqual("python test plan", attributes["name"]) self.assertEqual(1, attributes["number_of_billing_cycles"]) self.assertEqual("1.00", attributes["price"]) self.assertEqual(1, len(actual_plan.add_ons)) self.assertEqual(add_on_attributes["name"], actual_plan.add_ons[0].name) self.assertEqual(1, len(actual_plan.discounts)) self.assertEqual(discount_attributes["name"], actual_plan.discounts[0].name) def test_create_returns_successful_result_if_valid(self): attributes = { "billing_day_of_month": 12, "billing_frequency": 1, "currency_iso_code": "USD", "description": "description on create", "name": "my new plan name", "number_of_billing_cycles": 1, "price": "9.99", "trial_period": False } result = Plan.create(attributes) self.assertTrue(result.is_success) plan = result.plan self.assertEqual(12, attributes["billing_day_of_month"]) self.assertEqual(1, attributes["billing_frequency"]) self.assertEqual("USD", attributes["currency_iso_code"]) self.assertEqual("description on create", attributes["description"]) self.assertEqual("my new plan name", attributes["name"]) self.assertEqual(1, attributes["number_of_billing_cycles"]) self.assertEqual("9.99", attributes["price"]) def test_find_with_valid_id(self): plan_attributes = { "billing_day_of_month": 12, "billing_frequency": 1, "currency_iso_code": "USD", "description": "description on create", "name": "my new plan name", "number_of_billing_cycles": 1, "price": "9.99", "trial_period": False } created_plan = Plan.create(plan_attributes).plan found_plan = Plan.find(created_plan.id) self.assertEqual(created_plan.name, found_plan.name) self.assertEqual(created_plan.id, found_plan.id) self.assertEqual(created_plan.price, found_plan.price) self.assertEqual(created_plan.billing_day_of_month, found_plan.billing_day_of_month) def test_find_with_invalid_token(self): with self.assertRaisesRegex(NotFoundError, "Plan with id 'bad_token' not found"): Plan.find("bad_token") def test_update_returns_successful_result_if_valid(self): plan_attributes = { "billing_day_of_month": 12, "billing_frequency": 1, "currency_iso_code": "USD", "description": "description on create", "name": "my new plan name", "number_of_billing_cycles": 1, "price": "9.99", "trial_period": False } created_plan = Plan.create(plan_attributes).plan result = Plan.update(created_plan.id, { "name": "updated name", "price": Decimal("99.88") }) self.assertTrue(result.is_success) updated_plan = result.plan self.assertEqual("updated name", updated_plan.name) self.assertEqual("99.88", updated_plan.price) braintree_python-4.31.0/tests/integration/test_samsung_pay.py000066400000000000000000000140631471021343500246030ustar00rootroot00000000000000from tests.test_helper import * # NEXT_MAJOR_VERSION remove this class # SamsungPay is deprecated @unittest.skip("deperacated - remove in next MAJOR release") class TestSamsungPay(unittest.TestCase): def test_create_from_nonce(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.SamsungPayVisa }) self.assertTrue(result.is_success) samsung_pay_card = result.payment_method self.assertIsInstance(samsung_pay_card, braintree.SamsungPayCard) self.assertIsNotNone(samsung_pay_card.bin) self.assertIsNotNone(samsung_pay_card.card_type) self.assertIsNotNone(samsung_pay_card.commercial) self.assertIsNotNone(samsung_pay_card.country_of_issuance) self.assertIsNotNone(samsung_pay_card.created_at) self.assertIsNotNone(samsung_pay_card.customer_id) self.assertIsNotNone(samsung_pay_card.customer_location) self.assertIsNotNone(samsung_pay_card.debit) self.assertIsNotNone(samsung_pay_card.default) self.assertIsNotNone(samsung_pay_card.durbin_regulated) self.assertIsNotNone(samsung_pay_card.expiration_date) self.assertIsNotNone(samsung_pay_card.expiration_month) self.assertIsNotNone(samsung_pay_card.expiration_year) self.assertIsNotNone(samsung_pay_card.expired) self.assertIsNotNone(samsung_pay_card.healthcare) self.assertIsNotNone(samsung_pay_card.image_url) self.assertIsNotNone(samsung_pay_card.issuing_bank) self.assertIsNotNone(samsung_pay_card.last_4) self.assertIsNotNone(samsung_pay_card.masked_number) self.assertIsNotNone(samsung_pay_card.payroll) self.assertIsNotNone(samsung_pay_card.prepaid) self.assertIsNotNone(samsung_pay_card.product_id) self.assertIsNotNone(samsung_pay_card.subscriptions) self.assertIsNotNone(samsung_pay_card.token) self.assertIsNotNone(samsung_pay_card.unique_number_identifier) self.assertIsNotNone(samsung_pay_card.updated_at) def test_create_from_nonce_customer_attr(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.SamsungPayVisa }) samsung_pay_cards = Customer.find(customer.id).samsung_pay_cards self.assertEqual(len(samsung_pay_cards), 1) self.assertEqual(result.payment_method.token, samsung_pay_cards[0].token) def test_create_from_nonce_with_name_and_address(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.SamsungPayVisa, "cardholder_name": "Gronk", "billing_address": { "street_address": "123 Abc Way", "locality": "Chicago", "region": "Illinois", "postal_code": "60622", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484", "country_name": "Mexico" } }) self.assertTrue(result.is_success) self.assertEqual("Gronk", result.payment_method.cardholder_name) address = result.payment_method.billing_address self.assertEqual("123 Abc Way", address.street_address) self.assertEqual("Chicago", address.locality) self.assertEqual("Illinois", address.region) self.assertEqual("60622", address.postal_code) self.assertEqual("MX", address.country_code_alpha2) self.assertEqual("MEX", address.country_code_alpha3) self.assertEqual("484", address.country_code_numeric) self.assertEqual("Mexico", address.country_name) def test_search_for_transaction(self): result = Transaction.sale({ "payment_method_nonce": Nonces.SamsungPayVisa, "amount": "1.69" }) self.assertTrue(result.is_success) transaction = result.transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == PaymentInstrumentType.SamsungPayCard ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_create_transaction_from_nonce_and_vault(self): customer = Customer.create().customer result = Transaction.sale({ "payment_method_nonce": Nonces.SamsungPayVisa, "customer_id": customer.id, "amount": "69.69", "options": { "store_in_vault": True } }) self.assertTrue(result.is_success) samsung_pay_card_details = result.transaction.samsung_pay_card_details self.assertIsInstance(samsung_pay_card_details, braintree.SamsungPayCard) self.assertIsNotNone(samsung_pay_card_details.bin) self.assertIsNotNone(samsung_pay_card_details.card_type) self.assertIsNotNone(samsung_pay_card_details.commercial) self.assertIsNotNone(samsung_pay_card_details.country_of_issuance) self.assertIsNotNone(samsung_pay_card_details.debit) self.assertIsNotNone(samsung_pay_card_details.durbin_regulated) self.assertIsNotNone(samsung_pay_card_details.expiration_date) self.assertIsNotNone(samsung_pay_card_details.expiration_year) self.assertIsNotNone(samsung_pay_card_details.expiration_month) self.assertIsNotNone(samsung_pay_card_details.healthcare) self.assertIsNotNone(samsung_pay_card_details.image_url) self.assertIsNotNone(samsung_pay_card_details.issuing_bank) self.assertIsNotNone(samsung_pay_card_details.last_4) self.assertIsNotNone(samsung_pay_card_details.payroll) self.assertIsNotNone(samsung_pay_card_details.prepaid) self.assertIsNotNone(samsung_pay_card_details.product_id) self.assertIsNotNone(samsung_pay_card_details.token) braintree_python-4.31.0/tests/integration/test_search.py000066400000000000000000000314661471021343500235300ustar00rootroot00000000000000from tests.test_helper import * class TestSearch(unittest.TestCase): def test_text_node_is(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] trial_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription trialless_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id == "integration_trial_plan" ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_text_node_is_not(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] trial_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription trialless_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id != "integration_trialless_plan" ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_text_node_starts_with(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] trial_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription trialless_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id.starts_with("integration_trial_p") ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_text_node_ends_with(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] trial_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription trialless_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id.ends_with("trial_plan") ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_text_node_contains(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] trial_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription trialless_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id.contains("rial_pl") ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_multiple_value_node_in_list(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] active_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription canceled_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription Subscription.cancel(canceled_subscription.id) collection = Subscription.search([ SubscriptionSearch.status.in_list([Subscription.Status.Active, Subscription.Status.Canceled]) ]) self.assertTrue(TestHelper.includes(collection, active_subscription)) self.assertTrue(TestHelper.includes(collection, canceled_subscription)) def test_multiple_value_node_in_list_as_arg_list(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] active_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription canceled_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription Subscription.cancel(canceled_subscription.id) collection = Subscription.search([ SubscriptionSearch.status.in_list(Subscription.Status.Active, Subscription.Status.Canceled) ]) self.assertTrue(TestHelper.includes(collection, active_subscription)) self.assertTrue(TestHelper.includes(collection, canceled_subscription)) def test_multiple_value_node_is(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] active_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription canceled_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription Subscription.cancel(canceled_subscription.id) collection = Subscription.search([ SubscriptionSearch.status == Subscription.Status.Active ]) self.assertTrue(TestHelper.includes(collection, active_subscription)) self.assertFalse(TestHelper.includes(collection, canceled_subscription)) def test_range_node_min(self): name = "Henrietta Livingston%s" % random.randint(1, 100000) Transaction.sale({ "amount": "1500.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }) t_1800 = Transaction.sale({ "amount": "1800.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount >= "1700" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1800.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.greater_than_or_equal_to("1700") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1800.id, collection.first.id) def test_range_node_max(self): name = "Henrietta Livingston%s" % random.randint(1, 100000) t_1500 = Transaction.sale({ "amount": "1500.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction Transaction.sale({ "amount": "1800.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount <= "1700" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1500.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.less_than_or_equal_to("1700") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1500.id, collection.first.id) def test_range_node_is(self): name = "Henrietta Livingston%s" % random.randint(1, 100000) Transaction.sale({ "amount": "1500.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }) t_1800 = Transaction.sale({ "amount": "1800.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount == "1800" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1800.id, collection.first.id) def test_range_node_between(self): name = "Henrietta Livingston%s" % random.randint(1, 100000) Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }) t_1500 = Transaction.sale({ "amount": "1500.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction Transaction.sale({ "amount": "1800.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.between("1100", "1600") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1500.id, collection.first.id) def test_search_on_multiple_values(self): credit_card = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", } }).customer.credit_cards[0] active_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription canceled_subscription = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription Subscription.cancel(canceled_subscription.id) collection = Subscription.search([ SubscriptionSearch.plan_id == "integration_trialless_plan", SubscriptionSearch.status.in_list([Subscription.Status.Active]) ]) self.assertTrue(TestHelper.includes(collection, active_subscription)) self.assertFalse(TestHelper.includes(collection, canceled_subscription)) braintree_python-4.31.0/tests/integration/test_sepa_direct_debit_account.py000066400000000000000000000053221471021343500274200ustar00rootroot00000000000000from tests.test_helper import * import time from braintree.test.nonces import Nonces class TestSepaDirectDebitAccount(unittest.TestCase): def test_find_returns_sepa_direct_debit_account(self): result = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": Nonces.SepaDirectDebit }) self.assertTrue(result.is_success) found_account = SepaDirectDebitAccount.find(result.payment_method.token) self.assertEqual(found_account.bank_reference_token, "a-fake-bank-reference-token") self.assertEqual(found_account.mandate_type, "RECURRENT") self.assertEqual(found_account.last_4, "1234") self.assertEqual(found_account.merchant_or_partner_customer_id, "a-fake-mp-customer-id") self.assertEqual(found_account.token, result.payment_method.token) self.assertTrue(found_account.global_id) def test_find_returns_subscriptions_associated_with_a_sepa_direct_debit_account(self): result = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": Nonces.SepaDirectDebit }) 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 sepa_direct_debit_account = SepaDirectDebitAccount.find(result.payment_method.token) self.assertTrue(subscription1.id in [s.id for s in sepa_direct_debit_account.subscriptions]) self.assertTrue(subscription2.id in [s.id for s in sepa_direct_debit_account.subscriptions]) def test_find_raises_on_not_found_token(self): self.assertRaises(NotFoundError, SepaDirectDebitAccount.find, "non-existant-token") def test_delete_sepa_direct_debit_account(self): result = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": Nonces.SepaDirectDebit }) self.assertTrue(result.is_success) sepa_direct_debit_account_token = result.payment_method.token delete_result = SepaDirectDebitAccount.delete(sepa_direct_debit_account_token) self.assertTrue(delete_result.is_success) self.assertRaises(NotFoundError, SepaDirectDebitAccount.find, sepa_direct_debit_account_token) def test_delete_raises_on_not_found(self): self.assertRaises(NotFoundError, SepaDirectDebitAccount.delete, "non-existant-token") braintree_python-4.31.0/tests/integration/test_settlement_batch_summary.py000066400000000000000000000052171471021343500273600ustar00rootroot00000000000000from tests.test_helper import * class TestSettlementBatchSummary(unittest.TestCase): possible_gateway_time_zone_offsets = (5, 4) def test_generate_returns_empty_collection_if_there_is_no_data(self): result = SettlementBatchSummary.generate('2011-01-01') self.assertTrue(result.is_success) self.assertEqual([], result.settlement_batch_summary.records) def test_generate_returns_error_if_date_can_not_be_parsed(self): result = SettlementBatchSummary.generate('THIS AINT NO DATE') self.assertFalse(result.is_success) settlement_date_errors = result.errors.for_object('settlement_batch_summary').on('settlement_date') self.assertEqual(1, len(settlement_date_errors)) self.assertEqual(ErrorCodes.SettlementBatchSummary.SettlementDateIsInvalid, settlement_date_errors[0].code) def test_generate_returns_transactions_settled_on_a_given_day(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Sergio Ramos" }, "merchant_account_id": "sandbox_credit_card", "options": {"submit_for_settlement": True} }) result = TestHelper.settle_transaction(result.transaction.id) settlement_date = result.transaction.settlement_batch_id.split('_')[0] result = SettlementBatchSummary.generate(settlement_date) self.assertTrue(result.is_success) visa_records = [row for row in result.settlement_batch_summary.records if row['card_type'] == 'Visa' and row['merchant_account_id'] == 'sandbox_credit_card'][0] count = int(visa_records['count']) self.assertGreaterEqual(count, 1) def test_generate_can_be_grouped_by_a_custom_field(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Sergio Ramos" }, "options": {"submit_for_settlement": True}, "custom_fields": { "store_me": 1 } }) result = TestHelper.settle_transaction(result.transaction.id) settlement_date = result.transaction.settlement_batch_id.split('_')[0] result = SettlementBatchSummary.generate(settlement_date, 'store_me') self.assertTrue(result.is_success) self.assertTrue('store_me' in result.settlement_batch_summary.records[0]) braintree_python-4.31.0/tests/integration/test_subscription.py000066400000000000000000001641741471021343500250120ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.nonces import Nonces from datetime import date, timedelta class TestSubscription(unittest.TestCase): def setUp(self): self.credit_card = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }).customer.credit_cards[0] self.updateable_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "price": Decimal("54.32"), "plan_id": TestHelper.trialless_plan["id"] }).subscription def test_create_returns_successful_result_if_valid(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }) self.assertTrue(result.is_success) subscription = result.subscription self.assertNotEqual(None, re.search(r"\A\w{6}\Z", subscription.id)) self.assertEqual(Decimal("12.34"), subscription.price) self.assertEqual(Decimal("12.34"), subscription.next_billing_period_amount) self.assertEqual(Subscription.Status.Active, subscription.status) self.assertEqual("integration_trialless_plan", subscription.plan_id) self.assertEqual(TestHelper.default_merchant_account_id, subscription.merchant_account_id) self.assertEqual(Decimal("0.00"), subscription.balance) self.assertEqual(date, type(subscription.first_billing_date)) self.assertEqual(date, type(subscription.next_billing_date)) self.assertEqual(date, type(subscription.billing_period_start_date)) self.assertEqual(date, type(subscription.billing_period_end_date)) self.assertEqual(date, type(subscription.paid_through_date)) self.assertEqual(datetime, type(subscription.created_at)) self.assertEqual(datetime, type(subscription.updated_at)) self.assertEqual(1, subscription.current_billing_cycle) self.assertEqual(0, subscription.failure_count) self.assertEqual(self.credit_card.token, subscription.payment_method_token) self.assertEqual(Subscription.Status.Active, subscription.status_history[0].status) self.assertEqual(Decimal("12.34"), subscription.status_history[0].price) self.assertEqual(Decimal("0.00"), subscription.status_history[0].balance) self.assertEqual(Subscription.Source.Api, subscription.status_history[0].subscription_source) self.assertEqual("USD", subscription.status_history[0].currency_iso_code) self.assertEqual(TestHelper.trialless_plan["id"], subscription.status_history[0].plan_id) def test_create_returns_successful_result_with_payment_method_nonce(self): config = Configuration.instantiate() customer_id = Customer.create().customer.id parsed_client_token = TestHelper.generate_decoded_client_token({"customer_id": customer_id}) authorization_fingerprint = json.loads(parsed_client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) _, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) nonce = json.loads(response)["creditCards"][0]["nonce"] result = Subscription.create({ "payment_method_nonce": nonce, "plan_id": TestHelper.trialless_plan["id"] }) self.assertTrue(result.is_success) transaction = result.subscription.transactions[0] self.assertEqual("411111", transaction.credit_card_details.bin) def test_create_can_set_the_id(self): new_id = str(random.randint(1, 1000000)) result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "id": new_id }) self.assertTrue(result.is_success) self.assertEqual(new_id, result.subscription.id) def test_create_can_set_the_merchant_account_id(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "merchant_account_id": TestHelper.non_default_merchant_account_id }) self.assertTrue(result.is_success) self.assertEqual(TestHelper.non_default_merchant_account_id, result.subscription.merchant_account_id) def test_create_defaults_to_plan_without_trial(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription self.assertEqual(TestHelper.trialless_plan["trial_period"], subscription.trial_period) self.assertEqual(None, subscription.trial_duration) self.assertEqual(None, subscription.trial_duration_unit) def test_create_defaults_to_plan_with_trial(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], }).subscription self.assertEqual(TestHelper.trial_plan["trial_period"], subscription.trial_period) self.assertEqual(TestHelper.trial_plan["trial_duration"], subscription.trial_duration) self.assertEqual(TestHelper.trial_plan["trial_duration_unit"], subscription.trial_duration_unit) def test_create_and_override_plan_with_trial(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "trial_duration": 5, "trial_duration_unit": Subscription.TrialDurationUnit.Month }).subscription self.assertEqual(True, subscription.trial_period) self.assertEqual(5, subscription.trial_duration) self.assertEqual(Subscription.TrialDurationUnit.Month, subscription.trial_duration_unit) def test_create_and_override_trial_period(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "trial_period": False }).subscription self.assertEqual(False, subscription.trial_period) def test_create_and_override_number_of_billing_cycles(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "number_of_billing_cycles": 10 }).subscription self.assertEqual(10, subscription.number_of_billing_cycles) def test_create_and_override_number_of_billing_cycles_to_never_expire(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "never_expires": True }).subscription self.assertEqual(None, subscription.number_of_billing_cycles) def test_create_creates_a_transaction_if_no_trial_period(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription self.assertEqual(1, len(subscription.transactions)) transaction = subscription.transactions[0] self.assertEqual(Transaction, type(transaction)) self.assertEqual(TestHelper.trialless_plan["price"], transaction.amount) self.assertEqual("sale", transaction.type) self.assertEqual(subscription.id, transaction.subscription_id) def test_create_has_transaction_with_billing_period_dates(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription transaction = subscription.transactions[0] self.assertEqual(subscription.billing_period_start_date, transaction.subscription_details.billing_period_start_date) self.assertEqual(subscription.billing_period_end_date, transaction.subscription_details.billing_period_end_date) def test_create_returns_a_transaction_if_transaction_is_declined(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": TransactionAmounts.Decline }) self.assertFalse(result.is_success) self.assertEqual(Transaction.Status.ProcessorDeclined, result.transaction.status) def test_create_doesnt_creates_a_transaction_if_trial_period(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], }).subscription self.assertEqual(0, len(subscription.transactions)) def test_create_with_error_result(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "id": "invalid token" }) self.assertFalse(result.is_success) id_errors = result.errors.for_object("subscription").on("id") self.assertEqual(1, len(id_errors)) self.assertEqual("81906", id_errors[0].code) def test_create_inherits_billing_day_of_month_from_plan(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.billing_day_of_month_plan["id"], }) self.assertTrue(result.is_success) self.assertEqual(5, result.subscription.billing_day_of_month) def test_create_allows_overriding_billing_day_of_month(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.billing_day_of_month_plan["id"], "billing_day_of_month": 19 }) self.assertTrue(result.is_success) self.assertEqual(19, result.subscription.billing_day_of_month) def test_create_allows_overriding_billing_day_of_month_with_start_immediately(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.billing_day_of_month_plan["id"], "options": { "start_immediately": True } }) self.assertTrue(result.is_success) self.assertEqual(1, len(result.subscription.transactions)) def test_create_allows_specifying_first_billing_date(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.billing_day_of_month_plan["id"], "first_billing_date": date.today() + timedelta(days=3) }) self.assertTrue(result.is_success) self.assertEqual(date.today() + timedelta(days=3), result.subscription.first_billing_date) self.assertEqual(Subscription.Status.Pending, result.subscription.status) def test_create_does_not_allow_first_billing_date_in_the_past(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.billing_day_of_month_plan["id"], "first_billing_date": date.today() - timedelta(days=3) }) self.assertFalse(result.is_success) billing_date_errors = result.errors.for_object("subscription").on("first_billing_date") self.assertEqual(1, len(billing_date_errors)) self.assertEqual(ErrorCodes.Subscription.FirstBillingDateCannotBeInThePast, billing_date_errors[0].code) def test_create_does_not_inherit_add_ons_or_discounts_from_the_plan_when_flag_is_set(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "options": { "do_not_inherit_add_ons_or_discounts": True } }).subscription self.assertEqual(0, len(subscription.add_ons)) self.assertEqual(0, len(subscription.discounts)) def test_create_inherits_add_ons_and_discounts_from_the_plan_when_not_specified(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"] }).subscription self.assertEqual(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEqual("increase_10", add_ons[0].id) self.assertEqual(Decimal("10.00"), add_ons[0].amount) self.assertEqual(1, add_ons[0].quantity) self.assertEqual(None, add_ons[0].number_of_billing_cycles) self.assertTrue(add_ons[0].never_expires) self.assertEqual(0, add_ons[0].current_billing_cycle) self.assertEqual("increase_20", add_ons[1].id) self.assertEqual(Decimal("20.00"), add_ons[1].amount) self.assertEqual(1, add_ons[1].quantity) self.assertEqual(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEqual(0, add_ons[1].current_billing_cycle) self.assertEqual(2, len(subscription.discounts)) discounts = sorted(subscription.discounts, key=lambda discount: discount.id) self.assertEqual("discount_11", discounts[0].id) self.assertEqual(Decimal("11.00"), discounts[0].amount) self.assertEqual(1, discounts[0].quantity) self.assertEqual(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) self.assertEqual(0, discounts[0].current_billing_cycle) self.assertEqual("discount_7", discounts[1].id) self.assertEqual(Decimal("7.00"), discounts[1].amount) self.assertEqual(1, discounts[1].quantity) self.assertEqual(None, discounts[1].number_of_billing_cycles) self.assertTrue(discounts[1].never_expires) self.assertEqual(0, discounts[1].current_billing_cycle) def test_create_allows_overriding_of_inherited_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "update": [ { "amount": Decimal("50.00"), "existing_id": "increase_10", "quantity": 2, "number_of_billing_cycles": 5 }, { "amount": Decimal("100.00"), "existing_id": "increase_20", "quantity": 4, "never_expires": True } ] }, "discounts": { "update": [ { "amount": Decimal("15.00"), "existing_id": "discount_7", "quantity": 3, "number_of_billing_cycles": 19 } ] } }).subscription self.assertEqual(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEqual("increase_10", add_ons[0].id) self.assertEqual(Decimal("50.00"), add_ons[0].amount) self.assertEqual(2, add_ons[0].quantity) self.assertEqual(5, add_ons[0].number_of_billing_cycles) self.assertFalse(add_ons[0].never_expires) self.assertEqual(0, add_ons[0].current_billing_cycle) self.assertEqual("increase_20", add_ons[1].id) self.assertEqual(Decimal("100.00"), add_ons[1].amount) self.assertEqual(4, add_ons[1].quantity) self.assertEqual(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEqual(0, add_ons[1].current_billing_cycle) self.assertEqual(2, len(subscription.discounts)) discounts = sorted(subscription.discounts, key=lambda discount: discount.id) self.assertEqual("discount_11", discounts[0].id) self.assertEqual(Decimal("11.00"), discounts[0].amount) self.assertEqual(1, discounts[0].quantity) self.assertEqual(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) self.assertEqual(0, discounts[0].current_billing_cycle) self.assertEqual("discount_7", discounts[1].id) self.assertEqual(Decimal("15.00"), discounts[1].amount) self.assertEqual(3, discounts[1].quantity) self.assertEqual(19, discounts[1].number_of_billing_cycles) self.assertFalse(discounts[1].never_expires) self.assertEqual(0, discounts[1].current_billing_cycle) def test_create_allows_deleting_of_inherited_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "remove": ["increase_10", "increase_20"] }, "discounts": { "remove": ["discount_7"] } }).subscription self.assertEqual(0, len(subscription.add_ons)) self.assertEqual(1, len(subscription.discounts)) self.assertEqual("discount_11", subscription.discounts[0].id) def test_create_allows_adding_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "add": [ { "amount": Decimal("50.00"), "inherited_from_id": "increase_30", "quantity": 2, "number_of_billing_cycles": 5 } ], "remove": ["increase_10", "increase_20"] }, "discounts": { "add": [ { "amount": Decimal("17.00"), "inherited_from_id": "discount_15", "never_expires": True } ], "remove": ["discount_7", "discount_11"] } }).subscription self.assertEqual(1, len(subscription.add_ons)) self.assertEqual("increase_30", subscription.add_ons[0].id) self.assertEqual(Decimal("50.00"), subscription.add_ons[0].amount) self.assertEqual(2, subscription.add_ons[0].quantity) self.assertEqual(5, subscription.add_ons[0].number_of_billing_cycles) self.assertFalse(subscription.add_ons[0].never_expires) self.assertEqual(0, subscription.add_ons[0].current_billing_cycle) self.assertEqual(1, len(subscription.discounts)) self.assertEqual("discount_15", subscription.discounts[0].id) self.assertEqual(Decimal("17.00"), subscription.discounts[0].amount) self.assertEqual(1, subscription.discounts[0].quantity) self.assertEqual(None, subscription.discounts[0].number_of_billing_cycles) self.assertTrue(subscription.discounts[0].never_expires) self.assertEqual(0, subscription.discounts[0].current_billing_cycle) def test_create_properly_parses_validation_errors_for_arrays(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "update": [ { "existing_id": "increase_10", "amount": "invalid" }, { "existing_id": "increase_20", "quantity": -2 } ] } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Subscription.Modification.AmountIsInvalid, result.errors.for_object("subscription").for_object("add_ons").for_object("update").for_index(0).on("amount")[0].code ) self.assertEqual( ErrorCodes.Subscription.Modification.QuantityIsInvalid, result.errors.for_object("subscription").for_object("add_ons").for_object("update").for_index(1).on("quantity")[0].code ) def test_descriptors_accepts_name_phone_and_url(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" } }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual("123*123456789012345678", subscription.descriptor.name) self.assertEqual("3334445555", subscription.descriptor.phone) transaction = subscription.transactions[0] self.assertEqual("123*123456789012345678", transaction.descriptor.name) self.assertEqual("3334445555", transaction.descriptor.phone) self.assertEqual("ebay.com", transaction.descriptor.url) def test_descriptors_has_validation_errors_if_format_is_invalid(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "descriptor": { "name": "badcompanyname12*badproduct12", "phone": "%bad4445555" } }) self.assertFalse(result.is_success) name_errors = result.errors.for_object("transaction").for_object("descriptor").on("name") self.assertEqual(1, len(name_errors)) self.assertEqual(ErrorCodes.Descriptor.NameFormatIsInvalid, name_errors[0].code) phone_errors = result.errors.for_object("transaction").for_object("descriptor").on("phone") self.assertEqual(1, len(phone_errors)) self.assertEqual(ErrorCodes.Descriptor.PhoneFormatIsInvalid, phone_errors[0].code) def test_description(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "options": {"validate": False} }) self.assertEqual(202, status_code) payment_method_token = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": nonce }).payment_method.token result = Subscription.create({ "payment_method_token": payment_method_token, "plan_id": TestHelper.trialless_plan["id"], "options": { "paypal": { "description": "A great product" } } }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual("A great product", subscription.description) transaction = subscription.transactions[0] paypal_details = transaction.paypal_details self.assertEqual("A great product", paypal_details.description) def test_find_with_valid_id(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], }).subscription found_subscription = Subscription.find(subscription.id) self.assertEqual(subscription.id, found_subscription.id) def test_find_with_invalid_token(self): with self.assertRaisesRegex(NotFoundError, "subscription with id 'bad_token' not found"): Subscription.find("bad_token") def test_update_creates_a_prorated_transaction_when_merchant_is_set_to_prorate(self): result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("1"), }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(2, len(subscription.transactions)) def test_update_creates_a_prorated_transaction_when_flag_is_passed_as_True(self): result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("1"), "options": { "prorate_charges": True } }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(2, len(subscription.transactions)) def test_update_does_not_create_a_prorated_transaction_when_flag_is_passed_as_False(self): result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("1"), "options": { "prorate_charges": False } }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(1, len(subscription.transactions)) def test_update_does_not_update_subscription_when_revert_subscription_on_proration_failure_is_true(self): result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("2100"), "options": { "prorate_charges": True, "revert_subscription_on_proration_failure": True } }) self.assertFalse(result.is_success) found_subscription = Subscription.find(result.subscription.id) self.assertEqual(len(self.updateable_subscription.transactions) + 1, len(result.subscription.transactions)) self.assertEqual("processor_declined", result.subscription.transactions[0].status) self.assertEqual(Decimal("0.00"), found_subscription.balance) self.assertEqual(self.updateable_subscription.price, found_subscription.price) def test_update_updates_subscription_when_revert_subscription_on_proration_failure_is_false(self): result = Subscription.update(self.updateable_subscription.id, { "price": self.updateable_subscription.price + Decimal("2100"), "options": { "prorate_charges": True, "revert_subscription_on_proration_failure": False } }) self.assertTrue(result.is_success) found_subscription = Subscription.find(result.subscription.id) self.assertEqual(len(self.updateable_subscription.transactions) + 1, len(result.subscription.transactions)) self.assertEqual("processor_declined", result.subscription.transactions[0].status) self.assertEqual(result.subscription.transactions[0].amount, Decimal(found_subscription.balance)) self.assertEqual(self.updateable_subscription.price + Decimal("2100"), found_subscription.price) def test_update_with_successful_result(self): new_id = str(random.randint(1, 1000000)) result = Subscription.update(self.updateable_subscription.id, { "id": new_id, "price": Decimal("9999.88"), "plan_id": TestHelper.trial_plan["id"] }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(new_id, subscription.id) self.assertEqual(TestHelper.trial_plan["id"], subscription.plan_id) self.assertEqual(Decimal("9999.88"), subscription.price) def test_update_with_merchant_account_id(self): result = Subscription.update(self.updateable_subscription.id, { "merchant_account_id": TestHelper.non_default_merchant_account_id, }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(TestHelper.non_default_merchant_account_id, subscription.merchant_account_id) def test_update_with_payment_method_token(self): newCard = CreditCard.create({ "customer_id": self.credit_card.customer_id, "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "100", "cardholder_name": self.credit_card.cardholder_name }).credit_card result = Subscription.update(self.updateable_subscription.id, { "payment_method_token": newCard.token }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(newCard.token, subscription.payment_method_token) def test_update_with_payment_method_nonce(self): config = Configuration.instantiate() customer_id = self.credit_card.customer_id parsed_client_token = TestHelper.generate_decoded_client_token({"customer_id": customer_id}) authorization_fingerprint = json.loads(parsed_client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) _, response = http.add_card({ "credit_card": { "number": "4242424242424242", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) nonce = json.loads(response)["creditCards"][0]["nonce"] result = Subscription.update(self.updateable_subscription.id, { "payment_method_nonce": nonce }) self.assertTrue(result.is_success) subscription = result.subscription newCard = CreditCard.find(subscription.payment_method_token) self.assertEqual("4242", newCard.last_4) self.assertNotEqual(newCard.last_4, self.credit_card.last_4) def test_update_with_number_of_billing_cycles(self): result = Subscription.update(self.updateable_subscription.id, { "number_of_billing_cycles": 10 }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(10, subscription.number_of_billing_cycles) def test_update_with_never_expires(self): result = Subscription.update(self.updateable_subscription.id, { "never_expires": True }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(None, subscription.number_of_billing_cycles) def test_update_with_error_result(self): result = Subscription.update(self.updateable_subscription.id, { "id": "bad id", }) self.assertFalse(result.is_success) id_errors = result.errors.for_object("subscription").on("id") self.assertEqual(1, len(id_errors)) self.assertEqual("81906", id_errors[0].code) def test_update_raises_error_when_subscription_not_found(self): with self.assertRaises(NotFoundError): Subscription.update("notfound", { "id": "newid", }) def test_update_allows_overriding_of_inherited_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], }).subscription subscription = Subscription.update(subscription.id, { "add_ons": { "update": [ { "amount": Decimal("50.00"), "existing_id": "increase_10", "quantity": 2, "number_of_billing_cycles": 5 }, { "amount": Decimal("100.00"), "existing_id": "increase_20", "quantity": 4, "never_expires": True } ] }, "discounts": { "update": [ { "amount": Decimal("15.00"), "existing_id": "discount_7", "quantity": 3, "number_of_billing_cycles": 19 } ] } }).subscription self.assertEqual(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEqual("increase_10", add_ons[0].id) self.assertEqual(Decimal("50.00"), add_ons[0].amount) self.assertEqual(2, add_ons[0].quantity) self.assertEqual(5, add_ons[0].number_of_billing_cycles) self.assertFalse(add_ons[0].never_expires) self.assertEqual("increase_20", add_ons[1].id) self.assertEqual(Decimal("100.00"), add_ons[1].amount) self.assertEqual(4, add_ons[1].quantity) self.assertEqual(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEqual(2, len(subscription.discounts)) discounts = sorted(subscription.discounts, key=lambda discount: discount.id) self.assertEqual("discount_11", discounts[0].id) self.assertEqual(Decimal("11.00"), discounts[0].amount) self.assertEqual(1, discounts[0].quantity) self.assertEqual(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) self.assertEqual("discount_7", discounts[1].id) self.assertEqual(Decimal("15.00"), discounts[1].amount) self.assertEqual(3, discounts[1].quantity) self.assertEqual(19, discounts[1].number_of_billing_cycles) self.assertFalse(discounts[1].never_expires) def test_update_allows_adding_and_removing_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], }).subscription subscription = Subscription.update(subscription.id, { "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "add": [ { "amount": Decimal("50.00"), "inherited_from_id": "increase_30", "quantity": 2, "number_of_billing_cycles": 5 } ], "remove": ["increase_10", "increase_20"] }, "discounts": { "add": [ { "amount": Decimal("17.00"), "inherited_from_id": "discount_15", "never_expires": True } ], "remove": ["discount_7", "discount_11"] } }).subscription self.assertEqual(1, len(subscription.add_ons)) self.assertEqual("increase_30", subscription.add_ons[0].id) self.assertEqual(Decimal("50.00"), subscription.add_ons[0].amount) self.assertEqual(2, subscription.add_ons[0].quantity) self.assertEqual(5, subscription.add_ons[0].number_of_billing_cycles) self.assertFalse(subscription.add_ons[0].never_expires) self.assertEqual(1, len(subscription.discounts)) self.assertEqual("discount_15", subscription.discounts[0].id) self.assertEqual(Decimal("17.00"), subscription.discounts[0].amount) self.assertEqual(1, subscription.discounts[0].quantity) self.assertEqual(None, subscription.discounts[0].number_of_billing_cycles) self.assertTrue(subscription.discounts[0].never_expires) def test_update_allows_adding_and_removing_unicode_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], }).subscription subscription = Subscription.update(subscription.id, { "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "add": [ { "amount": Decimal("50.00"), "inherited_from_id": u"increase_30", "quantity": 2, "number_of_billing_cycles": 5 } ], "remove": [u"increase_10", u"increase_20"] }, "discounts": { "add": [ { "amount": Decimal("17.00"), "inherited_from_id": u"discount_15", "never_expires": True } ], "remove": [u"discount_7", u"discount_11"] } }).subscription self.assertEqual(1, len(subscription.add_ons)) self.assertEqual(u"increase_30", subscription.add_ons[0].id) self.assertEqual(Decimal("50.00"), subscription.add_ons[0].amount) self.assertEqual(2, subscription.add_ons[0].quantity) self.assertEqual(5, subscription.add_ons[0].number_of_billing_cycles) self.assertFalse(subscription.add_ons[0].never_expires) self.assertEqual(1, len(subscription.discounts)) self.assertEqual(u"discount_15", subscription.discounts[0].id) self.assertEqual(Decimal("17.00"), subscription.discounts[0].amount) self.assertEqual(1, subscription.discounts[0].quantity) self.assertEqual(None, subscription.discounts[0].number_of_billing_cycles) self.assertTrue(subscription.discounts[0].never_expires) def test_update_can_replace_entire_set_of_add_ons_and_discounts(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], }).subscription subscription = Subscription.update(subscription.id, { "payment_method_token": self.credit_card.token, "plan_id": TestHelper.add_on_discount_plan["id"], "add_ons": { "add": [ {"inherited_from_id": "increase_30"}, {"inherited_from_id": "increase_20"}, ], }, "discounts": { "add": [ {"inherited_from_id": "discount_15"}, ], }, "options": { "replace_all_add_ons_and_discounts": True, }, }).subscription self.assertEqual(2, len(subscription.add_ons)) add_ons = sorted(subscription.add_ons, key=lambda add_on: add_on.id) self.assertEqual("increase_20", add_ons[0].id) self.assertEqual(Decimal("20.00"), add_ons[0].amount) self.assertEqual(1, add_ons[0].quantity) self.assertEqual(None, add_ons[0].number_of_billing_cycles) self.assertTrue(add_ons[0].never_expires) self.assertEqual("increase_30", add_ons[1].id) self.assertEqual(Decimal("30.00"), add_ons[1].amount) self.assertEqual(1, add_ons[1].quantity) self.assertEqual(None, add_ons[1].number_of_billing_cycles) self.assertTrue(add_ons[1].never_expires) self.assertEqual(1, len(subscription.discounts)) self.assertEqual("discount_15", subscription.discounts[0].id) self.assertEqual(Decimal("15.00"), subscription.discounts[0].amount) self.assertEqual(1, subscription.discounts[0].quantity) self.assertEqual(None, subscription.discounts[0].number_of_billing_cycles) self.assertTrue(subscription.discounts[0].never_expires) def test_update_descriptor_name_and_phone(self): result = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "descriptor": { "name": "123*123456789012345678", "phone": "1234567890" } }) self.assertTrue(result.is_success) subscription = result.subscription updated_subscription = Subscription.update(subscription.id, { "descriptor": { "name": "999*99", "phone": "1234567890" } }).subscription self.assertEqual("999*99", updated_subscription.descriptor.name) self.assertEqual("1234567890", updated_subscription.descriptor.phone) def test_update_description(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "options": {"validate": False} }) self.assertEqual(202, status_code) payment_method_token = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": nonce }).payment_method.token result = Subscription.create({ "payment_method_token": payment_method_token, "plan_id": TestHelper.trialless_plan["id"], "options": { "paypal": { "description": "A great product" } } }) self.assertTrue(result.is_success) subscription = result.subscription updated_subscription = Subscription.update(subscription.id, { "options": { "paypal": { "description": "An incredible product" } } }).subscription self.assertEqual("An incredible product", updated_subscription.description) def test_cancel_with_successful_response(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription result = Subscription.cancel(subscription.id) self.assertTrue(result.is_success) self.assertEqual("Canceled", result.subscription.status) def test_unsuccessful_cancel_returns_validation_error(self): Subscription.cancel(self.updateable_subscription.id) result = Subscription.cancel(self.updateable_subscription.id) self.assertFalse(result.is_success) status_errors = result.errors.for_object("subscription").on("status") self.assertTrue(len(status_errors), 1) self.assertEqual("81905", status_errors[0].code) def test_cancel_raises_not_found_error_with_bad_subscription(self): with self.assertRaises(NotFoundError): Subscription.cancel("notreal") def test_search_with_argument_list_rather_than_literal_list(self): trial_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("1") }).subscription trialless_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": Decimal("1") }).subscription collection = Subscription.search( SubscriptionSearch.plan_id == "integration_trial_plan", SubscriptionSearch.price == Decimal("1") ) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) def test_search_on_billing_cycles_remaining(self): subscription_5 = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "number_of_billing_cycles": 5 }).subscription subscription_10 = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "number_of_billing_cycles": 10 }).subscription collection = Subscription.search([ SubscriptionSearch.billing_cycles_remaining >= 7 ]) self.assertTrue(TestHelper.includes(collection, subscription_10)) self.assertFalse(TestHelper.includes(collection, subscription_5)) def test_search_on_created_at(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription empty_collection = Subscription.search([ SubscriptionSearch.created_at.between(date.today() + timedelta(1), date.today() + timedelta(2)) ]) self.assertTrue(empty_collection.maximum_size == 0) success_collection = Subscription.search([ SubscriptionSearch.created_at.between(date.today() - timedelta(1), date.today() + timedelta(1)) ]) self.assertTrue(success_collection.maximum_size > 0) def test_search_on_days_past_due(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription, 3) collection = Subscription.search([ SubscriptionSearch.days_past_due.between(2, 10) ]) self.assertTrue(collection.maximum_size > 0) for subscription in collection.items: self.assertTrue(2 <= subscription.days_past_due <= 10) def test_search_on_plan_id(self): trial_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("2") }).subscription trialless_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": Decimal("2") }).subscription collection = Subscription.search([ SubscriptionSearch.plan_id == "integration_trial_plan", SubscriptionSearch.price == Decimal("2") ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertFalse(TestHelper.includes(collection, trialless_subscription)) collection = Subscription.search([ SubscriptionSearch.plan_id.in_list("integration_trial_plan", "integration_trialless_plan"), SubscriptionSearch.price == Decimal("2") ]) self.assertTrue(TestHelper.includes(collection, trial_subscription)) self.assertTrue(TestHelper.includes(collection, trialless_subscription)) def test_search_on_plan_id_is_acts_like_text_node_instead_of_multiple_value(self): for plan in [TestHelper.trial_plan, TestHelper.trialless_plan]: Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": plan["id"], "price": Decimal("3") }) collection = Subscription.search([ SubscriptionSearch.plan_id == "no such plan id", SubscriptionSearch.price == Decimal("3") ]) self.assertEqual(0, collection.maximum_size) def test_search_on_status(self): active_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": Decimal("3") }).subscription canceled_subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "price": Decimal("3") }).subscription Subscription.cancel(canceled_subscription.id) collection = Subscription.search([ SubscriptionSearch.status.in_list([Subscription.Status.Active, Subscription.Status.Canceled]), SubscriptionSearch.price == Decimal("3") ]) self.assertTrue(TestHelper.includes(collection, active_subscription)) self.assertTrue(TestHelper.includes(collection, canceled_subscription)) def test_search_on_merchant_account_id(self): subscription_default_ma = Subscription.create({ "merchant_account_id": TestHelper.default_merchant_account_id, "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("4") }).subscription subscription_non_default_ma = Subscription.create({ "merchant_account_id": TestHelper.non_default_merchant_account_id, "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("4") }).subscription collection = Subscription.search([ SubscriptionSearch.merchant_account_id == TestHelper.default_merchant_account_id, SubscriptionSearch.price == Decimal("4") ]) self.assertTrue(TestHelper.includes(collection, subscription_default_ma)) self.assertFalse(TestHelper.includes(collection, subscription_non_default_ma)) def test_search_on_bogus_merchant_account_id(self): subscription = Subscription.create({ "merchant_account_id": TestHelper.default_merchant_account_id, "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("4") }).subscription collection = Subscription.search([ SubscriptionSearch.merchant_account_id == subscription.merchant_account_id, SubscriptionSearch.price == Decimal("4") ]) self.assertTrue(TestHelper.includes(collection, subscription)) collection = Subscription.search([ SubscriptionSearch.merchant_account_id.in_list(["totally_bogus_id", subscription.merchant_account_id]), SubscriptionSearch.price == Decimal("4") ]) self.assertTrue(TestHelper.includes(collection, subscription)) collection = Subscription.search([ SubscriptionSearch.merchant_account_id == "totally_bogus_id", SubscriptionSearch.price == Decimal("4") ]) self.assertFalse(TestHelper.includes(collection, subscription)) def test_search_on_price(self): subscription_900 = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("900") }).subscription subscription_1000 = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], "price": Decimal("1000") }).subscription collection = Subscription.search([ SubscriptionSearch.price >= Decimal("950") ]) self.assertTrue(TestHelper.includes(collection, subscription_1000)) self.assertFalse(TestHelper.includes(collection, subscription_900)) def test_search_on_transaction_id(self): subscription_found = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription subscription_not_found = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription collection = Subscription.search( SubscriptionSearch.transaction_id == subscription_found.transactions[0].id ) self.assertTrue(TestHelper.includes(collection, subscription_found)) self.assertFalse(TestHelper.includes(collection, subscription_not_found)) def test_search_on_id(self): subscription_found = Subscription.create({ "id": "find_me_%s" % random.randint(1, 1000000), "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], }).subscription subscription_not_found = Subscription.create({ "id": "do_not_find_me_%s" % random.randint(1, 1000000), "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"], }).subscription collection = Subscription.search([ SubscriptionSearch.id.starts_with("find_me") ]) self.assertTrue(TestHelper.includes(collection, subscription_found)) self.assertFalse(TestHelper.includes(collection, subscription_not_found)) def test_search_on_next_billing_date(self): subscription_found = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"] }).subscription subscription_not_found = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trial_plan["id"] }).subscription next_billing_date_cutoff = datetime.today() + timedelta(days=5) collection = Subscription.search( SubscriptionSearch.next_billing_date >= next_billing_date_cutoff ) self.assertTrue(TestHelper.includes(collection, subscription_found)) self.assertFalse(TestHelper.includes(collection, subscription_not_found)) def test_retry_charge_without_amount(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription) result = Subscription.retry_charge(subscription.id) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(subscription.price, transaction.amount) self.assertNotEqual(None, transaction.processor_authorization_code) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) def test_retry_charge_with_amount(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription) result = Subscription.retry_charge(subscription.id, Decimal(TransactionAmounts.Authorize)) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertNotEqual(None, transaction.processor_authorization_code) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) def test_retry_charge_with_submit_for_settlement(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription) result = Subscription.retry_charge(subscription.id, None, True) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(subscription.price, transaction.amount) self.assertNotEqual(None, transaction.processor_authorization_code) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) def test_retry_charge_with_submit_for_settlement_and_amount(self): subscription = Subscription.create({ "payment_method_token": self.credit_card.token, "plan_id": TestHelper.trialless_plan["id"], }).subscription TestHelper.make_past_due(subscription) result = Subscription.retry_charge(subscription.id, Decimal(TransactionAmounts.Authorize), True) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertNotEqual(None, transaction.processor_authorization_code) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) def test_create_with_paypal_future_payment_method_token(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "options": {"validate": False} }) self.assertEqual(202, status_code) payment_method_token = PaymentMethod.create({ "customer_id": Customer.create().customer.id, "payment_method_nonce": nonce }).payment_method.token result = Subscription.create({ "payment_method_token": payment_method_token, "plan_id": TestHelper.trialless_plan["id"] }) self.assertTrue(result.is_success) subscription = result.subscription self.assertEqual(payment_method_token, subscription.payment_method_token) def test_create_fails_with_paypal_one_time_payment_method_nonce(self): result = Subscription.create({ "payment_method_nonce": Nonces.PayPalOneTimePayment, "plan_id": TestHelper.trialless_plan["id"] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Subscription.PaymentMethodNonceIsInvalid, result.errors.for_object("subscription")[0].code ) def test_create_fails_with_paypal_future_payment_method_nonce(self): result = Subscription.create({ "payment_method_nonce": Nonces.PayPalBillingAgreement, "plan_id": TestHelper.trialless_plan["id"] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Subscription.PaymentMethodNonceIsInvalid, result.errors.for_object("subscription")[0].code ) braintree_python-4.31.0/tests/integration/test_test_helper.py000066400000000000000000000022261471021343500245710ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.nonces import Nonces class TestTestHelper(unittest.TestCase): def setUp(self): self.transaction = Transaction.sale({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" }, "amount": "100.00", "options": { "submit_for_settlement": "true" } }).transaction def test_settle_transaction_settles_transaction(self): TestHelper.settle_transaction(self.transaction.id) self.assertEqual(Transaction.Status.Settled, Transaction.find(self.transaction.id).status) def test_settlement_confirm_transaction(self): TestHelper.settlement_confirm_transaction(self.transaction.id) self.assertEqual(Transaction.Status.SettlementConfirmed, Transaction.find(self.transaction.id).status) def test_settlement_decline_transaction(self): TestHelper.settlement_decline_transaction(self.transaction.id) self.assertEqual(Transaction.Status.SettlementDeclined, Transaction.find(self.transaction.id).status) braintree_python-4.31.0/tests/integration/test_testing_gateway.py000066400000000000000000000035301471021343500254500ustar00rootroot00000000000000from tests.test_helper import * from braintree.configuration import Configuration from braintree.exceptions.test_operation_performed_in_production_error import TestOperationPerformedInProductionError class TestTestingGateway(unittest.TestCase): def setUp(self): config = Configuration(braintree.Environment.Production, "merchant_id", "public_key", "private_key") braintree_gateway = BraintreeGateway(config) self.gateway = TestingGateway(braintree_gateway) def test_error_is_raised_in_production_for_settle_transaction(self): with self.assertRaises(TestOperationPerformedInProductionError): self.gateway.settle_transaction("") def test_error_is_raised_in_production_for_make_past_due(self): with self.assertRaises(TestOperationPerformedInProductionError): self.gateway.make_past_due("") def test_error_is_raised_in_production_for_escrow_transaction(self): with self.assertRaises(TestOperationPerformedInProductionError): self.gateway.escrow_transaction("") def test_error_is_raised_in_production_for_settlement_confirm_transaction(self): with self.assertRaises(TestOperationPerformedInProductionError): self.gateway.settlement_confirm_transaction("") def test_error_is_raised_in_production_for_settlement_decline_transaction(self): with self.assertRaises(TestOperationPerformedInProductionError): self.gateway.settlement_decline_transaction("") def test_error_is_raised_in_production_for_create_3ds_verification(self): with self.assertRaises(TestOperationPerformedInProductionError): self.gateway.create_3ds_verification("", "") def test_error_is_raised_in_production(self): with self.assertRaises(TestOperationPerformedInProductionError): self.gateway.settle_transaction("") braintree_python-4.31.0/tests/integration/test_transaction.py000066400000000000000000010222511471021343500246010ustar00rootroot00000000000000import json from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers from braintree.test.nonces import Nonces from braintree.dispute import Dispute from braintree.payment_instrument_type import PaymentInstrumentType from datetime import date class TestTransaction(unittest.TestCase): def test_sale(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, transaction.processor_response_type) def test_sale_returns_risk_data(self): with FraudProtectionEnterpriseIntegrationMerchant(): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "device_data": "abc123", }) self.assertTrue(result.is_success) transaction = result.transaction self.assertIsInstance(transaction.risk_data, RiskData) self.assertNotEqual(transaction.risk_data.id, None) self.assertTrue(hasattr(transaction.risk_data, 'decision')) self.assertTrue(hasattr(transaction.risk_data, 'decision_reasons')) self.assertTrue(hasattr(transaction.risk_data, 'transaction_risk_score')) # def test_sale_returns_chargeback_protection_risk_data(self): # with EffortlessChargebackProtectionMerchant(): # result = Transaction.sale({ # "amount": TransactionAmounts.Authorize, # "credit_card": { # "number": "4111111111111111", # "expiration_date": "05/2009" # }, # "device_data": "abc123", # }) # # self.assertTrue(result.is_success) # transaction = result.transaction # risk_data = result.transaction.risk_data # self.assertIsInstance(risk_data, RiskData) # self.assertNotEqual(risk_data.id, None) # self.assertTrue(hasattr(risk_data, 'liability_shift')) def test_sale_receives_network_transaction_id_visa(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) self.assertTrue(len(result.transaction.network_transaction_id) > 0) def test_case_accepts_previous_network_transaction_id_mastercard(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.MasterCard, "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) self.assertTrue(len(result.transaction.network_transaction_id) > 0) def test_sale_does_not_accept_previous_network_transaction_id_elo(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Elo, "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) self.assertEqual(result.transaction, None) def test_sale_accepts_external_vault_status_visa(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "external_vault": { "status": "will_vault", } }) self.assertTrue(result.is_success) self.assertNotEqual(result.transaction.network_transaction_id, "") def test_sale_accepts_external_vault_status_mastercard(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.MasterCard, "expiration_date": "05/2009" }, "external_vault": { "status": "will_vault", } }) self.assertTrue(result.is_success) self.assertTrue(len(result.transaction.network_transaction_id) > 0) def test_sale_does_not_accept_external_vault_status_elo(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Elo, "expiration_date": "05/2009" }, "external_vault": { "status": "will_vault", } }) self.assertFalse(result.is_success) self.assertEqual(result.transaction, None) def test_sale_accepts_external_vault_status_amex(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Amex, "expiration_date": "05/2009" }, "external_vault": { "status": "will_vault", } }) self.assertTrue(result.is_success) self.assertNotEqual(result.transaction.network_transaction_id, "") def test_sale_accepts_blank_external_vault_previous_network_transaction_id_non_visa(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.MasterCard, "expiration_date": "05/2009" }, "external_vault": { "status": "vaulted", "previous_network_transaction_id": "" } }) self.assertTrue(result.is_success) self.assertTrue(len(result.transaction.network_transaction_id) > 0) def test_sale_accepts_external_vault_status_vaulted_without_previous_network_transaction_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "external_vault": { "status": "vaulted", } }) self.assertTrue(result.is_success) self.assertNotEqual(result.transaction.network_transaction_id, "") def test_sale_accepts_external_vault_previous_network_transaction_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "external_vault": { "status": "vaulted", "previous_network_transaction_id": "123456789012345" } }) self.assertTrue(result.is_success) self.assertNotEqual(result.transaction.network_transaction_id, "") def test_sale_with_external_vault_validation_error_invalid_status(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "external_vault": { "status": "bad value" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ExternalVault.StatusIsInvalid, result.errors.for_object("transaction").for_object("external_vault").on("status")[0].code ) def test_sale_with_external_vault_validation_error_invalid_status_with_previous_network_transaction_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "external_vault": { "status": "will_vault", "previous_network_transaction_id": "123456789012345" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ExternalVault.StatusWithPreviousNetworkTransactionIdIsInvalid, result.errors.for_object("transaction").for_object("external_vault").on("status")[0].code ) def test_sale_with_external_vault_discover_success(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Discover, "expiration_date": "05/2009" }, "external_vault": { "status": "vaulted", "previous_network_transaction_id": "123456789012345" } }) self.assertTrue(result.is_success) def test_sale_returns_a_successful_result_with_type_of_sale(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\w{6,}\Z", transaction.id)) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEqual("411111", transaction.credit_card_details.bin) self.assertEqual("1111", transaction.credit_card_details.last_4) self.assertEqual("05/2009", transaction.credit_card_details.expiration_date) self.assertEqual(None, transaction.voice_referral_number) self.assertEqual(None, transaction.acquirer_reference_number) def test_sale_allows_amount_as_a_decimal(self): result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\w{6,}\Z", transaction.id)) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) self.assertEqual("411111", transaction.credit_card_details.bin) self.assertEqual("1111", transaction.credit_card_details.last_4) self.assertEqual("05/2009", transaction.credit_card_details.expiration_date) def test_sale_with_expiration_month_and_year_separately(self): result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2012" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual("05", transaction.credit_card_details.expiration_month) self.assertEqual("2012", transaction.credit_card_details.expiration_year) def test_sale_works_with_all_attributes(self): result = Transaction.sale({ "amount": "100.00", "order_id": "123", "product_sku": "productsku01", "channel": "MyShoppingCartProvider", "exchange_rate_quote_id": "dummyExchangeRateQuoteId-Brainree-Python", "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", "phone_number": "122-555-1237", "international_phone": {"country_code": "1", "national_number": "3121234567"}, "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", "phone_number": "122-555-1236", "international_phone": {"country_code": "1", "national_number": "3121234567"}, "postal_code": "60103", "country_name": "Mexico", "country_code_alpha2": "MX", "country_code_alpha3": "MEX", "country_code_numeric": "484", "shipping_method": Address.ShippingMethod.Electronic } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\w{6,}\Z", transaction.id)) self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) self.assertEqual(Decimal("100.00"), transaction.amount) self.assertEqual("123", transaction.order_id) self.assertEqual("MyShoppingCartProvider", transaction.channel) self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(datetime, type(transaction.authorization_expires_at)) self.assertEqual(datetime, type(transaction.created_at)) self.assertEqual(datetime, type(transaction.updated_at)) self.assertEqual("510510", transaction.credit_card_details.bin) self.assertEqual("5100", transaction.credit_card_details.last_4) self.assertEqual("51051051****5100", transaction.credit_card_details.masked_number) self.assertEqual("MasterCard", transaction.credit_card_details.card_type) self.assertEqual("The Cardholder", transaction.credit_card_details.cardholder_name) self.assertEqual(None, transaction.avs_error_response_code) self.assertEqual("M", transaction.avs_postal_code_response_code) self.assertEqual("M", transaction.avs_street_address_response_code) self.assertEqual("Dan", transaction.customer_details.first_name) self.assertEqual("Smith", transaction.customer_details.last_name) self.assertEqual("Braintree", transaction.customer_details.company) self.assertEqual("dan@example.com", transaction.customer_details.email) self.assertEqual("419-555-1234", transaction.customer_details.phone) self.assertEqual("419-555-1235", transaction.customer_details.fax) self.assertEqual("http://braintreepayments.com", transaction.customer_details.website) self.assertEqual("Carl", transaction.billing_details.first_name) self.assertEqual("Jones", transaction.billing_details.last_name) self.assertEqual("Braintree", transaction.billing_details.company) self.assertEqual("123 E Main St", transaction.billing_details.street_address) self.assertEqual("Suite 403", transaction.billing_details.extended_address) self.assertEqual("Chicago", transaction.billing_details.locality) self.assertEqual("IL", transaction.billing_details.region) self.assertEqual("60622", transaction.billing_details.postal_code) self.assertEqual("United States of America", transaction.billing_details.country_name) self.assertEqual("US", transaction.billing_details.country_code_alpha2) self.assertEqual("USA", transaction.billing_details.country_code_alpha3) self.assertEqual("840", transaction.billing_details.country_code_numeric) self.assertEqual("1", transaction.billing_details.international_phone["country_code"]) self.assertEqual("3121234567", transaction.billing_details.international_phone["national_number"]) self.assertEqual("Andrew", transaction.shipping_details.first_name) self.assertEqual("Mason", transaction.shipping_details.last_name) self.assertEqual("Braintree", transaction.shipping_details.company) self.assertEqual("456 W Main St", transaction.shipping_details.street_address) self.assertEqual("Apt 2F", transaction.shipping_details.extended_address) self.assertEqual("Bartlett", transaction.shipping_details.locality) self.assertEqual("IL", transaction.shipping_details.region) self.assertEqual("60103", transaction.shipping_details.postal_code) self.assertEqual("Mexico", transaction.shipping_details.country_name) self.assertEqual("MX", transaction.shipping_details.country_code_alpha2) self.assertEqual("MEX", transaction.shipping_details.country_code_alpha3) self.assertEqual("484", transaction.shipping_details.country_code_numeric) self.assertEqual("1", transaction.shipping_details.international_phone["country_code"]) self.assertEqual("3121234567", transaction.shipping_details.international_phone["national_number"]) self.assertEqual(None, transaction.additional_processor_response) def test_sale_with_exchange_rate_quote_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "exchange_rate_quote_id": "dummyExchangeRateQuoteId-Brainree-Python", }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, transaction.processor_response_type) def test_sale_with_invalid_exchange_rate_quote_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "exchange_rate_quote_id": "a" * 4010, }) self.assertFalse(result.is_success) exchange_rate_quote_id_errors = result.errors.for_object("transaction").on("exchange_rate_quote_id") self.assertEqual(ErrorCodes.Transaction.ExchangeRateQuoteIdIsTooLong, exchange_rate_quote_id_errors[0].code) def test_sale_with_invalid_product_sku(self): result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "product_sku": "product$ku!", }) self.assertFalse(result.is_success) product_sku_errors = result.errors.for_object("transaction").on("product_sku") self.assertEqual(1, len(product_sku_errors)) self.assertEqual(ErrorCodes.Transaction.ProductSkuIsInvalid, product_sku_errors[0].code) def test_sale_to_create_error_tax_amount_is_required_for_aib_swedish(self): result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "merchant_account_id": TestHelper.aib_swe_ma_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2030" } }) self.assertFalse(result.is_success) tax_amount_errors = result.errors.for_object("transaction").on("tax_amount") self.assertEqual(1, len(tax_amount_errors)) self.assertEqual(ErrorCodes.Transaction.TaxAmountIsRequiredForAibSwedish, tax_amount_errors[0].code) def test_sale_with_invalid_address(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" }, "billing": { "phone_number": "123-234-3456=098765" }, "shipping": { "phone_number": "123-234-3456=098765", "shipping_method": "urgent" }, }) self.assertFalse(result.is_success) billing_phone_number_errors = result.errors.for_object("transaction").for_object("billing").on("phone_number") self.assertEqual(1, len(billing_phone_number_errors)) self.assertEqual(ErrorCodes.Transaction.BillingPhoneNumberIsInvalid, billing_phone_number_errors[0].code) shipping_phone_number_errors = result.errors.for_object("transaction").for_object("shipping").on("phone_number") self.assertEqual(1, len(shipping_phone_number_errors)) self.assertEqual(ErrorCodes.Transaction.ShippingPhoneNumberIsInvalid, shipping_phone_number_errors[0].code) shipping_method_errors = result.errors.for_object("transaction").for_object("shipping").on("shipping_method") self.assertEqual(1, len(shipping_method_errors)) self.assertEqual(ErrorCodes.Transaction.ShippingMethodIsInvalid, shipping_method_errors[0].code) def test_sale_with_vault_customer_and_credit_card_data(self): customer = Customer.create({ "first_name": "Pingu", "last_name": "Penguin", }).customer result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "customer_id": customer.id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.credit_card_details.masked_number, "41111111****1111") self.assertEqual(None, transaction.vault_credit_card) def test_sale_with_vault_customer_and_credit_card_data_and_store_in_vault(self): customer = Customer.create({ "first_name": "Pingu", "last_name": "Penguin", }).customer result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "customer_id": customer.id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "store_in_vault": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("41111111****1111", transaction.credit_card_details.masked_number) self.assertEqual("411111******1111", transaction.vault_credit_card.masked_number) def test_sale_with_venmo_merchant_data(self): result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "venmo_merchant_data": { "venmo_merchant_public_id": "12345", "originating_transaction_id": "abc123", "originating_merchant_id": "xyz123", "originating_merchant_kind": "braintree", } } }) self.assertTrue(result.is_success) def test_sale_with_custom_fields(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "custom_fields": { "store_me": "some extra stuff" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("some extra stuff", transaction.custom_fields["store_me"]) def test_sale_with_merchant_account_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(TestHelper.non_default_merchant_account_id, transaction.merchant_account_id) def test_sale_without_merchant_account_id_falls_back_to_default(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(TestHelper.default_merchant_account_id, transaction.merchant_account_id) def test_sale_with_shipping_address_id(self): result = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010" } }) self.assertTrue(result.is_success) customer = result.customer result = Address.create({ "customer_id": customer.id, "street_address": "123 Fake St." }) self.assertTrue(result.is_success) address = result.address result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "customer_id": customer.id, "shipping_address_id": address.id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("123 Fake St.", transaction.shipping_details.street_address) self.assertEqual(address.id, transaction.shipping_details.id) def test_sale_with_risk_data_security_parameters(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "risk_data": { "customer_browser": "IE7", "customer_device_id": "customer_device_id_012", "customer_ip": "192.168.0.1", "customer_location_zip": "91244", "customer_tenure": 20 } }) self.assertTrue(result.is_success) def test_sale_with_invalid_risk_data_security_parameters(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "risk_data": { "customer_browser": "IE7", "customer_device_id": "customer_device_id_012", "customer_ip": "192.168.0.1", "customer_location_zip": "912$4", "customer_tenure": "20" } }) self.assertFalse(result.is_success) customer_location_zip_errors = result.errors.for_object("transaction").for_object("risk_data").on("customer_location_zip") self.assertEqual(1, len(customer_location_zip_errors)) self.assertEqual(ErrorCodes.RiskData.CustomerLocationZipInvalidCharacters, customer_location_zip_errors[0].code) def test_sale_with_billing_address_id(self): result = Customer.create({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010" } }) self.assertTrue(result.is_success) customer = result.customer result = Address.create({ "customer_id": customer.id, "street_address": "123 Fake St." }) self.assertTrue(result.is_success) address = result.address result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "customer_id": customer.id, "billing_address_id": address.id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("123 Fake St.", transaction.billing_details.street_address) self.assertEqual(address.id, transaction.billing_details.id) def test_sale_with_device_session_id_and_fraud_merchant_id_sends_deprecation_warning(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") 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) assert len(w) > 0 assert issubclass(w[-1].category, DeprecationWarning) def test_sale_with_level_2(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "purchase_order_number": "12345", "tax_amount": Decimal("10.00"), "tax_exempt": True, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("12345", transaction.purchase_order_number) self.assertEqual(Decimal("10.00"), transaction.tax_amount) self.assertEqual(True, transaction.tax_exempt) def test_create_with_invalid_tax_amount(self): result = Transaction.sale({ "amount": Decimal("100"), "tax_amount": "asdf", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) tax_amount_errors = result.errors.for_object("transaction").on("tax_amount") self.assertEqual(1, len(tax_amount_errors)) self.assertEqual(ErrorCodes.Transaction.TaxAmountFormatIsInvalid, tax_amount_errors[0].code) def test_create_with_too_long_purchase_order_number(self): result = Transaction.sale({ "amount": Decimal("100"), "purchase_order_number": "aaaaaaaaaaaaaaaaaa", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) purchase_order_number_errors = result.errors.for_object("transaction").on("purchase_order_number") self.assertEqual(1, len(purchase_order_number_errors)) self.assertEqual(ErrorCodes.Transaction.PurchaseOrderNumberIsTooLong, purchase_order_number_errors[0].code) def test_create_with_invalid_purchase_order_number(self): result = Transaction.sale({ "amount": Decimal("100"), "purchase_order_number": "\xc3\x9f\xc3\xa5\xe2\x88\x82", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) purchase_order_number_errors = result.errors.for_object("transaction").on("purchase_order_number") self.assertEqual(1, len(purchase_order_number_errors)) self.assertEqual(ErrorCodes.Transaction.PurchaseOrderNumberIsInvalid, purchase_order_number_errors[0].code) def test_sale_with_level_3(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "purchase_order_number": "12345", "discount_amount": Decimal("1.00"), "shipping_amount": Decimal("2.00"), "ships_from_postal_code": "12345", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal("1.00"), transaction.discount_amount) self.assertEqual(Decimal("2.00"), transaction.shipping_amount) self.assertEqual("12345", transaction.ships_from_postal_code) def test_sale_with_shipping_tax_amount(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "purchase_order_number": "12345", "discount_amount": Decimal("1.00"), "shipping_amount": Decimal("2.00"), "shipping_tax_amount": Decimal("3.00"), "ships_from_postal_code": "12345", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Decimal("1.00"), transaction.discount_amount) self.assertEqual(Decimal("2.00"), transaction.shipping_amount) self.assertEqual(Decimal("3.00"), transaction.shipping_tax_amount) self.assertEqual("12345", transaction.ships_from_postal_code) def test_sca_exemption_successful_result(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4023490000000008", "expiration_date": "05/2009" }, "sca_exemption": "low_value" }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.sca_exemption_requested, "low_value") def test_invalid_sca_exemption_failure_result(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4023490000000008", "expiration_date": "05/2009" }, "sca_exemption": "invalid" }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("sca_exemption") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ScaExemptionInvalid, errors[0].code) def test_create_with_discount_amount_invalid(self): result = Transaction.sale({ "amount": Decimal("100"), "discount_amount": "asdf", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("discount_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.DiscountAmountFormatIsInvalid, errors[0].code) def test_create_with_discount_amount_negative(self): result = Transaction.sale({ "amount": Decimal("100"), "discount_amount": Decimal("-100"), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("discount_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.DiscountAmountCannotBeNegative, errors[0].code) def test_create_with_discount_amount_too_large(self): result = Transaction.sale({ "amount": Decimal("100"), "discount_amount": Decimal("999999999"), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("discount_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.DiscountAmountIsTooLarge, errors[0].code) def test_create_with_shipping_amount_invalid(self): result = Transaction.sale({ "amount": Decimal("100"), "shipping_amount": "asdf", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("shipping_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ShippingAmountFormatIsInvalid, errors[0].code) def test_create_with_shipping_amount_negative(self): result = Transaction.sale({ "amount": Decimal("100"), "shipping_amount": Decimal("-100"), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("shipping_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ShippingAmountCannotBeNegative, errors[0].code) def test_create_with_shipping_amount_too_large(self): result = Transaction.sale({ "amount": Decimal("100"), "shipping_amount": Decimal("999999999"), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("shipping_amount") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ShippingAmountIsTooLarge, errors[0].code) def test_create_with_ships_from_postal_code_is_too_long(self): result = Transaction.sale({ "amount": Decimal("100"), "ships_from_postal_code": "0000000000", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("ships_from_postal_code") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ShipsFromPostalCodeIsTooLong, errors[0].code) def test_create_with_ships_from_postal_code_invalid_characters(self): result = Transaction.sale({ "amount": Decimal("100"), "ships_from_postal_code": "1$345", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) errors = result.errors.for_object("transaction").on("ships_from_postal_code") self.assertEqual(1, len(errors)) self.assertEqual(ErrorCodes.Transaction.ShipsFromPostalCodeInvalidCharacters, errors[0].code) def test_sale_with_soft_declined(self): result = Transaction.sale({ "amount": TransactionAmounts.Decline, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Status.ProcessorDeclined, transaction.status) self.assertEqual(ProcessorResponseTypes.SoftDeclined, transaction.processor_response_type) self.assertEqual("2000 : Do Not Honor", transaction.additional_processor_response) def test_sale_with_hard_declined(self): result = Transaction.sale({ "amount": TransactionAmounts.HardDecline, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Status.ProcessorDeclined, transaction.status) self.assertEqual(ProcessorResponseTypes.HardDeclined, transaction.processor_response_type) self.assertEqual("2015 : Transaction Not Allowed", transaction.additional_processor_response) def test_sale_with_gateway_rejected_with_avs(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "billing": { "street_address": "200 Fake Street" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.GatewayRejectionReason.Avs, transaction.gateway_rejection_reason) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_sale_with_gateway_rejected_with_avs_and_cvv(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "billing": { "postal_code": "20000" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "200" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.GatewayRejectionReason.AvsAndCvv, transaction.gateway_rejection_reason) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_sale_with_gateway_rejected_with_cvv(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009", "cvv": "200" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.GatewayRejectionReason.Cvv, transaction.gateway_rejection_reason) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key @unittest.skip("pending") def test_sale_with_gateway_rejected_with_excessive_retry(self): with DuplicateCheckingMerchant(): excessive_retry = False counter = 0 while not (excessive_retry or counter > 25): result = Transaction.sale({ "amount": TransactionAmounts.Decline, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2017", "cvv": "333" } }) excessive_retry = (result.transaction.status == braintree.Transaction.Status.GatewayRejected) counter += 1 self.assertFalse(result.is_success) self.assertEqual(Transaction.GatewayRejectionReason.ExcessiveRetry, result.transaction.gateway_rejection_reason) def test_sale_with_gateway_rejected_with_fraud(self): with AdvancedFraudKountIntegrationMerchant(): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4000111111111511", "expiration_date": "05/2017", "cvv": "333" } }) self.assertFalse(result.is_success) self.assertEqual(Transaction.GatewayRejectionReason.Fraud, result.transaction.gateway_rejection_reason) def test_sale_with_gateway_rejected_with_risk_threshold(self): with AdvancedFraudKountIntegrationMerchant(): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111130000000003", "expiration_date": "05/2017", "cvv": "333" } }) self.assertFalse(result.is_success) self.assertEqual(Transaction.GatewayRejectionReason.RiskThreshold, result.transaction.gateway_rejection_reason) def test_sale_with_gateway_rejected_with_risk_threshold_nonce(self): with AdvancedFraudKountIntegrationMerchant(): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.GatewayRejectedRiskThreshold }) self.assertFalse(result.is_success) self.assertEqual(Transaction.GatewayRejectionReason.RiskThreshold, result.transaction.gateway_rejection_reason) def test_sale_with_gateway_rejected_token_issuance(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.fake_venmo_account_merchant_account_id, "payment_method_nonce": Nonces.VenmoAccountTokenIssuanceError }) self.assertFalse(result.is_success) self.assertEqual(Transaction.GatewayRejectionReason.TokenIssuance, result.transaction.gateway_rejection_reason) def test_sale_with_service_fee(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "service_fee_amount": "1.00" }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.service_fee_amount, "1.00") def test_sale_on_master_merchant_accoount_is_invalid_with_service_fee(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "service_fee_amount": "1.00" }) self.assertFalse(result.is_success) amount_errors = result.errors.for_object("transaction").on("service_fee_amount") self.assertEqual(1, len(amount_errors)) self.assertEqual(ErrorCodes.Transaction.ServiceFeeAmountNotAllowedOnMasterMerchantAccount, amount_errors[0].code) def test_sale_on_submerchant_is_invalid_without_with_service_fee(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.SubMerchantAccountRequiresServiceFeeAmount, result.errors.for_object("transaction").on("merchant_account_id")[0].code ) def test_sale_with_hold_in_escrow_option(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "hold_in_escrow": True }, "service_fee_amount": "1.00" }) self.assertTrue(result.is_success) self.assertEqual( Transaction.EscrowStatus.HoldPending, result.transaction.escrow_status ) def test_sale_with_hold_in_escrow_option_fails_for_master_merchant_account(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "hold_in_escrow": True } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotHoldInEscrow, result.errors.for_object("transaction").on("base")[0].code ) def test_hold_in_escrow_after_sale(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "service_fee_amount": "1.00" }) self.assertTrue(result.is_success) result = Transaction.hold_in_escrow(result.transaction.id) self.assertTrue(result.is_success) self.assertEqual( Transaction.EscrowStatus.HoldPending, result.transaction.escrow_status ) def test_hold_in_escrow_after_sale_fails_for_master_merchant_account(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) result = Transaction.hold_in_escrow(result.transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotHoldInEscrow, result.errors.for_object("transaction").on("base")[0].code ) def test_release_from_escrow_from_escrow(self): transaction = self.__create_escrowed_transaction() result = Transaction.release_from_escrow(transaction.id) self.assertTrue(result.is_success) self.assertEqual( Transaction.EscrowStatus.ReleasePending, result.transaction.escrow_status ) def test_release_from_escrow_from_escrow_fails_when_transaction_not_in_escrow(self): result = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) result = Transaction.release_from_escrow(result.transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotReleaseFromEscrow, result.errors.for_object("transaction").on("base")[0].code ) def test_cancel_release_from_escrow(self): transaction = self.__create_escrowed_transaction() submit_result = Transaction.release_from_escrow(transaction.id) result = Transaction.cancel_release(submit_result.transaction.id) self.assertTrue(result.is_success) self.assertEqual( Transaction.EscrowStatus.Held, result.transaction.escrow_status ) def test_cancel_release_from_escrow_fails_if_transaction_is_not_pending_release(self): transaction = self.__create_escrowed_transaction() result = Transaction.cancel_release(transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotCancelRelease, result.errors.for_object("transaction").on("base")[0].code ) def test_sale_with_payment_method_nonce(self): config = Configuration.instantiate() parsed_client_token = TestHelper.generate_decoded_client_token() authorization_fingerprint = json.loads(parsed_client_token)["authorizationFingerprint"] http = ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) _, response = http.add_card({ "credit_card": { "number": "4111111111111111", "expiration_month": "11", "expiration_year": "2099", }, "share": True }) nonce = json.loads(response)["creditCards"][0]["nonce"] result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": nonce }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("411111", transaction.credit_card_details.bin) def test_sale_with_fake_apple_pay_nonce(self): result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": Nonces.ApplePayAmEx }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.amount, 10.00) self.assertEqual(result.transaction.payment_instrument_type, PaymentInstrumentType.ApplePayCard) apple_pay_details = result.transaction.apple_pay_details self.assertNotEqual(None, apple_pay_details) self.assertEqual(ApplePayCard.CardType.AmEx, apple_pay_details.card_type) self.assertEqual("AmEx 41002", apple_pay_details.payment_instrument_name) self.assertTrue(int(apple_pay_details.expiration_month) > 0) self.assertTrue(int(apple_pay_details.expiration_year) > 0) self.assertNotEqual(None, apple_pay_details.cardholder_name) def test_sale_with_fake_android_pay_proxy_card_nonce(self): result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": Nonces.AndroidPayCardDiscover }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.amount, 10.00) self.assertEqual(result.transaction.payment_instrument_type, PaymentInstrumentType.AndroidPayCard) android_pay_card_details = result.transaction.android_pay_card_details self.assertNotEqual(None, android_pay_card_details) self.assertEqual(CreditCard.CardType.Discover, android_pay_card_details.card_type) self.assertTrue(int(android_pay_card_details.expiration_month) > 0) self.assertTrue(int(android_pay_card_details.expiration_year) > 0) self.assertFalse(android_pay_card_details.is_network_tokenized) 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) self.assertTrue(android_pay_card_details.is_network_tokenized) 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, "1234567891234567891") def test_sale_with_fake_venmo_account_nonce_and_profile_id(self): result = Transaction.sale({ "amount": "10.00", "payment_method_nonce": Nonces.VenmoAccount, "merchant_account_id": TestHelper.fake_venmo_account_merchant_account_id, "options": { "venmo": { "profile_id": "integration_venmo_merchant_public_id", }, }, }) self.assertTrue(result.is_success) def test_sale_with_advanced_fraud_checking_skipped(self): with AdvancedFraudKountIntegrationMerchant(): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "skip_advanced_fraud_checking": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.risk_data, None) def test_sale_with_processing_overrides_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, "processing_overrides" : { "customer_email" : "pythonSDK@example.com", "customer_first_name" : "pythonSDK_test_customer_first_name", "customer_last_name" : "pythonSDK_test_customer_last_name", "customer_tax_identifier" : "1.2.3.4.5.6" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) def test_sale_with_skip_cvv_option_set(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "skip_cvv": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.cvv_response_code, "B") def test_sale_with_skip_avs_option_set(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "skip_avs": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.avs_error_response_code, None) self.assertEqual(transaction.avs_street_address_response_code, "B") def test_sale_with_line_items_zero(self): result = Transaction.sale({ "amount": "45.15", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", } }) self.assertTrue(result.is_success) transaction = result.transaction line_items = transaction.line_items self.assertEqual(0, len(line_items)) def test_sale_with_line_items_single_only_required_fields(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "total_amount": "45.15", }] }) self.assertTrue(result.is_success) transaction = result.transaction line_items = transaction.line_items self.assertEqual(1, len(line_items)) lineItem = line_items[0] self.assertEqual("1.0232", lineItem.quantity) self.assertEqual("Name #1", lineItem.name) self.assertEqual(TransactionLineItem.Kind.Debit, lineItem.kind) self.assertEqual("45.1232", lineItem.unit_amount) self.assertEqual("45.15", lineItem.total_amount) def test_sale_with_line_items_single(self): result = Transaction.sale({ "amount": "45.15", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "description": "Description #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_tax_amount": "1.23", "unit_of_measure": "gallon", "discount_amount": "1.02", "tax_amount": "4.50", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", "url": "https://example.com/products/23434", }] }) self.assertTrue(result.is_success) transaction = result.transaction line_items = transaction.line_items self.assertEqual(1, len(line_items)) lineItem = line_items[0] self.assertEqual("1.0232", lineItem.quantity) self.assertEqual("Name #1", lineItem.name) self.assertEqual("Description #1", lineItem.description) self.assertEqual(TransactionLineItem.Kind.Debit, lineItem.kind) self.assertEqual("45.1232", lineItem.unit_amount) self.assertEqual("1.23", lineItem.unit_tax_amount) self.assertEqual("gallon", lineItem.unit_of_measure) self.assertEqual("1.02", lineItem.discount_amount) self.assertEqual("4.50", lineItem.tax_amount) self.assertEqual("45.15", lineItem.total_amount) self.assertEqual("23434", lineItem.product_code) self.assertEqual("9SAASSD8724", lineItem.commodity_code) self.assertEqual("https://example.com/products/23434", lineItem.url) def test_sale_with_line_items_multiple(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "description": "Description #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "tax_amount": "4.50", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "2.02", "name": "Name #2", "description": "Description #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "5", "unit_of_measure": "gallon", "tax_amount": "4.50", "total_amount": "45.15", }] }) self.assertTrue(result.is_success) transaction = result.transaction line_items = transaction.line_items self.assertEqual(2, len(line_items)) line_item_1 = None for line_item in line_items: if line_item.name == "Name #1": line_item_1 = line_item break if line_item_1 is None: self.fail("TransactionLineItem with name \"Name #1\" not returned.") self.assertEqual("1.0232", line_item_1.quantity) self.assertEqual("Name #1", line_item_1.name) self.assertEqual("Description #1", line_item_1.description) self.assertEqual(TransactionLineItem.Kind.Debit, line_item_1.kind) self.assertEqual("45.1232", line_item_1.unit_amount) self.assertEqual("gallon", line_item_1.unit_of_measure) self.assertEqual("1.02", line_item_1.discount_amount) self.assertEqual("45.15", line_item_1.total_amount) self.assertEqual("23434", line_item_1.product_code) self.assertEqual("9SAASSD8724", line_item_1.commodity_code) line_item_2 = None for line_item in line_items: if line_item.name == "Name #2": line_item_2 = line_item break if line_item_2 is None: self.fail("TransactionLineItem with name \"Name #2\" not returned.") self.assertEqual("2.02", line_item_2.quantity) self.assertEqual("Name #2", line_item_2.name) self.assertEqual("Description #2", line_item_2.description) self.assertEqual(TransactionLineItem.Kind.Credit, line_item_2.kind) self.assertEqual("5", line_item_2.unit_amount) self.assertEqual("gallon", line_item_2.unit_of_measure) self.assertEqual("45.15", line_item_2.total_amount) self.assertEqual(None, line_item_2.discount_amount) self.assertEqual(None, line_item_2.product_code) self.assertEqual(None, line_item_2.commodity_code) def test_sale_with_line_items_with_zero_amount_fields(self): result = Transaction.sale({ "amount": "45.15", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "total_amount": "45.15", "discount_amount": "0", "unit_tax_amount": "0", "tax_amount": "0", }] }) self.assertTrue(result.is_success) transaction = result.transaction line_items = transaction.line_items lineItem = line_items[0] self.assertEqual("0.00", lineItem.unit_tax_amount) self.assertEqual("0.00", lineItem.discount_amount) self.assertEqual("0.00", lineItem.tax_amount) def test_sale_with_line_items_validation_error_commodity_code_is_too_long(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "0123456789123", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.CommodityCodeIsTooLong, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("commodity_code")[0].code ) def test_sale_with_line_items_validation_error_description_is_too_long(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "description": "This is a line item description which is far too long. Like, way too long to be practical. We don't like how long this line item description is.", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.DescriptionIsTooLong, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("description")[0].code ) def test_sale_with_line_items_validation_error_discount_amount_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "2147483648", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.DiscountAmountIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("discount_amount")[0].code ) def test_sale_with_line_items_validation_error_discount_amount_cannot_be_negative(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "-1.23", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.DiscountAmountCannotBeNegative, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("discount_amount")[0].code ) def test_sale_with_line_items_validation_error_tax_amount_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "tax_amount": "2147483648", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TaxAmountIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_0").on("tax_amount")[0].code ) def test_sale_with_line_items_validation_error_tax_amount_cannot_be_negative(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "tax_amount": "-1.23", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TaxAmountCannotBeNegative, result.errors.for_object("transaction").for_object("line_items").for_object("index_0").on("tax_amount")[0].code ) def test_sale_with_line_items_validation_error_tax_amount_format_is_invalid(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "tax_amount": "4.555", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TaxAmountFormatIsInvalid, result.errors.for_object("transaction").for_object("line_items").for_object("index_0").on("tax_amount")[0].code ) def test_sale_with_line_items_validation_error_kind_is_required(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.KindIsRequired, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("kind")[0].code ) def test_sale_with_line_items_validation_error_name_is_required(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.NameIsRequired, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("name")[0].code ) def test_sale_with_line_items_validation_error_name_is_too_long(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "123456789012345678901234567890123456", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.NameIsTooLong, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("name")[0].code ) def test_sale_with_line_items_validation_error_product_code_is_too_long(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "123456789012345678901234567890123456", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.ProductCodeIsTooLong, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("product_code")[0].code ) def test_sale_with_line_items_validation_error_quantity_is_required(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.QuantityIsRequired, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("quantity")[0].code ) def test_sale_with_line_items_validation_error_quantity_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "2147483648", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.QuantityIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("quantity")[0].code ) def test_sale_with_line_items_validation_error_total_amount_is_required(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TotalAmountIsRequired, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("total_amount")[0].code ) def test_sale_with_line_items_validation_error_total_amount_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "2147483648", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TotalAmountIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("total_amount")[0].code ) def test_sale_with_line_items_validation_error_total_amount_must_be_greater_than_zero(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "-2", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.TotalAmountMustBeGreaterThanZero, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("total_amount")[0].code ) def test_sale_with_line_items_validation_error_unit_amount_is_required(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitAmountIsRequired, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_amount")[0].code ) def test_sale_with_line_items_validation_error_unit_amount_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "2147483648", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitAmountIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_amount")[0].code ) def test_sale_with_line_items_validation_error_unit_amount_must_be_greater_than_zero(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "-2", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitAmountMustBeGreaterThanZero, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_amount")[0].code ) def test_sale_with_line_items_accepts_valid_image_url_and_upc_code_and_type(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", "upc_code": "1234567890", "upc_type": "UPC-A", "image_url": "https://google.com/image.png", }] }) self.assertTrue(result.is_success) line_items = result.transaction.line_items lineItem = line_items[0] self.assertEqual("1234567890", lineItem.upc_code) self.assertEqual("UPC-A", lineItem.upc_type) def test_sale_with_line_items_returns_validation_errors_for_upc_code_too_long_and_type_invalid(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", "upc_code": "THISCODEISABITTOOLONG", "upc_type": "invalid", "image_url": "https://google.com/image.png", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UPCCodeIsTooLong, result.errors.for_object("transaction").for_object("line_items").for_object("index_0").on("upc_code")[0].code ) self.assertEqual( ErrorCodes.Transaction.LineItem.UPCTypeIsInvalid, result.errors.for_object("transaction").for_object("line_items").for_object("index_0").on("upc_type")[0].code ) def test_sale_with_line_items_returns_UPC_code_missing_error(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", "upc_type": "UPC-B", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UPCCodeIsMissing, result.errors.for_object("transaction").for_object("line_items").for_object("index_0").on("upc_code")[0].code ) def test_sale_with_line_items_returns_UPC_type_missing_error(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", "upc_code": "00000000000000", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UPCTypeIsMissing, result.errors.for_object("transaction").for_object("line_items").for_object("index_0").on("upc_type")[0].code ) def test_sale_with_amount_not_supported_by_processor(self): result = Transaction.sale({ "amount": "0.2", "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.AmountNotSupportedByProcessor, result.errors.for_object("transaction")[0].code ) def test_sale_with_line_items_validation_error_unit_of_measure_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.0232", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.1232", "unit_of_measure": "1234567890123", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitOfMeasureIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_of_measure")[0].code ) def test_sale_with_line_items_validation_error_unit_tax_amount_format_is_invalid(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.2322", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.2322", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.0122", "unit_tax_amount": "2.012", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitTaxAmountFormatIsInvalid, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_tax_amount")[0].code ) def test_sale_with_line_items_validation_error_unit_tax_amount_is_too_large(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.2322", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_tax_amount": "1.23", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.2322", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.0122", "unit_tax_amount": "2147483648", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitTaxAmountIsTooLarge, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_tax_amount")[0].code ) def test_sale_with_line_items_validation_error_unit_tax_amount_cannot_be_negative(self): result = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.2322", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }, { "quantity": "1.2322", "name": "Name #2", "kind": TransactionLineItem.Kind.Credit, "unit_amount": "45.0122", "unit_tax_amount": "-1.23", "unit_of_measure": "gallon", "discount_amount": "1.02", "total_amount": "45.15", "product_code": "23434", "commodity_code": "9SAASSD8724", }] }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.LineItem.UnitTaxAmountCannotBeNegative, result.errors.for_object("transaction").for_object("line_items").for_object("index_1").on("unit_tax_amount")[0].code ) def test_sale_with_line_items_validation_error_too_many_live_items(self): sale_params = { "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [], } for i in range(250): sale_params["line_items"].append({ "quantity": "2.02", "name": "Line item #" + str(i), "kind": TransactionLineItem.Kind.Credit, "unit_amount": "5", "unit_of_measure": "gallon", "total_amount": "10.1", }) result = Transaction.sale(sale_params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.TooManyLineItems, result.errors.for_object("transaction").on("line_items")[0].code ) def test_sale_with_debit_network(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.pinless_debit_merchant_account_id, "payment_method_nonce": Nonces.TransactablePinlessDebitVisa, "options": { "submit_for_settlement": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertTrue(hasattr(transaction, 'debit_network')) self.assertIsNotNone(transaction.debit_network) def test_pinless_eligible_sale_with_process_debit_as_credit(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.pinless_debit_merchant_account_id, "payment_method_nonce": Nonces.TransactablePinlessDebitVisa, "options": { "submit_for_settlement": True, "credit_card":{ "process_debit_as_credit": True, } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertIsNone(transaction.debit_network) def test_validation_error_on_invalid_custom_fields(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "custom_fields": { "invalid_key": "some extra stuff" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CustomFieldIsInvalid, result.errors.for_object("transaction").on("custom_fields")[0].code ) def test_card_type_indicators(self): result = Transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": CreditCardNumbers.CardTypeIndicators.Unknown, "expiration_month": "05", "expiration_year": "2012" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(CreditCard.Prepaid.Unknown, transaction.credit_card_details.prepaid) self.assertEqual(CreditCard.Debit.Unknown, transaction.credit_card_details.debit) self.assertEqual(CreditCard.Commercial.Unknown, transaction.credit_card_details.commercial) self.assertEqual(CreditCard.Healthcare.Unknown, transaction.credit_card_details.healthcare) self.assertEqual(CreditCard.Payroll.Unknown, transaction.credit_card_details.payroll) self.assertEqual(CreditCard.DurbinRegulated.Unknown, transaction.credit_card_details.durbin_regulated) self.assertEqual(CreditCard.CardTypeIndicator.Unknown, transaction.credit_card_details.issuing_bank) self.assertEqual(CreditCard.CardTypeIndicator.Unknown, transaction.credit_card_details.country_of_issuance) self.assertEqual(CreditCard.ProductId.Unknown, transaction.credit_card_details.product_id) def test_create_can_set_recurring_flag(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "recurring": True }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(True, transaction.recurring) def test_create_recurring_flag_sends_deprecation_warning(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "recurring": True }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(True, transaction.recurring) assert len(w) > 0 assert issubclass(w[-1].category, DeprecationWarning) assert "Use transaction_source parameter instead" in str(w[-1].message) def test_create_can_set_transaction_source_flag_recurring_first(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "recurring_first" }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(True, transaction.recurring) def test_create_can_set_transaction_source_flag_recurring(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "recurring" }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(True, transaction.recurring) def test_create_can_set_transaction_source_installment_first(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "installment_first" }) self.assertTrue(result.is_success) def test_create_can_set_transaction_source_flag_installment(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "installment" }) self.assertTrue(result.is_success) def test_create_can_set_transaction_source_flag_merchant(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "merchant" }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(False, transaction.recurring) def test_create_can_set_transaction_source_flag_moto(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "moto" }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(False, transaction.recurring) def test_create_can_set_transaction_source_flag_invalid(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "transaction_source": "invalid_value" }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.TransactionSourceIsInvalid, result.errors.for_object("transaction").on("transaction_source")[0].code ) def test_create_can_store_customer_and_credit_card_in_the_vault(self): result = Transaction.sale({ "amount": "100", "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "store_in_vault": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", transaction.customer_details.id)) self.assertEqual(transaction.customer_details.id, transaction.vault_customer.id) self.assertNotEqual(None, re.search(r"\A\w{4,}\Z", transaction.credit_card_details.token)) self.assertEqual(transaction.credit_card_details.token, transaction.vault_credit_card.token) def test_create_can_store_customer_and_credit_card_in_the_vault_on_success(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "store_in_vault_on_success": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", transaction.customer_details.id)) self.assertEqual(transaction.customer_details.id, transaction.vault_customer.id) self.assertNotEqual(None, re.search(r"\A\w{4,}\Z", transaction.credit_card_details.token)) self.assertEqual(transaction.credit_card_details.token, transaction.vault_credit_card.token) def test_create_does_not_store_customer_and_credit_card_in_the_vault_on_failure(self): result = Transaction.sale({ "amount": TransactionAmounts.Decline, "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "store_in_vault_on_success": True } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(None, transaction.customer_details.id) self.assertEqual(None, transaction.credit_card_details.token) self.assertEqual(None, transaction.vault_customer) self.assertEqual(None, transaction.vault_credit_card) def test_create_associated_a_billing_address_with_credit_card_in_vault(self): result = Transaction.sale({ "amount": "100", "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "5105105105105100", "expiration_date": "05/2012" }, "billing": { "first_name": "Carl", "last_name": "Jones", "company": "Braintree", "street_address": "123 E Main St", "extended_address": "Suite 403", "locality": "Chicago", "region": "IL", "postal_code": "60622", "country_name": "United States of America" }, "options": { "store_in_vault": True, "add_billing_address_to_payment_method": True, } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", transaction.customer_details.id)) self.assertEqual(transaction.customer_details.id, transaction.vault_customer.id) credit_card = CreditCard.find(transaction.vault_credit_card.token) self.assertEqual(credit_card.billing_address.id, transaction.billing_details.id) self.assertEqual(credit_card.billing_address.id, transaction.vault_billing_address.id) self.assertEqual("Carl", credit_card.billing_address.first_name) self.assertEqual("Jones", credit_card.billing_address.last_name) self.assertEqual("Braintree", credit_card.billing_address.company) self.assertEqual("123 E Main St", credit_card.billing_address.street_address) self.assertEqual("Suite 403", credit_card.billing_address.extended_address) self.assertEqual("Chicago", credit_card.billing_address.locality) self.assertEqual("IL", credit_card.billing_address.region) self.assertEqual("60622", credit_card.billing_address.postal_code) self.assertEqual("United States of America", credit_card.billing_address.country_name) def test_create_and_store_the_shipping_address_in_the_vault(self): result = Transaction.sale({ "amount": "100", "customer": { "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "number": "5105105105105100", "expiration_date": "05/2012" }, "shipping": { "first_name": "Carl", "last_name": "Jones", "company": "Braintree", "street_address": "123 E Main St", "extended_address": "Suite 403", "locality": "Chicago", "region": "IL", "postal_code": "60622", "country_name": "United States of America" }, "options": { "store_in_vault": True, "store_shipping_address_in_vault": True, } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\d{6,}\Z", transaction.customer_details.id)) self.assertEqual(transaction.customer_details.id, transaction.vault_customer.id) shipping_address = transaction.vault_customer.addresses[0] self.assertEqual("Carl", shipping_address.first_name) self.assertEqual("Jones", shipping_address.last_name) self.assertEqual("Braintree", shipping_address.company) self.assertEqual("123 E Main St", shipping_address.street_address) self.assertEqual("Suite 403", shipping_address.extended_address) self.assertEqual("Chicago", shipping_address.locality) self.assertEqual("IL", shipping_address.region) self.assertEqual("60622", shipping_address.postal_code) self.assertEqual("United States of America", shipping_address.country_name) def test_create_submits_for_settlement_if_given_submit_for_settlement_option(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2012" }, "options": { "submit_for_settlement": True } }) self.assertTrue(result.is_success) self.assertEqual(Transaction.Status.SubmittedForSettlement, result.transaction.status) def test_create_does_not_submit_for_settlement_if_submit_for_settlement_is_false(self): result = Transaction.sale({ "amount": "100", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2012" }, "options": { "submit_for_settlement": False } }) self.assertTrue(result.is_success) self.assertEqual(Transaction.Status.Authorized, result.transaction.status) def test_create_can_specify_the_customer_id_and_payment_method_token(self): customer_id = "customer_" + str(random.randint(1, 1000000)) payment_method_token = "credit_card_" + str(random.randint(1, 1000000)) result = Transaction.sale({ "amount": "100", "customer": { "id": customer_id, "first_name": "Adam", "last_name": "Williams" }, "credit_card": { "token": payment_method_token, "number": "5105105105105100", "expiration_date": "05/2012" }, "options": { "store_in_vault": True } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(customer_id, transaction.customer_details.id) self.assertEqual(customer_id, transaction.vault_customer.id) self.assertEqual(payment_method_token, transaction.credit_card_details.token) self.assertEqual(payment_method_token, transaction.vault_credit_card.token) def test_create_using_customer_id(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }) self.assertTrue(result.is_success) customer = result.customer credit_card = customer.credit_cards[0] result = Transaction.sale({ "amount": "100", "customer_id": customer.id }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(customer.id, transaction.customer_details.id) self.assertEqual(customer.id, transaction.vault_customer.id) self.assertEqual(credit_card.token, transaction.credit_card_details.token) self.assertEqual(credit_card.token, transaction.vault_credit_card.token) def test_create_using_payment_method_token(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }) self.assertTrue(result.is_success) customer = result.customer credit_card = customer.credit_cards[0] result = Transaction.sale({ "amount": "100", "payment_method_token": credit_card.token }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(customer.id, transaction.customer_details.id) self.assertEqual(customer.id, transaction.vault_customer.id) self.assertEqual(credit_card.token, transaction.credit_card_details.token) self.assertEqual(credit_card.token, transaction.vault_credit_card.token) def test_create_using_payment_method_token_with_cvv(self): result = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }) self.assertTrue(result.is_success) customer = result.customer credit_card = customer.credit_cards[0] result = Transaction.sale({ "amount": "100", "payment_method_token": credit_card.token, "credit_card": { "cvv": "301" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(customer.id, transaction.customer_details.id) self.assertEqual(customer.id, transaction.vault_customer.id) self.assertEqual(credit_card.token, transaction.credit_card_details.token) self.assertEqual(credit_card.token, transaction.vault_credit_card.token) self.assertEqual("S", transaction.cvv_response_code) def test_create_with_failing_validations(self): params = { "transaction": { "amount": None, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } } } result = Transaction.sale(params["transaction"]) params["transaction"]["credit_card"].pop("number") self.assertFalse(result.is_success) self.assertEqual(params, result.params) self.assertEqual( ErrorCodes.Transaction.AmountIsRequired, result.errors.for_object("transaction").on("amount")[0].code ) def test_credit_with_a_successful_result(self): result = Transaction.credit({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\w{6,}\Z", transaction.id)) self.assertEqual(Transaction.Type.Credit, transaction.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) cc_details = transaction.credit_card_details self.assertEqual("411111", cc_details.bin) self.assertEqual("1111", cc_details.last_4) self.assertEqual("05/2009", cc_details.expiration_date) def test_credit_with_unsuccessful_result(self): result = Transaction.credit({ "amount": None, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) params = { "transaction": { "type": Transaction.Type.Credit, "amount": None, "credit_card": { "expiration_date": "05/2009" } } } self.assertFalse(result.is_success) self.assertEqual(params, result.params) self.assertEqual( ErrorCodes.Transaction.AmountIsRequired, result.errors.for_object("transaction").on("amount")[0].code ) def test_credit_card_payment_instrument_type_is_credit_card(self): result = Transaction.credit({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual( PaymentInstrumentType.CreditCard, transaction.payment_instrument_type ) def test_service_fee_not_allowed_with_credits(self): result = Transaction.credit({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "service_fee_amount": "1.00" }) self.assertFalse(result.is_success) self.assertTrue( ErrorCodes.Transaction.ServiceFeeIsNotAllowedOnCredits in [error.code for error in result.errors.for_object("transaction").on("base")] ) def test_credit_with_merchant_account_id(self): result = Transaction.credit({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.non_default_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(TestHelper.non_default_merchant_account_id, transaction.merchant_account_id) def test_credit_without_merchant_account_id_falls_back_to_default(self): result = Transaction.credit({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(TestHelper.default_merchant_account_id, transaction.merchant_account_id) def test_find_returns_a_found_transaction(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Fail, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction TestHelper.settle_transaction(transaction.id) found_transaction = Transaction.find(transaction.id) self.assertEqual(transaction.id, found_transaction.id) self.assertNotEqual(None, transaction.graphql_id) def test_find_for_bad_transaction_raises_not_found_error(self): with self.assertRaisesRegex(NotFoundError, "transaction with id 'notreal' not found"): Transaction.find("notreal") def test_void_with_successful_result(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction result = Transaction.void(transaction.id) self.assertTrue(result.is_success) self.assertEqual(transaction.id, result.transaction.id) self.assertEqual(Transaction.Status.Voided, result.transaction.status) def test_void_with_unsuccessful_result(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Decline, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction result = Transaction.void(transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotBeVoided, result.errors.for_object("transaction").on("base")[0].code ) def test_create_with_successful_result(self): result = Transaction.create({ "type": Transaction.Type.Sale, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) def test_create_with_error_result(self): result = Transaction.create({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "billing": { "country_code_alpha2": "ZZ", "country_code_alpha3": "ZZZ", "country_code_numeric": "000", "country_name": "zzzzzz" } }) self.assertFalse(result.is_success) self.assertEqual(ErrorCodes.Transaction.TypeIsRequired, result.errors.for_object("transaction").on("type")[0].code) self.assertEqual( ErrorCodes.Address.CountryCodeAlpha2IsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_code_alpha2")[0].code ) self.assertEqual( ErrorCodes.Address.CountryCodeAlpha3IsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_code_alpha3")[0].code ) self.assertEqual( ErrorCodes.Address.CountryCodeNumericIsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_code_numeric")[0].code ) self.assertEqual( ErrorCodes.Address.CountryNameIsNotAccepted, result.errors.for_object("transaction").for_object("billing").on("country_name")[0].code ) def test_submit_for_settlement_without_amount(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual(Decimal(TransactionAmounts.Authorize), submitted_transaction.amount) def test_submit_for_settlement_with_amount(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction submitted_transaction = Transaction.submit_for_settlement(transaction.id, Decimal("900")).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual(Decimal("900.00"), submitted_transaction.amount) def test_submit_for_settlement_with_order_id(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = {"order_id": "ABC123"} submitted_transaction = Transaction.submit_for_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual("ABC123", submitted_transaction.order_id) def test_submit_for_settlement_with_descriptor(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = { "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" } } submitted_transaction = Transaction.submit_for_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual("123*123456789012345678", submitted_transaction.descriptor.name) self.assertEqual("3334445555", submitted_transaction.descriptor.phone) self.assertEqual("ebay.com", submitted_transaction.descriptor.url) def test_submit_for_settlement_with_level_2_data(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = {"purchase_order_number": "123456", "tax_amount": "2.00", "tax_exempt": False} submitted_transaction = Transaction.submit_for_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) def test_submit_for_settlement_with_level_3_data(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = { "discount_amount": "12.33", "shipping_amount": "5.00", "shipping_tax_amount": "2.00", "ships_from_postal_code": "90210", "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "total_amount": "45.15", }] } submitted_transaction = Transaction.submit_for_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Decimal("2.00"), submitted_transaction.shipping_tax_amount) self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) def test_submit_for_settlement_with_shipping_data(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = { "discount_amount": "12.33", "shipping_amount": "5.00", "ships_from_postal_code": "90210", "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", } } submitted_transaction = Transaction.submit_for_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) 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", } with self.assertRaisesRegex(KeyError, "'Invalid keys: invalid_param'"): Transaction.submit_for_settlement(transaction.id, Decimal("900"), params) def test_submit_for_settlement_with_validation_error(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction result = Transaction.submit_for_settlement(transaction.id, Decimal("1200")) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.SettlementAmountIsTooLarge, result.errors.for_object("transaction").on("amount")[0].code ) def test_submit_for_settlement_with_validation_error_on_service_fee(self): transaction = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "service_fee_amount": "5.00" }).transaction result = Transaction.submit_for_settlement(transaction.id, "1.00") self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.SettlementAmountIsLessThanServiceFeeAmount, result.errors.for_object("transaction").on("amount")[0].code ) def test_submit_for_settlement_with_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": { "submit_for_settlement": False } }) self.assertTrue(result.is_success) params = { "industry": { "industry_type": Transaction.IndustryType.TravelAndFlight, "data": { "passenger_first_name": "John", "passenger_last_name": "Doe", "passenger_middle_initial": "M", "passenger_title": "Mr.", "issued_date": date(2018, 1, 1), "travel_agency_name": "Expedia", "travel_agency_code": "12345678", "ticket_number": "ticket-number", "issuing_carrier_code": "AA", "customer_code": "customer-code", "fare_amount": "70.00", "fee_amount": "10.00", "tax_amount": "20.00", "restricted_ticket": False, "date_of_birth": "2012-12-12", "country_code": "US", "legs": [ { "conjunction_ticket": "CJ0001", "exchange_ticket": "ET0001", "coupon_number": "1", "service_class": "Y", "carrier_code": "AA", "fare_basis_code": "W", "flight_number": "AA100", "departure_date": date(2018, 1, 2), "departure_airport_code": "MDW", "departure_time": "08:00", "arrival_airport_code": "ATX", "arrival_time": "10:00", "stopover_permitted": False, "fare_amount": "35.00", "fee_amount": "5.00", "tax_amount": "10.00", "endorsement_or_restrictions": "NOT REFUNDABLE" }, { "conjunction_ticket": "CJ0002", "exchange_ticket": "ET0002", "coupon_number": "1", "service_class": "Y", "carrier_code": "AA", "fare_basis_code": "W", "flight_number": "AA200", "departure_date": date(2018, 1, 3), "departure_airport_code": "ATX", "departure_time": "12:00", "arrival_airport_code": "MDW", "arrival_time": "14:00", "stopover_permitted": False, "fare_amount": "35.00", "fee_amount": "5.00", "tax_amount": "10.00", "endorsement_or_restrictions": "NOT REFUNDABLE" } ] } } } submitted_transaction = Transaction.submit_for_settlement(result.transaction.id, TransactionAmounts.Authorize, params).transaction self.assertEqual(Transaction.Status.Settling, submitted_transaction.status) def test_submit_for_partial_settlement_with_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": { "submit_for_settlement": False } }) self.assertTrue(result.is_success) params = { "industry": { "industry_type": Transaction.IndustryType.TravelAndFlight, "data": { "passenger_first_name": "John", "passenger_last_name": "Doe", "passenger_middle_initial": "M", "passenger_title": "Mr.", "issued_date": date(2018, 1, 1), "travel_agency_name": "Expedia", "travel_agency_code": "12345678", "ticket_number": "ticket-number", "issuing_carrier_code": "AA", "customer_code": "customer-code", "fare_amount": "70.00", "fee_amount": "10.00", "tax_amount": "20.00", "restricted_ticket": False, "date_of_birth": "2012-12-12", "country_code": "US", "legs": [ { "conjunction_ticket": "CJ0001", "exchange_ticket": "ET0001", "coupon_number": "1", "service_class": "Y", "carrier_code": "AA", "fare_basis_code": "W", "flight_number": "AA100", "departure_date": date(2018, 1, 2), "departure_airport_code": "MDW", "departure_time": "08:00", "arrival_airport_code": "ATX", "arrival_time": "10:00", "stopover_permitted": False, "fare_amount": "35.00", "fee_amount": "5.00", "tax_amount": "10.00", "endorsement_or_restrictions": "NOT REFUNDABLE" }, { "conjunction_ticket": "CJ0002", "exchange_ticket": "ET0002", "coupon_number": "1", "service_class": "Y", "carrier_code": "AA", "fare_basis_code": "W", "flight_number": "AA200", "departure_date": date(2018, 1, 3), "departure_airport_code": "ATX", "departure_time": "12:00", "arrival_airport_code": "MDW", "arrival_time": "14:00", "stopover_permitted": False, "fare_amount": "35.00", "fee_amount": "5.00", "tax_amount": "10.00", "endorsement_or_restrictions": "NOT REFUNDABLE" } ] } } } submitted_transaction = Transaction.submit_for_partial_settlement(result.transaction.id, Decimal("500.00"), params).transaction self.assertEqual(Transaction.Status.Settling, submitted_transaction.status) def test_update_details_with_valid_params(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } }).transaction params = { "amount" : "9.00", "order_id": "123", "descriptor": { "name": "456*123456789012345678", "phone": "3334445555", "url": "ebay.com" } } result = Transaction.update_details(transaction.id, params) self.assertTrue(result.is_success) self.assertEqual(Decimal("9.00"), result.transaction.amount) self.assertEqual(Transaction.Status.SubmittedForSettlement, result.transaction.status) self.assertEqual("123", result.transaction.order_id) self.assertEqual("456*123456789012345678", result.transaction.descriptor.name) self.assertEqual("3334445555", result.transaction.descriptor.phone) self.assertEqual("ebay.com", result.transaction.descriptor.url) def test_update_details_with_invalid_params(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True }, }).transaction params = { "amount" : "9.00", "invalid_key": "invalid_value", "order_id": "123", "descriptor": { "name": "456*123456789012345678", "phone": "3334445555", "url": "ebay.com" } } with self.assertRaisesRegex(KeyError, "'Invalid keys: invalid_key'"): Transaction.update_details(transaction.id, params) def test_update_details_with_invalid_order_id(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True }, }).transaction params = { "amount" : "9.00", "order_id": "A" * 256, "descriptor": { "name": "456*123456789012345678", "phone": "3334445555", "url": "ebay.com" } } result = Transaction.update_details(transaction.id, params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.OrderIdIsTooLong, result.errors.for_object("transaction").on("order_id")[0].code ) def test_update_details_with_invalid_descriptor(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True }, }).transaction params = { "amount" : "9.00", "order_id": "123", "descriptor": { "name": "invalid name", "phone": "invalid phone", "url": "12345678901234567890" } } result = Transaction.update_details(transaction.id, params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Descriptor.NameFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("name")[0].code ) self.assertEqual( ErrorCodes.Descriptor.PhoneFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("phone")[0].code ) self.assertEqual( ErrorCodes.Descriptor.UrlFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("url")[0].code ) def test_update_details_with_invalid_amount(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True }, }).transaction params = { "amount" : "999.00", "order_id": "123", } result = Transaction.update_details(transaction.id, params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.SettlementAmountIsTooLarge, result.errors.for_object("transaction").on("amount")[0].code ) def test_update_details_with_invalid_status(self): transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, }).transaction params = { "amount" : "9.00", "order_id": "123", } result = Transaction.update_details(transaction.id, params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotUpdateTransactionDetailsNotSubmittedForSettlement, result.errors.for_object("transaction").on("base")[0].code ) def test_update_details_with_invalid_processor(self): transaction = Transaction.sale({ "amount": "10.00", "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.Success, "expiration_date": "05/2020" }, "options": { "submit_for_settlement": True }, }).transaction params = { "amount" : "9.00", "order_id": "123", } result = Transaction.update_details(transaction.id, params) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ProcessorDoesNotSupportUpdatingTransactionDetails, result.errors.for_object("transaction").on("base")[0].code ) def test_status_history(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEqual(2, len(submitted_transaction.status_history)) self.assertEqual(Transaction.Status.Authorized, submitted_transaction.status_history[0].status) self.assertEqual(Decimal(TransactionAmounts.Authorize), submitted_transaction.status_history[0].amount) self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status_history[1].status) self.assertEqual(Decimal(TransactionAmounts.Authorize), submitted_transaction.status_history[1].amount) def test_successful_refund(self): transaction = self.__create_transaction_to_refund() result = Transaction.refund(transaction.id) self.assertTrue(result.is_success) refund = result.transaction self.assertEqual(Transaction.Type.Credit, refund.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), refund.amount) self.assertEqual(transaction.id, refund.refunded_transaction_id) self.assertEqual(refund.id, Transaction.find(transaction.id).refund_id) def test_successful_partial_refund(self): transaction = self.__create_transaction_to_refund() result = Transaction.refund(transaction.id, Decimal("500.00")) self.assertTrue(result.is_success) self.assertEqual(Transaction.Type.Credit, result.transaction.type) self.assertEqual(Decimal("500.00"), result.transaction.amount) def test_multiple_successful_partial_refunds(self): transaction = self.__create_transaction_to_refund() refund1 = Transaction.refund(transaction.id, Decimal("500.00")).transaction self.assertEqual(Transaction.Type.Credit, refund1.type) self.assertEqual(Decimal("500.00"), refund1.amount) refund2 = Transaction.refund(transaction.id, Decimal("500.00")).transaction self.assertEqual(Transaction.Type.Credit, refund2.type) self.assertEqual(Decimal("500.00"), refund2.amount) transaction = Transaction.find(transaction.id) self.assertEqual(2, len(transaction.refund_ids)) self.assertTrue(TestHelper.in_list(transaction.refund_ids, refund1.id)) self.assertTrue(TestHelper.in_list(transaction.refund_ids, refund2.id)) def test_refund_already_refunded_transation_fails(self): transaction = self.__create_transaction_to_refund() Transaction.refund(transaction.id) result = Transaction.refund(transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.HasAlreadyBeenRefunded, result.errors.for_object("transaction").on("base")[0].code ) def test_refund_with_options_params(self): transaction = self.__create_transaction_to_refund() options = { "amount": Decimal("1.00"), "order_id": "abcd", "merchant_account_id": TestHelper.non_default_merchant_account_id } result = Transaction.refund(transaction.id, options) self.assertTrue(result.is_success) self.assertEqual( "abcd", result.transaction.order_id ) self.assertEqual( Decimal("1.00"), result.transaction.amount ) self.assertEqual( TestHelper.non_default_merchant_account_id, result.transaction.merchant_account_id ) def test_refund_returns_an_error_if_unsettled(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } }).transaction result = Transaction.refund(transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotRefundUnlessSettled, result.errors.for_object("transaction").on("base")[0].code ) def test_refund_returns_an_error_if_soft_declined(self): transaction = Transaction.sale({ "amount": Decimal("9000.00"), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } }).transaction TestHelper.settle_transaction(transaction.id) result = Transaction.refund(transaction.id, Decimal("2046.00")) refund = result.transaction self.assertFalse(result.is_success) self.assertEqual(Transaction.Status.ProcessorDeclined, refund.status) self.assertEqual(ProcessorResponseTypes.SoftDeclined, refund.processor_response_type) self.assertEqual("2046 : Declined", refund.additional_processor_response) def test_refund_returns_an_error_if_hard_declined(self): transaction = Transaction.sale({ "amount": Decimal("9000.00"), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } }).transaction TestHelper.settle_transaction(transaction.id) result = Transaction.refund(transaction.id, Decimal("2009.00")) refund = result.transaction self.assertFalse(result.is_success) self.assertEqual(Transaction.Status.ProcessorDeclined, refund.status) self.assertEqual(ProcessorResponseTypes.HardDeclined, refund.processor_response_type) self.assertEqual("2009 : No Such Issuer", refund.additional_processor_response) @staticmethod def __create_transaction_to_refund(): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } }).transaction TestHelper.settle_transaction(transaction.id) return transaction @staticmethod def __create_paypal_transaction(): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": { "submit_for_settlement": True } }).transaction return transaction @staticmethod def __create_escrowed_transaction(): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" }, "service_fee_amount": "10.00", "merchant_account_id": TestHelper.non_default_sub_merchant_account_id, "options": { "hold_in_escrow": True } }).transaction TestHelper.escrow_transaction(transaction.id) return transaction @staticmethod def __first_data_transaction_params(): merchant_dict = { "merchant_account_id": TestHelper.fake_first_data_merchant_account_id, "amount": "75.50", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2012" }, } return merchant_dict @staticmethod def __first_data_visa_transaction_params(): merchant_dict = { "merchant_account_id": TestHelper.fake_first_data_merchant_account_id, "amount": "75.50", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2012" } } return merchant_dict def test_snapshot_plan_id_add_ons_and_discounts_from_subscription(self): credit_card = Customer.create({ "first_name": "Mike", "last_name": "Jones", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" } }).customer.credit_cards[0] result = Subscription.create({ "payment_method_token": credit_card.token, "plan_id": TestHelper.trialless_plan["id"], "add_ons": { "add": [ { "amount": Decimal("11.00"), "inherited_from_id": "increase_10", "quantity": 2, "number_of_billing_cycles": 5 }, { "amount": Decimal("21.00"), "inherited_from_id": "increase_20", "quantity": 3, "number_of_billing_cycles": 6 } ] }, "discounts": { "add": [ { "amount": Decimal("7.50"), "inherited_from_id": "discount_7", "quantity": 2, "never_expires": True } ] } }) transaction = result.subscription.transactions[0] self.assertEqual(TestHelper.trialless_plan["id"], transaction.plan_id) self.assertEqual(2, len(transaction.add_ons)) add_ons = sorted(transaction.add_ons, key=lambda add_on: add_on.id) self.assertEqual("increase_10", add_ons[0].id) self.assertEqual(Decimal("11.00"), add_ons[0].amount) self.assertEqual(2, add_ons[0].quantity) self.assertEqual(5, add_ons[0].number_of_billing_cycles) self.assertFalse(add_ons[0].never_expires) self.assertEqual("increase_20", add_ons[1].id) self.assertEqual(Decimal("21.00"), add_ons[1].amount) self.assertEqual(3, add_ons[1].quantity) self.assertEqual(6, add_ons[1].number_of_billing_cycles) self.assertFalse(add_ons[1].never_expires) self.assertEqual(1, len(transaction.discounts)) discounts = transaction.discounts self.assertEqual("discount_7", discounts[0].id) self.assertEqual(Decimal("7.50"), discounts[0].amount) self.assertEqual(2, discounts[0].quantity) self.assertEqual(None, discounts[0].number_of_billing_cycles) self.assertTrue(discounts[0].never_expires) def test_transactions_accept_lodging_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "industry": { "industry_type": Transaction.IndustryType.Lodging, "data": { "folio_number": "aaa", "check_in_date": "2014-07-07", "check_out_date": "2014-07-11", "room_rate": "170.00", "room_tax": "30.00", "no_show": False, "advanced_deposit": False, "fire_safe": True, "property_phone": "1112223345", "additional_charges": [ { "kind": Transaction.AdditionalCharge.Restaurant, "amount": "50.00" }, { "kind": Transaction.AdditionalCharge.Other, "amount": "150.00" } ] } } }) self.assertTrue(result.is_success) def test_transactions_return_validation_errors_on_lodging_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "industry": { "industry_type": Transaction.IndustryType.Lodging, "data": { "folio_number": "aaa", "check_in_date": "2014-07-07", "check_out_date": "2014-06-06", "room_rate": "asdfsdf", "additional_charges": [ { "kind": "unknown", "amount": "20.00" } ] } } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Industry.Lodging.CheckOutDateMustFollowCheckInDate, result.errors.for_object("transaction").for_object("industry").on("check_out_date")[0].code ) self.assertEqual( ErrorCodes.Transaction.Industry.Lodging.RoomRateFormatIsInvalid, result.errors.for_object("transaction").for_object("industry").on("room_rate")[0].code ) self.assertEqual( ErrorCodes.Transaction.Industry.AdditionalCharge.KindIsInvalid, result.errors.for_object("transaction").for_object("industry").for_object("additional_charges").for_object("index_0").on("kind")[0].code ) def test_transactions_accept_travel_cruise_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "industry": { "industry_type": Transaction.IndustryType.TravelAndCruise, "data": { "travel_package": "flight", "departure_date": "2014-07-07", "lodging_check_in_date": "2014-07-07", "lodging_check_out_date": "2014-09-07", "lodging_name": "Royal Caribbean" } } }) self.assertTrue(result.is_success) def test_transactions_return_validation_errors_on_travel_cruise_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "industry": { "industry_type": Transaction.IndustryType.TravelAndCruise, "data": { "travel_package": "roadtrip", "departure_date": "2014-07-07", "lodging_check_in_date": "2014-07-07", "lodging_check_out_date": "2014-09-07", "lodging_name": "Royal Caribbean" } } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Industry.TravelCruise.TravelPackageIsInvalid, result.errors.for_object("transaction").for_object("industry").on("travel_package")[0].code ) def test_transactions_accept_travel_flight_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"submit_for_settlement": True}, "industry": { "industry_type": Transaction.IndustryType.TravelAndFlight, "data": { "passenger_first_name": "John", "passenger_last_name": "Doe", "passenger_middle_initial": "M", "passenger_title": "Mr.", "issued_date": date(2018, 1, 1), "travel_agency_name": "Expedia", "travel_agency_code": "12345678", "ticket_number": "ticket-number", "issuing_carrier_code": "AA", "customer_code": "customer-code", "fare_amount": "70.00", "fee_amount": "10.00", "tax_amount": "20.00", "restricted_ticket": False, "arrival_date": date(2022, 2, 3), "ticket_issuer_address": "ti-address", "date_of_birth": "2012-12-12", "country_code": "US", "legs": [ { "conjunction_ticket": "CJ0001", "exchange_ticket": "ET0001", "coupon_number": "1", "service_class": "Y", "carrier_code": "AA", "fare_basis_code": "W", "flight_number": "AA100", "departure_date": date(2018, 1, 2), "departure_airport_code": "MDW", "departure_time": "08:00", "arrival_airport_code": "ATX", "arrival_time": "10:00", "stopover_permitted": False, "fare_amount": "35.00", "fee_amount": "5.00", "tax_amount": "10.00", "endorsement_or_restrictions": "NOT REFUNDABLE" }, { "conjunction_ticket": "CJ0002", "exchange_ticket": "ET0002", "coupon_number": "1", "service_class": "Y", "carrier_code": "AA", "fare_basis_code": "W", "flight_number": "AA200", "departure_date": date(2018, 1, 3), "departure_airport_code": "ATX", "departure_time": "12:00", "arrival_airport_code": "MDW", "arrival_time": "14:00", "stopover_permitted": False, "fare_amount": "35.00", "fee_amount": "5.00", "tax_amount": "10.00", "endorsement_or_restrictions": "NOT REFUNDABLE" } ] } } }) self.assertTrue(result.is_success) def test_transaction_submit_for_settlement_with_travel_flight_industry_data(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.fake_first_data_merchant_account_id, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = { "industry": { "industry_type": Transaction.IndustryType.TravelAndFlight, "data": { "passenger_first_name": "John", "passenger_last_name": "Doe", "passenger_middle_initial": "M", "passenger_title": "Mr.", "issued_date": date(2018, 1, 1), "travel_agency_name": "Expedia", "travel_agency_code": "12345678", "ticket_number": "ticket-number", "issuing_carrier_code": "AA", "customer_code": "customer-code", "fare_amount": "70.00", "fee_amount": "10.00", "tax_amount": "20.00", "restricted_ticket": False, "arrival_date": date(2022, 2, 3), "ticket_issuer_address": "ti-address", "legs": [ { "conjunction_ticket": "CJ0001", "exchange_ticket": "ET0001", "coupon_number": "1", "service_class": "Y", "carrier_code": "AA", "fare_basis_code": "W", "flight_number": "AA100", "departure_date": date(2018, 1, 2), "departure_airport_code": "MDW", "departure_time": "08:00", "arrival_airport_code": "ATX", "arrival_time": "10:00", "stopover_permitted": False, "fare_amount": "35.00", "fee_amount": "5.00", "tax_amount": "10.00", "endorsement_or_restrictions": "NOT REFUNDABLE" }, { "conjunction_ticket": "CJ0002", "exchange_ticket": "ET0002", "coupon_number": "1", "service_class": "Y", "carrier_code": "AA", "fare_basis_code": "W", "flight_number": "AA200", "departure_date": date(2018, 1, 3), "departure_airport_code": "ATX", "departure_time": "12:00", "arrival_airport_code": "MDW", "arrival_time": "14:00", "stopover_permitted": False, "fare_amount": "35.00", "fee_amount": "5.00", "tax_amount": "10.00", "endorsement_or_restrictions": "NOT REFUNDABLE" } ] } } } submitted_transaction = Transaction.submit_for_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) def test_transactions_return_validation_errors_on_travel_flight_industry_data(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"submit_for_settlement": True}, "industry": { "industry_type": Transaction.IndustryType.TravelAndFlight, "data": { "fare_amount": "-1.23", "legs": [ { "fare_amount": "-1.23" } ] } } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Industry.TravelFlight.FareAmountCannotBeNegative, result.errors.for_object("transaction").for_object("industry").on("fare_amount")[0].code ) self.assertEqual( ErrorCodes.Transaction.Industry.Leg.TravelFlight.FareAmountCannotBeNegative, result.errors.for_object("transaction").for_object("industry").for_object("legs").for_object("index_0").on("fare_amount")[0].code ) def test_descriptors_accepts_name_phone_and_url(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("123*123456789012345678", transaction.descriptor.name) self.assertEqual("3334445555", transaction.descriptor.phone) self.assertEqual("ebay.com", transaction.descriptor.url) def test_descriptors_has_validation_errors_if_format_is_invalid(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "descriptor": { "name": "badcompanyname12*badproduct12", "phone": "%bad4445555", "url": "12345678901234" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Descriptor.NameFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("name")[0].code ) self.assertEqual( ErrorCodes.Descriptor.PhoneFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("phone")[0].code ) self.assertEqual( ErrorCodes.Descriptor.UrlFormatIsInvalid, result.errors.for_object("transaction").for_object("descriptor").on("url")[0].code ) def test_clone_transaction(self): result = Transaction.sale({ "amount": "100.00", "order_id": "123", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2011", }, "customer": { "first_name": "Dan", }, "billing": { "first_name": "Carl", }, "shipping": { "first_name": "Andrew", } }) self.assertTrue(result.is_success) transaction = result.transaction clone_result = Transaction.clone_transaction( transaction.id, { "amount": "123.45", "channel": "MyShoppingCartProvider", "options": {"submit_for_settlement": "false"} }) self.assertTrue(clone_result.is_success) clone_transaction = clone_result.transaction self.assertNotEqual(transaction.id, clone_transaction.id) self.assertEqual(Transaction.Type.Sale, clone_transaction.type) self.assertEqual(Transaction.Status.Authorized, clone_transaction.status) self.assertEqual(Decimal("123.45"), clone_transaction.amount) self.assertEqual("MyShoppingCartProvider", clone_transaction.channel) self.assertEqual("123", clone_transaction.order_id) self.assertEqual("51051051****5100", clone_transaction.credit_card_details.masked_number) self.assertEqual("Dan", clone_transaction.customer_details.first_name) self.assertEqual("Carl", clone_transaction.billing_details.first_name) self.assertEqual("Andrew", clone_transaction.shipping_details.first_name) def test_clone_transaction_submits_for_settlement(self): result = Transaction.sale({ "amount": "100.00", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2011", } }) self.assertTrue(result.is_success) transaction = result.transaction clone_result = Transaction.clone_transaction(transaction.id, {"amount": "123.45", "options": {"submit_for_settlement": "true"}}) self.assertTrue(clone_result.is_success) clone_transaction = clone_result.transaction self.assertEqual(Transaction.Type.Sale, clone_transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, clone_transaction.status) def test_clone_transaction_with_validations(self): result = Transaction.credit({ "amount": "100.00", "credit_card": { "number": "5105105105105100", "expiration_date": "05/2011", } }) self.assertTrue(result.is_success) transaction = result.transaction clone_result = Transaction.clone_transaction(transaction.id, {"amount": "123.45"}) self.assertFalse(clone_result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotCloneCredit, clone_result.errors.for_object("transaction").on("base")[0].code ) def test_find_exposes_disbursement_details(self): transaction = Transaction.find("deposittransaction") disbursement_details = transaction.disbursement_details self.assertEqual(date(2013, 4, 10), disbursement_details.disbursement_date) self.assertEqual("USD", disbursement_details.settlement_currency_iso_code) self.assertEqual(Decimal("1"), disbursement_details.settlement_currency_exchange_rate) self.assertEqual(False, disbursement_details.funds_held) self.assertEqual(True, disbursement_details.success) self.assertEqual(Decimal("100.00"), disbursement_details.settlement_amount) def test_sale_with_three_d_secure_option(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "three_d_secure": { "required": True } } }) self.assertFalse(result.is_success) self.assertEqual(Transaction.Status.GatewayRejected, result.transaction.status) self.assertEqual(Transaction.GatewayRejectionReason.ThreeDSecure, result.transaction.gateway_rejection_reason) # NEXT_MAJOR_VERSION Remove this test # three_d_secure_token is deprecated in favor of three_d_secure_authentication_id 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) # NEXT_MAJOR_VERSION Remove this test # three_d_secure_token is deprecated in favor of three_d_secure_authentication_id 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) # NEXT_MAJOR_VERSION Remove this test # three_d_secure_token is deprecated in favor of three_d_secure_authentication_id def test_sale_returns_error_with_none_three_d_secure_token(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_token": None }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureTokenIsInvalid, result.errors.for_object("transaction").on("three_d_secure_token")[0].code ) # NEXT_MAJOR_VERSION Remove this test # three_d_secure_token is deprecated in favor of three_d_secure_authentication_id def test_sale_returns_error_with_mismatched_3ds_verification_data(self): three_d_secure_token = TestHelper.create_3ds_verification(TestHelper.three_d_secure_merchant_account_id, { "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2009", }) result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "5105105105105100", "expiration_date": "05/2009" }, "three_d_secure_token": three_d_secure_token }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureTransactionDataDoesntMatchVerify, result.errors.for_object("transaction").on("three_d_secure_token")[0].code ) def test_sale_with_three_d_secure_authentication_id_with_vaulted_token(self): customer_id = Customer.create().customer.id credit_card_result = CreditCard.create({ "customer_id": customer_id, "number": "4111111111111111", "expiration_date": "12/2020", }) config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key" ) gateway = BraintreeGateway(config) payment_method_token = credit_card_result.credit_card.token three_d_secure_authentication_id = TestHelper.create_3ds_verification(TestHelper.three_d_secure_merchant_account_id, { "number": "4111111111111111", "expiration_month": "12", "expiration_year": "2020", }) result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "payment_method_token": payment_method_token, "three_d_secure_authentication_id": three_d_secure_authentication_id }) self.assertTrue(result.is_success) def test_sale_with_three_d_secure_authentication_id_with_nonce(self): config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key" ) gateway = BraintreeGateway(config) credit_card = { "credit_card": { "number": "4111111111111111", "expiration_month": "12", "expiration_year": "2020" } } nonce = TestHelper.generate_three_d_secure_nonce(gateway, credit_card) found_nonce = PaymentMethodNonce.find(nonce) three_d_secure_info = found_nonce.three_d_secure_info result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "payment_method_nonce": nonce, "three_d_secure_authentication_id": three_d_secure_info.three_d_secure_authentication_id }) self.assertTrue(result.is_success) def test_sale_returns_error_with_none_three_d_secure_authentication_id(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_authentication_id": None }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureAuthenticationIdIsInvalid, result.errors.for_object("transaction").on("three_d_secure_authentication_id")[0].code ) def test_sale_returns_error_with_mismatched_payment_data_with_three_d_secure_authentication_id(self): three_d_secure_authentication_id = 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_authentication_id": three_d_secure_authentication_id }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureTransactionPaymentMethodDoesntMatchThreeDSecureAuthenticationPaymentMethod, result.errors.for_object("transaction").on("three_d_secure_authentication_id")[0].code ) def test_sale_returns_error_with_mismatched_3ds_data_with_three_d_secure_authentication_id(self): three_d_secure_authentication_id = TestHelper.create_3ds_verification(TestHelper.three_d_secure_merchant_account_id, { "number": "4111111111111111", "expiration_month": "12", "expiration_year": "2020", }) config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key" ) gateway = BraintreeGateway(config) credit_card = { "credit_card": { "number": "4111111111111111", "expiration_month": "12", "expiration_year": "2020" } } nonce = TestHelper.generate_three_d_secure_nonce(gateway, credit_card) result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "5105105105105100", "expiration_date": "05/2009" }, "payment_method_nonce": nonce, "three_d_secure_authentication_id": three_d_secure_authentication_id }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureAuthenticationIdDoesntMatchNonceThreeDSecureAuthentication, result.errors.for_object("transaction").on("three_d_secure_authentication_id")[0].code ) def test_transaction_with_both_three_d_secure_authentication_id_and_three_d_secure_pass_thru(self): three_d_secure_authentication_id = 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_authentication_id": three_d_secure_authentication_id, "three_d_secure_pass_thru": { "eci_flag": "02", "cavv": "some-cavv", "xid": "some-xid" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureAuthenticationIdWithThreeDSecurePassThruIsInvalid, result.errors.for_object("transaction").on("three_d_secure_authentication_id")[0].code ) def test_transaction_with_three_d_secure_pass_thru(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_pass_thru": { "eci_flag": "02", "cavv": "some-cavv", "xid": "some-xid" } }) self.assertTrue(result.is_success) self.assertEqual(Transaction.Status.Authorized, result.transaction.status) def test_transaction_with_three_d_secure_pass_thru_with_invalid_processor_settings(self): result = Transaction.sale({ "merchant_account_id": "heartland_ma", "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_pass_thru": { "eci_flag": "02", "cavv": "some-cavv", "xid": "some-xid" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureMerchantAccountDoesNotSupportCardType, result.errors.for_object("transaction").on("merchant_account_id")[0].code ) def test_transaction_with_three_d_secure_pass_thru_error(self): result = Transaction.sale({ "merchant_account_id": TestHelper.three_d_secure_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "three_d_secure_pass_thru": { "eci_flag": "", "cavv": "some-cavv", "xid": "some-xid" } }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.ThreeDSecureEciFlagIsRequired, result.errors.for_object("transaction").for_object("three_d_secure_pass_thru").on("eci_flag")[0].code ) @unittest.skip("until we have a more stable ci env") def test_sale_with_amex_rewards_succeeds(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.Success, "expiration_date": "05/2020" }, "options" : { "submit_for_settlement" : True, "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) @unittest.skip("until we have a more stable ci env") def test_sale_with_amex_rewards_succeeds_even_if_card_is_ineligible(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.IneligibleCard, "expiration_date": "05/2009" }, "options" : { "submit_for_settlement" : True, "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) @unittest.skip("until we have a more stable ci env") def test_sale_with_amex_rewards_succeeds_even_if_card_balance_is_insufficient(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.InsufficientPoints, "expiration_date": "05/2009" }, "options" : { "submit_for_settlement" : True, "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, transaction.status) @unittest.skip("until we have a more stable ci env") def test_submit_for_settlement_with_amex_rewards_succeeds(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.Success, "expiration_date": "05/2009" }, "options" : { "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) @unittest.skip("until we have a more stable ci env") def test_submit_for_settlement_with_amex_rewards_succeeds_even_if_card_is_ineligible(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.IneligibleCard, "expiration_date": "05/2009" }, "options" : { "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) @unittest.skip("until we have a more stable ci env") def test_submit_for_settlement_with_amex_rewards_succeeds_even_if_card_balance_is_insufficient(self): result = Transaction.sale({ "merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.AmexPayWithPoints.InsufficientPoints, "expiration_date": "05/2009" }, "options" : { "amex_rewards" : { "request_id" : "ABC123", "points" : "100", "currency_amount" : "1.00", "currency_iso_code" : "USD" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(Transaction.Type.Sale, transaction.type) self.assertEqual(Transaction.Status.Authorized, transaction.status) submitted_transaction = Transaction.submit_for_settlement(transaction.id).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) def test_find_exposes_acquirer_reference_numbers(self): transaction = Transaction.find("transactionwithacquirerreferencenumber") self.assertEqual("123456789 091019", transaction.acquirer_reference_number) def test_find_exposes_authorization_adjustments(self): transaction = Transaction.find("authadjustmenttransaction") authorization_adjustment = transaction.authorization_adjustments[0] self.assertEqual(datetime, type(authorization_adjustment.timestamp)) self.assertEqual(Decimal("-20.00"), authorization_adjustment.amount) self.assertEqual(True, authorization_adjustment.success) self.assertEqual("1000", authorization_adjustment.processor_response_code) self.assertEqual("Approved", authorization_adjustment.processor_response_text) self.assertEqual(ProcessorResponseTypes.Approved, authorization_adjustment.processor_response_type) def test_find_exposes_authorization_adjustments_soft_declined(self): transaction = Transaction.find("authadjustmenttransactionsoftdeclined") authorization_adjustment = transaction.authorization_adjustments[0] self.assertEqual(datetime, type(authorization_adjustment.timestamp)) self.assertEqual(Decimal("-20.00"), authorization_adjustment.amount) self.assertEqual(False, authorization_adjustment.success) self.assertEqual("3000", authorization_adjustment.processor_response_code) self.assertEqual("Processor Network Unavailable - Try Again", authorization_adjustment.processor_response_text) self.assertEqual(ProcessorResponseTypes.SoftDeclined, authorization_adjustment.processor_response_type) def test_find_exposes_authorization_adjustments_hard_declined(self): transaction = Transaction.find("authadjustmenttransactionharddeclined") authorization_adjustment = transaction.authorization_adjustments[0] self.assertEqual(datetime, type(authorization_adjustment.timestamp)) self.assertEqual(Decimal("-20.00"), authorization_adjustment.amount) self.assertEqual(False, authorization_adjustment.success) self.assertEqual("2015", authorization_adjustment.processor_response_code) self.assertEqual("Transaction Not Allowed", authorization_adjustment.processor_response_text) self.assertEqual(ProcessorResponseTypes.HardDeclined, authorization_adjustment.processor_response_type) def test_find_exposes_disputes(self): transaction = Transaction.find("disputedtransaction") dispute = transaction.disputes[0] self.assertEqual(date(2014, 3, 1), dispute.received_date) self.assertEqual(date(2014, 3, 21), dispute.reply_by_date) self.assertEqual("USD", dispute.currency_iso_code) self.assertEqual(Decimal("250.00"), dispute.amount) self.assertEqual(Dispute.Status.Won, dispute.status) self.assertEqual(Dispute.Reason.Fraud, dispute.reason) self.assertEqual("disputedtransaction", dispute.transaction_details.id) self.assertEqual(Decimal("1000.00"), dispute.transaction_details.amount) self.assertEqual(Dispute.Kind.Chargeback, dispute.kind) self.assertEqual(date(2014, 3, 1), dispute.date_opened) self.assertEqual(date(2014, 3, 7), dispute.date_won) def test_find_exposes_three_d_secure_info(self): transaction = Transaction.find("threedsecuredtransaction") three_d_secure_info = transaction.three_d_secure_info self.assertEqual("Y", three_d_secure_info.enrolled) self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertEqual("somebase64value", three_d_secure_info.cavv) self.assertEqual("xidvalue", three_d_secure_info.xid) self.assertEqual("dstxnid", three_d_secure_info.ds_transaction_id) self.assertEqual("07", three_d_secure_info.eci_flag) self.assertIsNotNone(three_d_secure_info.three_d_secure_version) def test_find_exposes_none_for_null_three_d_secure_info(self): transaction = Transaction.find("settledtransaction") three_d_secure_info = transaction.three_d_secure_info self.assertEqual(None, three_d_secure_info) def test_find_exposes_refund_from_transaction_fee(self): transaction = Transaction.find("settledtransaction") paypal_details = transaction.paypal_details self.assertNotEqual(None, paypal_details.refund_from_transaction_fee_amount) self.assertNotEqual(None, paypal_details.refund_from_transaction_fee_currency_iso_code) def test_find_exposes_retrievals(self): transaction = Transaction.find("retrievaltransaction") dispute = transaction.disputes[0] self.assertEqual("USD", dispute.currency_iso_code) self.assertEqual(Decimal("1000.00"), dispute.amount) self.assertEqual(Dispute.Status.Open, dispute.status) self.assertEqual(Dispute.Reason.Retrieval, dispute.reason) self.assertEqual("retrievaltransaction", dispute.transaction_details.id) self.assertEqual(Decimal("1000.00"), dispute.transaction_details.amount) def test_creating_paypal_transaction_with_one_time_use_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) def test_creating_local_payment_transaction_with_local_payment_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "payment_method_nonce": Nonces.LocalPayment, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, transaction.local_payment_details.payment_id) self.assertNotEqual(None, transaction.local_payment_details.payer_id) self.assertNotEqual(None, transaction.local_payment_details.funding_source) self.assertNotEqual(None, transaction.local_payment_details.capture_id) self.assertNotEqual(None, transaction.local_payment_details.debug_id) self.assertNotEqual(None, transaction.local_payment_details.transaction_fee_amount) self.assertNotEqual(None, transaction.local_payment_details.transaction_fee_currency_iso_code) def test_refunding_local_payment_transaction(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "payment_method_nonce": Nonces.LocalPayment, }) self.assertTrue(result.is_success) result = Transaction.refund(result.transaction.id) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, transaction.local_payment_details.payment_id) self.assertNotEqual(None, transaction.local_payment_details.payer_id) self.assertNotEqual(None, transaction.local_payment_details.funding_source) self.assertNotEqual(None, transaction.local_payment_details.refund_id) self.assertNotEqual(None, transaction.local_payment_details.debug_id) self.assertNotEqual(None, transaction.local_payment_details.refund_from_transaction_fee_amount) self.assertNotEqual(None, transaction.local_payment_details.refund_from_transaction_fee_currency_iso_code) def test_creating_local_payment_transaction_with_local_payment_webhook_content(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "paypal_account": { "payment_id": "PAY-1234", "payer_id": "PAYER-1234", }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payment_id, "PAY-1234") self.assertEqual(transaction.paypal_details.payer_id, "PAYER-1234") def test_creating_paypal_transaction_with_payee_id(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": { "payee_id": "fake-payee-id" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.payee_id, "fake-payee-id") def test_creating_paypal_transaction_with_payee_email(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": { "payee_email": "payee@example.com" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.payee_email, "payee@example.com") def test_creating_paypal_transaction_with_payee_email_in_options_params(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": {}, "options": { "payee_email": "payee@example.com" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.payee_email, "payee@example.com") def test_creating_paypal_transaction_with_payee_email_in_options_paypal_params(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": {}, "options": { "paypal": { "payee_email": "foo@paypal.com" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.payee_email, "foo@paypal.com") def test_creating_paypal_transaction_with_custom_field_in_options_paypal_params(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": {}, "options": { "paypal": { "custom_field": "custom field stuff" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.custom_field, "custom field stuff") def test_creating_paypal_transaction_with_supplementary_data_in_options_paypal_params(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": {}, "options": { "paypal": { "supplementary_data": { "key1": "value1", "key2": "value2" } } } }) # note - supplementary data is not returned in response self.assertTrue(result.is_success) def test_creating_paypal_transaction_with_description_in_options_paypal_params(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "paypal_account": {}, "options": { "paypal": { "description": "Product description" } } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.image_url) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertEqual(transaction.paypal_details.description, "Product description") def test_paypal_transaction_payment_instrument_type(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(PaymentInstrumentType.PayPalAccount, transaction.payment_instrument_type) def test_creating_paypal_transaction_with_one_time_use_nonce_and_store_in_vault(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"store_in_vault": True} }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertEqual(transaction.paypal_details.token, None) self.assertNotEqual(None, transaction.paypal_details.debug_id) def test_creating_paypal_transaction_with_future_payment_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalBillingAgreement }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.debug_id) def test_creating_paypal_transaction_with_billing_agreement_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalBillingAgreement }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, re.search(r'PAY-\w+', transaction.paypal_details.payment_id)) self.assertNotEqual(None, re.search(r'AUTH-\w+', transaction.paypal_details.authorization_id)) self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertNotEqual(None, transaction.paypal_details.billing_agreement_id) def test_validation_failure_on_invalid_paypal_nonce(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "consent-code": "consent-code", "access-token": "access-token", "options": {"validate": False} }) self.assertEqual(202, status_code) result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": nonce }) self.assertFalse(result.is_success) error_code = result.errors.for_object("transaction").for_object("paypal_account").on("base")[0].code self.assertEqual(error_code, ErrorCodes.PayPalAccount.CannotHaveBothAccessTokenAndConsentCode) def test_validation_failure_on_non_existent_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": "doesnt-exist" }) self.assertFalse(result.is_success) error_code = result.errors.for_object("transaction").on("payment_method_nonce")[0].code self.assertEqual(error_code, ErrorCodes.Transaction.PaymentMethodNonceUnknown) def test_creating_sepa_direct_debit_transaction_with_vaulted_fake_nonce(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.SepaDirectDebit, }) self.assertTrue(result.is_success) transaction_result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_token": result.payment_method.token, "options": { "submit_for_settlement": True, } }) self.assertTrue(transaction_result.is_success) transaction = transaction_result.transaction sdd_details = transaction.sepa_direct_debit_account_details self.assertEqual(sdd_details.bank_reference_token, "a-fake-bank-reference-token") self.assertEqual(sdd_details.mandate_type, "RECURRENT") self.assertEqual(sdd_details.last_4, "1234") self.assertEqual(sdd_details.merchant_or_partner_customer_id, "a-fake-mp-customer-id") self.assertEqual(sdd_details.transaction_fee_amount, "0.01") self.assertEqual(sdd_details.transaction_fee_currency_iso_code, "USD") self.assertEqual(sdd_details.token, result.payment_method.token) self.assertTrue(sdd_details.capture_id) self.assertTrue(sdd_details.global_id) self.assertIsNone(sdd_details.refund_id) self.assertIsNone(sdd_details.debug_id) self.assertIsNone(sdd_details.paypal_v2_order_id) self.assertIsNone(sdd_details.refund_from_transaction_fee_amount) self.assertIsNone(sdd_details.refund_from_transaction_fee_currency_iso_code) self.assertIsNone(sdd_details.settlement_type) def test_creating_meta_checkout_card_transaction_with_fake_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.MetaCheckoutCard, }) self.assertTrue(result.is_success) transaction = result.transaction details = transaction.meta_checkout_card_details next_year = str(date.today().year + 1) self.assertEqual(details.bin, "401288") self.assertEqual(details.card_type, "Visa") self.assertEqual(details.cardholder_name, "Meta Checkout Card Cardholder") self.assertEqual(details.container_id, "container123") self.assertEqual(details.customer_location, "US") self.assertEqual(details.expiration_date, "12/" + next_year) self.assertEqual(details.expiration_month, "12") self.assertEqual(details.expiration_year, next_year) self.assertEqual(details.image_url, "https://assets.braintreegateway.com/payment_method_logo/visa.png?environment=development") self.assertEqual(details.is_network_tokenized, False) self.assertEqual(details.last_4, "1881") self.assertEqual(details.masked_number, "401288******1881") self.assertEqual(details.prepaid, "No") def test_creating_meta_checkout_token_transaction_with_fake_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.MetaCheckoutToken, }) self.assertTrue(result.is_success) transaction = result.transaction details = transaction.meta_checkout_token_details next_year = str(date.today().year + 1) self.assertEqual(details.bin, "401288") self.assertEqual(details.card_type, "Visa") self.assertEqual(details.cardholder_name, "Meta Checkout Token Cardholder") self.assertEqual(details.container_id, "container123") self.assertEqual(details.cryptogram, "AlhlvxmN2ZKuAAESNFZ4GoABFA==") self.assertEqual(details.customer_location, "US") self.assertEqual(details.ecommerce_indicator, "07") self.assertEqual(details.expiration_date, "12/" + next_year) self.assertEqual(details.expiration_month, "12") self.assertEqual(details.expiration_year, next_year) self.assertEqual(details.image_url, "https://assets.braintreegateway.com/payment_method_logo/visa.png?environment=development") self.assertEqual(details.is_network_tokenized, True) self.assertEqual(details.last_4, "1881") self.assertEqual(details.masked_number, "401288******1881") self.assertEqual(details.prepaid, "No") 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.PayPalBillingAgreement }) self.assertTrue(result.is_success) transaction_result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_token": result.payment_method.token }) self.assertTrue(transaction_result.is_success) transaction = transaction_result.transaction self.assertEqual(transaction.paypal_details.payer_email, "payer@example.com") self.assertNotEqual(None, transaction.paypal_details.debug_id) def test_creating_paypal_transaction_with_one_time_nonce_and_store_in_vault_fails_gracefully(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"store_in_vault": True} }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(None, transaction.paypal_details.token) def test_creating_paypal_transaction_with_future_payment_nonce_and_store_in_vault(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalFuturePayment, "options": {"store_in_vault": True} }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, transaction.paypal_details.token) paypal_account = PaymentMethod.find(transaction.paypal_details.token) self.assertEqual(paypal_account.email, transaction.paypal_details.payer_email) def test_creating_paypal_transaction_and_submitting_for_settlement(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"submit_for_settlement": True} }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.status, Transaction.Status.Settling) def test_voiding_a_paypal_transaction(self): sale_result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, }) self.assertTrue(sale_result.is_success) sale_transaction = sale_result.transaction void_result = Transaction.void(sale_transaction.id) self.assertTrue(void_result.is_success) void_transaction = void_result.transaction self.assertEqual(void_transaction.id, sale_transaction.id) self.assertEqual(void_transaction.status, Transaction.Status.Voided) def test_paypal_transaction_successful_refund(self): transaction = self.__create_paypal_transaction() result = Transaction.refund(transaction.id) self.assertTrue(result.is_success) refund = result.transaction self.assertEqual(Transaction.Type.Credit, refund.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), refund.amount) self.assertEqual(transaction.id, refund.refunded_transaction_id) self.assertEqual(refund.id, Transaction.find(transaction.id).refund_id) def test_paypal_transaction_successful_partial_refund(self): transaction = self.__create_paypal_transaction() result = Transaction.refund(transaction.id, Decimal("500.00")) self.assertTrue(result.is_success) self.assertEqual(Transaction.Type.Credit, result.transaction.type) self.assertEqual(Decimal("500.00"), result.transaction.amount) def test_paypal_transaction_multiple_successful_partial_refunds(self): transaction = self.__create_paypal_transaction() refund1 = Transaction.refund(transaction.id, Decimal("500.00")).transaction self.assertEqual(Transaction.Type.Credit, refund1.type) self.assertEqual(Decimal("500.00"), refund1.amount) refund2 = Transaction.refund(transaction.id, Decimal("500.00")).transaction self.assertEqual(Transaction.Type.Credit, refund2.type) self.assertEqual(Decimal("500.00"), refund2.amount) transaction = Transaction.find(transaction.id) self.assertEqual(2, len(transaction.refund_ids)) self.assertTrue(TestHelper.in_list(transaction.refund_ids, refund1.id)) self.assertTrue(TestHelper.in_list(transaction.refund_ids, refund2.id)) def test_paypal_transaction_returns_required_fields(self): transaction = self.__create_paypal_transaction() self.assertNotEqual(None, transaction.paypal_details.debug_id) self.assertNotEqual(None, transaction.paypal_details.payer_email) self.assertNotEqual(None, transaction.paypal_details.authorization_id) self.assertNotEqual(None, transaction.paypal_details.payer_id) self.assertNotEqual(None, transaction.paypal_details.payer_first_name) self.assertNotEqual(None, transaction.paypal_details.payer_last_name) self.assertNotEqual(None, transaction.paypal_details.payer_status) self.assertNotEqual(None, transaction.paypal_details.seller_protection_status) self.assertNotEqual(None, transaction.paypal_details.capture_id) #self.assertNotEqual(None, transaction.paypal_details.refund_id) self.assertNotEqual(None, transaction.paypal_details.transaction_fee_amount) self.assertNotEqual(None, transaction.paypal_details.transaction_fee_currency_iso_code) def test_paypal_transaction_refund_returns_an_error_if_unsettled(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } }).transaction result = Transaction.refund(transaction.id) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.CannotRefundUnlessSettled, result.errors.for_object("transaction").on("base")[0].code ) def test_transaction_settlement_errors(self): sale_result = Transaction.sale({ "credit_card": { "number": "4111111111111111", "expiration_date": "05/2010", "cvv": "100" }, "amount": "100.00", }) transaction = sale_result.transaction settle_result = TestHelper.settle_transaction(transaction.id) self.assertFalse(settle_result.is_success) error_codes = [ error.code for error in settle_result.errors.for_object("transaction").on("base") ] self.assertTrue(ErrorCodes.Transaction.CannotSimulateTransactionSettlement in error_codes) def test_transaction_returns_settlement_declined_response(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"submit_for_settlement": True} }) self.assertTrue(result.is_success) TestHelper.settlement_decline_transaction(result.transaction.id) transaction = Transaction.find(result.transaction.id) self.assertTrue("4001", transaction.processor_settlement_response_code) self.assertTrue("Settlement Declined", transaction.processor_settlement_response_text) self.assertTrue(Transaction.Status.SettlementDeclined, transaction.status) def test_transaction_returns_settlement_pending_response(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment, "options": {"submit_for_settlement": True} }) self.assertTrue(result.is_success) TestHelper.settlement_pending_transaction(result.transaction.id) transaction = Transaction.find(result.transaction.id) self.assertTrue("4002", transaction.processor_settlement_response_code) self.assertTrue("Settlement Pending", transaction.processor_settlement_response_text) self.assertTrue(Transaction.Status.SettlementPending, transaction.status) def test_transaction_submit_for_partial_settlement(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) authorized_transaction = result.transaction partial_settlement_result = Transaction.submit_for_partial_settlement(authorized_transaction.id, Decimal("500.00")) partial_settlement_transaction = partial_settlement_result.transaction self.assertTrue(partial_settlement_result.is_success) self.assertEqual(partial_settlement_transaction.amount, Decimal("500.00")) self.assertEqual(Transaction.Type.Sale, partial_settlement_transaction.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, partial_settlement_transaction.status) self.assertEqual(authorized_transaction.id, partial_settlement_transaction.authorized_transaction_id) partial_settlement_result_2 = Transaction.submit_for_partial_settlement(authorized_transaction.id, Decimal("500.00")) partial_settlement_transaction_2 = partial_settlement_result_2.transaction self.assertTrue(partial_settlement_result_2.is_success) self.assertEqual(partial_settlement_transaction_2.amount, Decimal("500.00")) self.assertEqual(Transaction.Type.Sale, partial_settlement_transaction_2.type) self.assertEqual(Transaction.Status.SubmittedForSettlement, partial_settlement_transaction_2.status) self.assertEqual(authorized_transaction.id, partial_settlement_transaction_2.authorized_transaction_id) refreshed_authorized_transaction = Transaction.find(authorized_transaction.id) self.assertEqual(2, len(refreshed_authorized_transaction.partial_settlement_transaction_ids)) def test_transaction_submit_for_partial_settlement_with_final_capture(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) authorized_transaction = result.transaction options = { "final_capture": "true" } partial_settlement_result1 = Transaction.submit_for_partial_settlement(authorized_transaction.id, Decimal("500.00")) partial_settlement_transaction1 = partial_settlement_result1.transaction self.assertTrue(partial_settlement_result1.is_success) self.assertEqual(partial_settlement_transaction1.amount, Decimal("500.00")) self.assertEqual(Transaction.Status.SubmittedForSettlement, partial_settlement_transaction1.status) refreshed_authorized_transaction1 = Transaction.find(authorized_transaction.id) self.assertEqual(Transaction.Status.SettlementPending, refreshed_authorized_transaction1.status) partial_settlement_result2 = Transaction.submit_for_partial_settlement(authorized_transaction.id, Decimal("100.00"), options) partial_settlement_transaction2 = partial_settlement_result2.transaction self.assertTrue(partial_settlement_result2.is_success) self.assertEqual(partial_settlement_transaction2.amount, Decimal("100.00")) refreshed_authorized_transaction2 = Transaction.find(authorized_transaction.id) self.assertEqual(2, len(refreshed_authorized_transaction2.partial_settlement_transaction_ids)) self.assertEqual(Transaction.Status.SettlementPending, refreshed_authorized_transaction2.status) def test_transaction_submit_for_partial_settlement_unsuccessful(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) authorized_transaction = result.transaction partial_settlement_result = Transaction.submit_for_partial_settlement(authorized_transaction.id, Decimal("500.00")) partial_settlement_transaction = partial_settlement_result.transaction partial_settlement_result_2 = Transaction.submit_for_partial_settlement(partial_settlement_transaction.id, Decimal("250.00")) self.assertFalse(partial_settlement_result_2.is_success) error_code = partial_settlement_result_2.errors.for_object("transaction").on("base")[0].code self.assertEqual(ErrorCodes.Transaction.CannotSubmitForPartialSettlement, error_code) def test_submit_for_partial_settlement_with_order_id(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = {"order_id": "ABC123"} submitted_transaction = Transaction.submit_for_partial_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual("ABC123", submitted_transaction.order_id) def test_submit_for_partial_settlement_with_descriptor(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = { "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" } } submitted_transaction = Transaction.submit_for_partial_settlement(transaction.id, Decimal("900"), params).transaction self.assertEqual(Transaction.Status.SubmittedForSettlement, submitted_transaction.status) self.assertEqual("123*123456789012345678", submitted_transaction.descriptor.name) self.assertEqual("3334445555", submitted_transaction.descriptor.phone) self.assertEqual("ebay.com", submitted_transaction.descriptor.url) def test_submit_for_partial_settlement_with_invalid_params(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }).transaction params = { "descriptor": { "name": "123*123456789012345678", "phone": "3334445555", "url": "ebay.com" }, "invalid_param": "foo", } with self.assertRaisesRegex(KeyError, "'Invalid keys: invalid_param'"): Transaction.submit_for_partial_settlement(transaction.id, Decimal("900"), params) def test_facilitated_transaction(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, False) nonce = grant_result.payment_method_nonce.nonce result = Transaction.sale({ "payment_method_nonce": nonce, "amount": TransactionAmounts.Authorize, }) self.assertNotEqual(result.transaction.facilitated_details, None) self.assertEqual(result.transaction.facilitated_details.merchant_id, "integration_merchant_id") self.assertEqual(result.transaction.facilitated_details.merchant_name, "14ladders") self.assertEqual(result.transaction.facilitated_details.payment_method_nonce, nonce) self.assertTrue(result.transaction.facilitator_details is not None) self.assertEqual(result.transaction.facilitator_details.oauth_application_client_id, "client_id$development$integration_client_id") self.assertEqual(result.transaction.facilitator_details.oauth_application_name, "PseudoShop") self.assertTrue(result.transaction.billing["postal_code"] is None) def test_include_billing_postal_code(self): granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures() grant_result = granting_gateway.payment_method.grant(credit_card.token, { "allow_vaulting": False, "include_billing_postal_code": True }) result = Transaction.sale({ "payment_method_nonce": grant_result.payment_method_nonce.nonce, "amount": TransactionAmounts.Authorize, }) self.assertTrue(result.transaction.billing["postal_code"], "95131") def test_sale_elo_card(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.adyen_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Elo, "expiration_date": ExpirationHelper.ADYEN.value, "cvv": "737", } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(TestHelper.adyen_merchant_account_id, transaction.merchant_account_id) def test_sale_hiper_card(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(CreditCard.CardType.Hiper, transaction.credit_card_details.card_type) def test_sale_hipercard_card(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hipercard, "expiration_date": "10/2020", "cvv": "737", } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(CreditCard.CardType.Hipercard, transaction.credit_card_details.card_type) def test_account_type_credit(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hipercard, "expiration_date": "10/2020", "cvv": "737", }, "options": { "credit_card": { "account_type": "credit", }, }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("credit", transaction.credit_card_details.account_type) def test_account_type_debit(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "submit_for_settlement": True, "credit_card": { "account_type": "debit", }, }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("debit", transaction.credit_card_details.account_type) def test_account_type_debit_error_does_not_support_auths(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "credit_card": { "account_type": "debit", }, }, }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Options.CreditCard.AccountTypeDebitDoesNotSupportAuths, result.errors.for_object("transaction").for_object("options").for_object("credit_card").on("account_type")[0].code ) def test_account_type_debit_error_account_type_is_invalid(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", }, "options": { "credit_card": { "account_type": "invalid", }, }, }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Options.CreditCard.AccountTypeIsInvalid, result.errors.for_object("transaction").for_object("options").for_object("credit_card").on("account_type")[0].code ) def test_account_type_debit_error_account_type_not_supported(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.MasterCard, "expiration_date": "05/2009" }, "options": { "credit_card": { "account_type": "debit", }, }, }) self.assertFalse(result.is_success) self.assertEqual( ErrorCodes.Transaction.Options.CreditCard.AccountTypeNotSupported, result.errors.for_object("transaction").for_object("options").for_object("credit_card").on("account_type")[0].code ) def test_paypal_here_details_auth_capture(self): result = Transaction.find('paypal_here_auth_capture_id') self.assertIsNotNone(result.paypal_here_details) self.assertEqual(PaymentInstrumentType.PayPalHere, result.payment_instrument_type) details = result.paypal_here_details self.assertIsNotNone(details.authorization_id) self.assertIsNotNone(details.capture_id) self.assertIsNotNone(details.invoice_id) self.assertIsNotNone(details.last_4) self.assertIsNotNone(details.payment_type) self.assertIsNotNone(details.transaction_fee_amount) self.assertIsNotNone(details.transaction_fee_currency_iso_code) self.assertIsNotNone(details.transaction_initiation_date) self.assertIsNotNone(details.transaction_updated_date) def test_paypal_here_details_sale(self): result = Transaction.find('paypal_here_sale_id') self.assertIsNotNone(result.paypal_here_details) details = result.paypal_here_details self.assertIsNotNone(details.payment_id) def test_paypal_here_details_refund(self): result = Transaction.find('paypal_here_refund_id') self.assertIsNotNone(result.paypal_here_details) details = result.paypal_here_details self.assertIsNotNone(details.refund_id) def test_sale_network_response_code_text(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, transaction.processor_response_type) self.assertEqual("XX", transaction.network_response_code) self.assertEqual("sample network response text", transaction.network_response_text) def test_retrieval_reference_number(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, }) transaction = result.transaction self.assertIsNotNone(transaction.retrieval_reference_number) def test_network_tokenized_credit_card_transaction(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_token": "network_tokenized_credit_card", }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, transaction.processor_response_type) self.assertEqual(True, transaction.processed_with_network_token) def test_non_network_tokenized_credit_card_transaction(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, transaction.processor_response_type) self.assertEqual(False, transaction.processed_with_network_token) def test_installment_count_transaction(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "installments": { "count": 4, }, }) transaction = result.transaction self.assertTrue(result.is_success) self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, transaction.processor_response_type) self.assertEqual(4, transaction.installment_count) def test_installment_transaction(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.card_processor_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "installments": { "count": 4, }, "options": { "submit_for_settlement": True }, }) transaction = result.transaction self.assertTrue(result.is_success) self.assertEqual("1000", transaction.processor_response_code) self.assertEqual(ProcessorResponseTypes.Approved, transaction.processor_response_type) self.assertEqual(4, transaction.installment_count) self.assertEqual(4, len(transaction.installments)) for i, t in enumerate(transaction.installments) : self.assertEqual('250.00', t['amount']) self.assertEqual('% s_INST_% s'%(transaction.id,i+1), t['id']) result = Transaction.refund(transaction.id,"20.00") self.assertTrue(result.is_success) refund = result.transaction for t in refund.refunded_installments : self.assertEqual('-5.00', t['adjustments'][0]['amount']) self.assertEqual("REFUND",t['adjustments'][0]['kind']) def test_manual_key_entry_transactions_with_valid_card_details(self): result = Transaction.sale({ "amount": "10.00", "credit_card": { "payment_reader_card_details": { "encrypted_card_data": "8F34DFB312DC79C24FD5320622F3E11682D79E6B0C0FD881", "key_serial_number": "FFFFFF02000572A00005", } }, }) self.assertTrue(result.is_success) def test_manual_key_entry_transactions_with_invalid_card_details(self): result = Transaction.sale({ "amount": "10.00", "credit_card": { "payment_reader_card_details": { "encrypted_card_data": "invalid", "key_serial_number": "invalid", } }, }) self.assertFalse(result.is_success) error_code = result.errors.for_object("transaction")[0].code self.assertEqual(ErrorCodes.Transaction.PaymentInstrumentNotSupportedByMerchantAccount, error_code) def test_external_network_token_transaction_with_token_details(self): result = Transaction.sale({ "amount": "10.00", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "06/2009", "network_tokenization_attributes": { "cryptogram": "/wAAAAAAAcb8AlGUF/1JQEkAAAA=", "ecommerce_indicator": "45310020105", "token_requestor_id" : "05" } }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertTrue(transaction.processed_with_network_token) self.assertTrue(transaction.network_token['is_network_tokenized']) def test_external_network_token_transaction_with_invalid_token_details(self): result = Transaction.sale({ "amount": "10.00", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "06/2009", "network_tokenization_attributes": { "ecommerce_indicator": "45310020105", "token_requestor_id" : "05" } }, }) self.assertFalse(result.is_success) error_code = result.errors.for_object("transaction").for_object("credit_card").on("network_tokenization_attributes")[0].code self.assertEqual(ErrorCodes.CreditCard.NetworkTokenizationAttributeCryptogramIsRequired, error_code) def test_adjust_authorization_for_successful_adjustment(self): initial_transaction_sale = Transaction.sale(self.__first_data_transaction_params()) self.assertTrue(initial_transaction_sale.is_success) adjusted_authorization_result = Transaction.adjust_authorization(initial_transaction_sale.transaction.id, Decimal("85.50")) self.assertTrue(adjusted_authorization_result.is_success) self.assertEqual(adjusted_authorization_result.transaction.amount, Decimal("85.50")) def test_adjust_authorization_processor_not_supports_multi_auth_adjustment(self): initial_transaction_sale = Transaction.sale({ "merchant_account_id": TestHelper.default_merchant_account_id, "amount": "75.50", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "06/2009" }, }) self.assertTrue(initial_transaction_sale.is_success) adjusted_authorization_result= Transaction.adjust_authorization(initial_transaction_sale.transaction.id, "85.50") self.assertFalse(adjusted_authorization_result.is_success) self.assertEqual(adjusted_authorization_result.transaction.amount, Decimal("75.50")) error_code = adjusted_authorization_result.errors.for_object("transaction").on("base")[0].code self.assertEqual(ErrorCodes.Transaction.ProcessorDoesNotSupportAuthAdjustment, error_code) def test_adjust_authorization_amount_submitted_is_zero(self): initial_transaction_sale = Transaction.sale(self.__first_data_transaction_params()) self.assertTrue(initial_transaction_sale.is_success) adjusted_authorization_result = Transaction.adjust_authorization(initial_transaction_sale.transaction.id, "0.0") self.assertFalse(adjusted_authorization_result.is_success) self.assertEqual(adjusted_authorization_result.transaction.amount, Decimal("75.50")) error_code = adjusted_authorization_result.errors.for_object("authorization_adjustment").on("amount")[0].code self.assertEqual(ErrorCodes.Transaction.AdjustmentAmountMustBeGreaterThanZero, error_code) def test_adjust_authorization_when_amount_submitted_same_as_authorized(self): initial_transaction_sale = Transaction.sale(self.__first_data_transaction_params()) self.assertTrue(initial_transaction_sale.is_success) adjusted_authorization_result = Transaction.adjust_authorization(initial_transaction_sale.transaction.id, "75.50") self.assertFalse(adjusted_authorization_result.is_success) self.assertEqual(adjusted_authorization_result.transaction.amount, Decimal("75.50")) error_code = adjusted_authorization_result.errors.for_object("authorization_adjustment").on("base")[0].code self.assertEqual(ErrorCodes.Transaction.NoNetAmountToPerformAuthAdjustment, error_code) def test_adjust_authorization_when_transaction_authorization_type_is_undfined_or_final(self): additional_params = { "transaction_source": "recurring" } merchant_params = { **self.__first_data_transaction_params(), **additional_params } initial_transaction_sale = Transaction.sale(merchant_params) self.assertTrue(initial_transaction_sale.is_success) adjusted_authorization_result = Transaction.adjust_authorization(initial_transaction_sale.transaction.id, "85.50") self.assertFalse(adjusted_authorization_result.is_success) self.assertEqual(adjusted_authorization_result.transaction.amount, Decimal("75.50")) error_code = adjusted_authorization_result.errors.for_object("transaction").on("base")[0].code self.assertEqual(ErrorCodes.Transaction.TransactionIsNotEligibleForAdjustment, error_code) def test_retried_transaction(self): result = Transaction.sale({ "merchant_account_id": TestHelper.default_merchant_account_id, "amount": TransactionAmounts.Decline, "payment_method_token": "network_tokenized_credit_card", }) self.assertFalse(result.is_success) transaction = result.transaction self.assertTrue(transaction.retried) self.assertTrue(len(transaction.retry_ids) > 0) self.assertEqual(transaction.retried_transaction_id, None) def test_non_retried_transaction(self): result = Transaction.sale({ "merchant_account_id": TestHelper.default_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "06/2009" }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertFalse(transaction.retried) def test_ineligible_retry_transaction(self): result = Transaction.sale({ "merchant_account_id": TestHelper.non_default_merchant_account_id, "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "06/2009" }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertFalse(transaction.retried) def test_merchant_advice_code(self): result = Transaction.sale({ "amount": TransactionAmounts.Decline, "credit_card": { "number": CreditCardNumbers.MasterCard, "expiration_date": "05/2025" }, }) transaction = result.transaction self.assertEqual(Transaction.Status.ProcessorDeclined, transaction.status) self.assertEqual("01", transaction.merchant_advice_code) self.assertEqual("New account information available", transaction.merchant_advice_code_text) def test_foreign_retailer_to_be_true_when_set_to_true_in_the_request(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2025" }, "foreign_retailer": "true", }) self.assertTrue(result.is_success) transaction = result.transaction self.assertTrue(transaction.foreign_retailer) def test_foreign_retailer_to_be_skipped_when_set_to_false_in_the_request(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2025" }, "foreign_retailer": "false", }) self.assertTrue(result.is_success) transaction = result.transaction self.assertFalse(hasattr(transaction, 'foreign_retailer')) def test_foreign_retailer_to_be_skipped_when_not_set_in_the_request(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2025" }, }) self.assertTrue(result.is_success) transaction = result.transaction self.assertFalse(hasattr(transaction, 'foreign_retailer')) braintree_python-4.31.0/tests/integration/test_transaction_gateway.py000066400000000000000000000235261471021343500263270ustar00rootroot00000000000000from tests.test_helper import * from braintree.configuration import Configuration class TestTransactionGateway(unittest.TestCase): def setUp(self): config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key" ) self.gateway = BraintreeGateway(config) def test_credit_with_a_successful_result(self): result = self.gateway.transaction.credit({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertTrue(result.is_success) transaction = result.transaction self.assertNotEqual(None, re.search(r"\A\w{6,}\Z", transaction.id)) self.assertEqual(Transaction.Type.Credit, transaction.type) self.assertEqual(Decimal(TransactionAmounts.Authorize), transaction.amount) cc_details = transaction.credit_card_details self.assertEqual("411111", cc_details.bin) self.assertEqual("1111", cc_details.last_4) self.assertEqual("05/2009", cc_details.expiration_date) def test_shared_vault_transaction_with_nonce(self): config = Configuration( merchant_id="integration_merchant_public_id", public_key="oauth_app_partner_user_public_key", private_key="oauth_app_partner_user_private_key", environment=Environment.Development ) gateway = BraintreeGateway(config) customer = gateway.customer.create({"first_name": "Bob"}).customer address = gateway.address.create({ "customer_id": customer.id, "first_name": "Joe", }).address credit_card = gateway.credit_card.create( params={ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", } ).credit_card shared_nonce = gateway.payment_method_nonce.create( credit_card.token ).payment_method_nonce.nonce oauth_app_gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret", environment=Environment.Development ) code = TestHelper.create_grant(oauth_app_gateway, { "merchant_public_id": "integration_merchant_id", "scope": "grant_payment_method,shared_vault_transactions" }) access_token = oauth_app_gateway.oauth.create_token_from_code({ "code": code }).credentials.access_token recipient_gateway = BraintreeGateway(access_token=access_token) result = recipient_gateway.transaction.sale({ "shared_payment_method_nonce": shared_nonce, "shared_customer_id": customer.id, "shared_shipping_address_id": address.id, "shared_billing_address_id": address.id, "amount": "100" }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.shipping_details.first_name, address.first_name) self.assertEqual(result.transaction.billing_details.first_name, address.first_name) self.assertEqual(result.transaction.customer_details.first_name, customer.first_name) def test_shared_vault_transaction_with_token(self): config = Configuration( merchant_id="integration_merchant_public_id", public_key="oauth_app_partner_user_public_key", private_key="oauth_app_partner_user_private_key", environment=Environment.Development ) gateway = BraintreeGateway(config) customer = gateway.customer.create({"first_name": "Bob"}).customer address = gateway.address.create({ "customer_id": customer.id, "first_name": "Joe", }).address credit_card = gateway.credit_card.create( params={ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", } ).credit_card oauth_app_gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret", environment=Environment.Development ) code = TestHelper.create_grant(oauth_app_gateway, { "merchant_public_id": "integration_merchant_id", "scope": "grant_payment_method,shared_vault_transactions" }) access_token = oauth_app_gateway.oauth.create_token_from_code({ "code": code }).credentials.access_token recipient_gateway = BraintreeGateway( access_token=access_token, ) result = recipient_gateway.transaction.sale({ "shared_payment_method_token": credit_card.token, "shared_customer_id": customer.id, "shared_shipping_address_id": address.id, "shared_billing_address_id": address.id, "amount": "100" }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.shipping_details.first_name, address.first_name) self.assertEqual(result.transaction.billing_details.first_name, address.first_name) self.assertEqual(result.transaction.customer_details.first_name, customer.first_name) def test_sale_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": "GBR", "payment_methods": ["credit_card", "paypal"] }) gateway = BraintreeGateway( access_token=result.credentials.access_token, environment=Environment.Development ) result = gateway.transaction.sale({ "amount": "4000.00", "billing": { "street_address": "200 Fake Street" }, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" } }) self.assertFalse(result.is_success) transaction = result.transaction self.assertEqual(Transaction.GatewayRejectionReason.ApplicationIncomplete, transaction.gateway_rejection_reason) def test_sale_with_apple_pay_params(self): result = self.gateway.transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "apple_pay_card": { "cardholder_name": "Evelyn Boyd Granville", "cryptogram": "AAAAAAAA/COBt84dnIEcwAA3gAAGhgEDoLABAAhAgAABAAAALnNCLw==", "eci_indicator": "07", "expiration_month": "10", "expiration_year": "14", "number": "370295001292109" } }) self.assertTrue(result.is_success) self.assertEqual(Transaction.Status.Authorized, result.transaction.status) def test_sale_with_google_pay_params(self): result = self.gateway.transaction.sale({ "amount": Decimal(TransactionAmounts.Authorize), "android_pay_card": { "cryptogram": "AAAAAAAA/COBt84dnIEcwAA3gAAGhgEDoLABAAhAgAABAAAALnNCLw==", "eci_indicator": "07", "expiration_month": "10", "expiration_year": "14", "google_transaction_id": "12345", "number": "4012888888881881", "source_card_last_four": "1881", "source_card_type": "Visa" } }) self.assertTrue(result.is_success) self.assertEqual(Transaction.Status.Authorized, result.transaction.status) self.assertEqual("android_pay_card", result.transaction.payment_instrument_type) self.assertEqual("10", result.transaction.android_pay_card_details.expiration_month) self.assertEqual("14", result.transaction.android_pay_card_details.expiration_year) self.assertEqual("12345", result.transaction.android_pay_card_details.google_transaction_id) self.assertEqual("1881", result.transaction.android_pay_card_details.source_card_last_4) self.assertEqual("Visa", result.transaction.android_pay_card_details.source_card_type) def test_create_can_set_recurring_flag(self): result = self.gateway.transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "recurring": True }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(True, transaction.recurring) def test_create_recurring_flag_sends_deprecation_warning(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") result = self.gateway.transaction.sale({ "amount": "100", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009" }, "recurring": True }) self.assertTrue(result.is_success) transaction = result.transaction self.assertEqual(True, transaction.recurring) assert len(w) > 0 assert issubclass(w[-1].category, DeprecationWarning) assert "Use transaction_source parameter instead" in str(w[-1].message) braintree_python-4.31.0/tests/integration/test_transaction_line_item.py000066400000000000000000000027011471021343500266230ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers class TestTransactionLineItem(unittest.TestCase): def test_transaction_line_item_find_all_returns_line_items(self): transaction = Transaction.sale({ "amount": "35.05", "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", }, "line_items": [{ "quantity": "1.0232", "name": "Name #1", "kind": TransactionLineItem.Kind.Debit, "unit_amount": "45.1232", "total_amount": "45.15", "upc_code": "123456789", "upc_type": "UPC-A", "image_url": "https://google.com/image.png", }] }).transaction line_items = TransactionLineItem.find_all(transaction.id) self.assertEqual(1, len(line_items)) lineItem = line_items[0] self.assertEqual("1.0232", lineItem.quantity) self.assertEqual("Name #1", lineItem.name) self.assertEqual(TransactionLineItem.Kind.Debit, lineItem.kind) self.assertEqual("45.1232", lineItem.unit_amount) self.assertEqual("45.15", lineItem.total_amount) self.assertEqual("123456789", lineItem.upc_code) self.assertEqual("UPC-A", lineItem.upc_type) self.assertEqual("https://google.com/image.png",lineItem.image_url) braintree_python-4.31.0/tests/integration/test_transaction_line_item_gateway.py000066400000000000000000000005161471021343500303460ustar00rootroot00000000000000from tests.test_helper import * class TestTransactionLineItemGateway(unittest.TestCase): def test_transaction_line_item_gateway_find_all_raises_when_transaction_not_found(self): with self.assertRaises(NotFoundError): transaction_id = "willnotbefound" TransactionLineItem.find_all(transaction_id) braintree_python-4.31.0/tests/integration/test_transaction_search.py000066400000000000000000002053621471021343500261330ustar00rootroot00000000000000from unittest.mock import patch from tests.test_helper import * class TestTransactionSearch(unittest.TestCase): def test_advanced_search_no_results(self): collection = Transaction.search([ TransactionSearch.billing_first_name == "no_such_person" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_searches_all_text_fields_at_once(self): first_name = "Tim%s" % random.randint(1, 100000) token = "creditcard%s" % random.randint(1, 100000) customer_id = "customer%s" % random.randint(1, 100000) transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Tom Smith", "token": token, }, "billing": { "company": "Braintree", "country_name": "United States of America", "extended_address": "Suite 123", "first_name": first_name, "last_name": "Smith", "locality": "Chicago", "postal_code": "12345", "region": "IL", "street_address": "123 Main St" }, "customer": { "company": "Braintree", "email": "smith@example.com", "fax": "5551231234", "first_name": "Tom", "id": customer_id, "last_name": "Smith", "phone": "5551231234", "website": "http://example.com", }, "options": { "store_in_vault": True, "submit_for_settlement": True }, "order_id": "myorder", "shipping": { "company": "Braintree P.S.", "country_name": "Mexico", "extended_address": "Apt 456", "first_name": "Thomas", "last_name": "Smithy", "locality": "Braintree", "postal_code": "54321", "region": "MA", "street_address": "456 Road" } }).transaction TestHelper.settle_transaction(transaction.id) transaction = Transaction.find(transaction.id) collection = Transaction.search([ TransactionSearch.billing_company == "Braintree", TransactionSearch.billing_country_name == "United States of America", TransactionSearch.billing_extended_address == "Suite 123", TransactionSearch.billing_first_name == first_name, TransactionSearch.billing_last_name == "Smith", TransactionSearch.billing_locality == "Chicago", TransactionSearch.billing_postal_code == "12345", TransactionSearch.billing_region == "IL", TransactionSearch.billing_street_address == "123 Main St", TransactionSearch.credit_card_cardholder_name == "Tom Smith", TransactionSearch.credit_card_expiration_date == "05/2012", TransactionSearch.credit_card_number == "4111111111111111", TransactionSearch.customer_company == "Braintree", TransactionSearch.customer_email == "smith@example.com", TransactionSearch.customer_fax == "5551231234", TransactionSearch.customer_first_name == "Tom", TransactionSearch.customer_id == customer_id, TransactionSearch.customer_last_name == "Smith", TransactionSearch.customer_phone == "5551231234", TransactionSearch.customer_website == "http://example.com", TransactionSearch.order_id == "myorder", TransactionSearch.payment_method_token == token, TransactionSearch.processor_authorization_code == transaction.processor_authorization_code, TransactionSearch.settlement_batch_id == transaction.settlement_batch_id, TransactionSearch.shipping_company == "Braintree P.S.", TransactionSearch.shipping_country_name == "Mexico", TransactionSearch.shipping_extended_address == "Apt 456", TransactionSearch.shipping_first_name == "Thomas", TransactionSearch.shipping_last_name == "Smithy", TransactionSearch.shipping_locality == "Braintree", TransactionSearch.shipping_postal_code == "54321", TransactionSearch.shipping_region == "MA", TransactionSearch.shipping_street_address == "456 Road", TransactionSearch.id == transaction.id ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_search_each_text_field(self): first_name = "Tim%s" % random.randint(1, 100000) token = "creditcard%s" % random.randint(1, 100000) customer_id = "customer%s" % random.randint(1, 100000) transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Tom Smith", "token": token, }, "billing": { "company": "Braintree", "country_name": "United States of America", "extended_address": "Suite 123", "first_name": first_name, "last_name": "Smith", "locality": "Chicago", "postal_code": "12345", "region": "IL", "street_address": "123 Main St" }, "customer": { "company": "Braintree", "email": "smith@example.com", "fax": "5551231234", "first_name": "Tom", "id": customer_id, "last_name": "Smith", "phone": "5551231234", "website": "http://example.com", }, "options": { "store_in_vault": True }, "order_id": "myorder", "shipping": { "company": "Braintree P.S.", "country_name": "Mexico", "extended_address": "Apt 456", "first_name": "Thomas", "last_name": "Smithy", "locality": "Braintree", "postal_code": "54321", "region": "MA", "street_address": "456 Road" } }).transaction search_criteria = { "billing_company": "Braintree", "billing_country_name": "United States of America", "billing_extended_address": "Suite 123", "billing_first_name": first_name, "billing_last_name": "Smith", "billing_locality": "Chicago", "billing_postal_code": "12345", "billing_region": "IL", "billing_street_address": "123 Main St", "credit_card_cardholder_name": "Tom Smith", "credit_card_expiration_date": "05/2012", "credit_card_number": "4111111111111111", "customer_company": "Braintree", "customer_email": "smith@example.com", "customer_fax": "5551231234", "customer_first_name": "Tom", "customer_id": customer_id, "customer_last_name": "Smith", "customer_phone": "5551231234", "customer_website": "http://example.com", "order_id": "myorder", "payment_method_token": token, "processor_authorization_code": transaction.processor_authorization_code, "shipping_company": "Braintree P.S.", "shipping_country_name": "Mexico", "shipping_extended_address": "Apt 456", "shipping_first_name": "Thomas", "shipping_last_name": "Smithy", "shipping_locality": "Braintree", "shipping_postal_code": "54321", "shipping_region": "MA", "shipping_street_address": "456 Road", "user": "integration_user_public_id", "credit_card_unique_identifier": transaction.credit_card["unique_number_identifier"] } for criterion, value in search_criteria.items(): text_node = getattr(TransactionSearch, criterion) collection = Transaction.search([ TransactionSearch.id == transaction.id, text_node == value ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, text_node == "invalid" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_with_argument_list_rather_than_literal_list(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Tom Smith", }, }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name == "Tom Smith" ) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_payment_instrument_type_is_credit_card(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Tom Smith", }, }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == "CreditCardDetail" ) self.assertEqual(transaction.payment_instrument_type, PaymentInstrumentType.CreditCard) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_payment_instrument_type_is_paypal(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.PayPalOneTimePayment }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == "PayPalDetail" ) self.assertEqual(transaction.payment_instrument_type, PaymentInstrumentType.PayPalAccount) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_payment_instrument_type_is_local_payment(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "payment_method_nonce": Nonces.LocalPayment }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == "LocalPaymentDetail" ) self.assertEqual(transaction.payment_instrument_type, PaymentInstrumentType.LocalPayment) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_payment_instrument_type_is_sepa_debit_account(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "payment_method_nonce": Nonces.SepaDirectDebit }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == "SEPADebitAccount" ) self.assertEqual(transaction.payment_instrument_type, PaymentInstrumentType.SepaDirectDebitAccount) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_sepa_debit_paypal_v2_order_id(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "payment_method_nonce": Nonces.SepaDirectDebit }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.sepa_debit_paypal_v2_order_id == transaction.sepa_direct_debit_account_details.paypal_v2_order_id ) self.assertEqual(transaction.payment_instrument_type, PaymentInstrumentType.SepaDirectDebitAccount) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_payment_instrument_type_is_meta_checkout(self): card_tx = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "payment_method_nonce": Nonces.MetaCheckoutCard }).transaction token_tx = Transaction.sale({ "amount": TransactionAmounts.Authorize, "options": { "submit_for_settlement": True, }, "payment_method_nonce": Nonces.MetaCheckoutToken }).transaction collection = Transaction.search( TransactionSearch.payment_instrument_type == "MetaCheckout" ) self.assertTrue(collection.maximum_size >= 2) tx_id_map = list(map(lambda x: x.id, collection)) self.assertTrue(card_tx.id in tx_id_map) self.assertTrue(token_tx.id in tx_id_map) def test_advanced_search_with_payment_instrument_type_is_apple_pay(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": Nonces.ApplePayVisa }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == "ApplePayDetail" ) self.assertEqual(transaction.payment_instrument_type, PaymentInstrumentType.ApplePayCard) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_with_debit_network(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.pinless_debit_merchant_account_id, #"currency_iso_code": "USD", "payment_method_nonce": Nonces.TransactablePinlessDebitVisa, "options": { "submit_for_settlement": True } }).transaction collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == transaction.credit_card_details.card_type ) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search( TransactionSearch.id == transaction.id, TransactionSearch.debit_network.in_list(Constants.get_all_enum_values(CreditCard.DebitNetwork)) ) self.assertEqual(1, collection.maximum_size) def test_advanced_search_multiple_value_node_allowed_values_debit_network(self): with self.assertRaisesRegex(AttributeError, "Invalid argument\(s\) for debit_network: noSuchDebitNetwork"): Transaction.search([ TransactionSearch.debit_network == "noSuchDebitNetwork" ]) def test_advanced_search_text_node_contains(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Jane Shea" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.contains("ane She") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.contains("invalid") ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_text_node_starts_with(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Jane Shea" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.starts_with("Jane S") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.starts_with("invalid") ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_text_node_ends_with(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Jane Shea" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.ends_with("e Shea") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name.ends_with("invalid") ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_text_node_is_not(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": "Jane Shea" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name != "invalid" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_cardholder_name != "Jane Shea" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_multiple_value_node_created_using(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_using == Transaction.CreatedUsing.FullInformation ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_using.in_list([Transaction.CreatedUsing.FullInformation, Transaction.CreatedUsing.Token]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_using == Transaction.CreatedUsing.Token ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_multiple_value_node_allowed_values_created_using(self): with self.assertRaisesRegex(AttributeError, "Invalid argument\(s\) for created_using: noSuchCreatedUsing"): Transaction.search([TransactionSearch.created_using == "noSuchCreatedUsing"]) def test_advanced_search_multiple_value_node_credit_card_customer_location(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_customer_location == CreditCard.CustomerLocation.US ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_customer_location.in_list([CreditCard.CustomerLocation.US, CreditCard.CustomerLocation.International]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_customer_location == CreditCard.CustomerLocation.International ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_multiple_value_node_allowed_values_credit_card_customer_location(self): with self.assertRaisesRegex(AttributeError, "Invalid argument\(s\) for credit_card_customer_location: noSuchCreditCardCustomerLocation"): Transaction.search([ TransactionSearch.credit_card_customer_location == "noSuchCreditCardCustomerLocation" ]) def test_advanced_search_multiple_value_node_merchant_account_id(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.merchant_account_id == transaction.merchant_account_id ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.merchant_account_id.in_list([transaction.merchant_account_id, "bogus_merchant_account_id"]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.merchant_account_id == "bogus_merchant_account_id" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_multiple_value_node_credit_card_card_type(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == transaction.credit_card_details.card_type ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type.in_list([transaction.credit_card_details.card_type, CreditCard.CardType.AmEx]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == CreditCard.CardType.AmEx ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_elo(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.adyen_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Elo, "expiration_date": "10/2020", "cvv": "737", } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == transaction.credit_card_details.card_type ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) self.assertEqual(transaction.credit_card_details.card_type, collection.first.credit_card_details.card_type) def test_advanced_search_hiper(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hiper, "expiration_date": "10/2020", "cvv": "737", } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == transaction.credit_card_details.card_type ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) self.assertEqual(transaction.credit_card_details.card_type, collection.first.credit_card_details.card_type) def test_advanced_search_hipercard(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.hiper_brl_merchant_account_id, "credit_card": { "number": CreditCardNumbers.Hipercard, "expiration_date": "10/2020", "cvv": "737", } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.credit_card_card_type == transaction.credit_card_details.card_type ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) self.assertEqual(transaction.credit_card_details.card_type, collection.first.credit_card_details.card_type) def test_advanced_search_multiple_value_node_allowed_values_credit_card_card_type(self): with self.assertRaisesRegex(AttributeError, "Invalid argument\(s\) for credit_card_card_type: noSuchCreditCardCardType"): Transaction.search([ TransactionSearch.credit_card_card_type == "noSuchCreditCardCardType" ]) def test_advanced_search_multiple_value_node_status(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.status == Transaction.Status.Authorized ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.status.in_list([Transaction.Status.Authorized, Transaction.Status.Settled]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.status == Transaction.Status.Settled ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_authorization_expired_status(self): collection = Transaction.search( TransactionSearch.status == Transaction.Status.AuthorizationExpired ) self.assertTrue(collection.maximum_size > 0) self.assertEqual(Transaction.Status.AuthorizationExpired, collection.first.status) def test_advanced_search_allows_new_settlement_statuses(self): collection = Transaction.search([ TransactionSearch.status.in_list(["settlement_confirmed", "settlement_declined"]) ]) print(collection) def test_advanced_search_settlement_confirmed_transaction(self): transaction_id = "settlement_confirmed_txn" collection = Transaction.search([ TransactionSearch.id == transaction_id ]) self.assertEqual(1, collection.maximum_size) def test_advanced_search_multiple_value_node_allowed_values_status(self): with self.assertRaisesRegex(AttributeError, "Invalid argument\(s\) for status: noSuchStatus"): Transaction.search([TransactionSearch.status == "noSuchStatus"]) def test_advanced_search_multiple_value_node_source(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.source == Transaction.Source.Api ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.source.in_list([Transaction.Source.Api, Transaction.Source.ControlPanel]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.source == Transaction.Source.ControlPanel ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_multiple_value_node_type(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.type == Transaction.Type.Sale ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.type.in_list([Transaction.Type.Sale, Transaction.Type.Credit]) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.type == Transaction.Type.Credit ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_multiple_value_node_allowed_values_type(self): with self.assertRaisesRegex(AttributeError, "Invalid argument\(s\) for type: noSuchType"): Transaction.search([ TransactionSearch.type == "noSuchType" ]) def test_advanced_search_multiple_value_node_type_with_refund(self): name = "Anabel Atkins%s" % random.randint(1, 100000) sale = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name }, 'options': { 'submit_for_settlement': True } }).transaction TestHelper.settle_transaction(sale.id) refund = Transaction.refund(sale.id).transaction credit = Transaction.credit({ "amount": Decimal(TransactionAmounts.Authorize), "credit_card": { "number": "4111111111111111", "expiration_date": "05/2009", "cardholder_name": name } }).transaction collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.type == Transaction.Type.Credit ]) self.assertEqual(2, collection.maximum_size) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.type == Transaction.Type.Credit, TransactionSearch.refund == True ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(refund.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.type == Transaction.Type.Credit, TransactionSearch.refund == False ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(credit.id, collection.first.id) def test_advanced_search_range_node_amount(self): name = "Henrietta Livingston%s" % random.randint(1, 100000) t_1000 = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction t_1500 = Transaction.sale({ "amount": "1500.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction t_1800 = Transaction.sale({ "amount": "1800.00", "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cardholder_name": name } }).transaction collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount >= "1700" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1800.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount <= "1250" ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1000.id, collection.first.id) collection = Transaction.search([ TransactionSearch.credit_card_cardholder_name == name, TransactionSearch.amount.between("1100", "1600") ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(t_1500.id, collection.first.id) def test_advanced_search_range_node_created_at_less_than_or_equal_to(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = transaction.created_at - timedelta(minutes=10) now = transaction.created_at future = transaction.created_at + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at <= past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at <= now ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at <= future ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_range_node_created_at_greater_than_or_equal_to(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = transaction.created_at - timedelta(minutes=10) now = transaction.created_at future = transaction.created_at + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at >= past ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at >= now ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at >= future ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_created_at_between(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = transaction.created_at - timedelta(minutes=10) now = transaction.created_at future = transaction.created_at + timedelta(minutes=10) future2 = transaction.created_at + timedelta(minutes=20) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(past, now) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(now, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_created_at_is(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = transaction.created_at - timedelta(minutes=10) now = transaction.created_at future = transaction.created_at + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at == past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at == now ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at == future ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_created_with_dates(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.created_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_range_node_disbursement_date_less_than_or_equal_to(self): transaction_id = "deposittransaction" disbursement_time = datetime(2013, 4, 10, 0, 0, 0) past = disbursement_time - timedelta(minutes=10) future = disbursement_time + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date <= past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction_id, ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) def test_advanced_search_range_node_disbursement_date_greater_than_or_equal_to(self): transaction_id = "deposittransaction" disbursement_time = datetime(2013, 4, 10, 0, 0, 0) past = disbursement_time - timedelta(minutes=10) future = disbursement_time + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date >= past ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date >= disbursement_time ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date >= future ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_disbursement_date_between(self): transaction_id = "deposittransaction" disbursement_time = datetime(2013, 4, 10, 0, 0, 0) past = disbursement_time - timedelta(days=1) future = disbursement_time + timedelta(days=1) future2 = disbursement_time + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(past, disbursement_time) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(disbursement_time, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_disbursement_date_is(self): transaction_id = "deposittransaction" disbursement_time = datetime(2013, 4, 10, 0, 0, 0) past = disbursement_time - timedelta(days=10) now = disbursement_time future = disbursement_time + timedelta(days=10) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date == past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date == now ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date == future ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_disbursement_date_with_dates(self): transaction_id = "deposittransaction" disbursement_date = date(2013, 4, 10) past = disbursement_date - timedelta(days=1) future = disbursement_date + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.disbursement_date.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction_id, collection.first.id) def test_advanced_search_range_node_disputed_date_less_than_or_equal_to(self): disputed_transaction_id = TestHelper.create_disputed_transaction().id disputed_time = datetime.now() past = disputed_time - timedelta(days=1) future = disputed_time + timedelta(minutes=10) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date <= past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date <= disputed_time ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date <= future ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) def test_advanced_search_range_node_disputed_date_greater_than_or_equal_to(self): disputed_transaction_id = TestHelper.create_disputed_transaction().id disputed_time = datetime.now() past = disputed_time - timedelta(minutes=10) future = disputed_time + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date >= past ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date >= disputed_time ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date >= future ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_disputed_date_between(self): disputed_transaction_id = TestHelper.create_disputed_transaction().id disputed_time = datetime.now() past = disputed_time - timedelta(days=1) future = disputed_time + timedelta(days=1) future2 = disputed_time + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date.between(past, disputed_time) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date.between(disputed_time, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_disputed_date_is(self): disputed_transaction_id = TestHelper.create_disputed_transaction().id disputed_date = datetime.today() past = disputed_date - timedelta(days=10) future = disputed_date + timedelta(days=10) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date == past ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date == future ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date == disputed_date ]) self.assertEqual(1, collection.maximum_size) def test_advanced_search_range_node_disputed_date_with_dates(self): disputed_transaction_id = TestHelper.create_disputed_transaction().id disputed_date = datetime.today() past = disputed_date - timedelta(days=1) future = disputed_date + timedelta(days=1) collection = Transaction.search([ TransactionSearch.id == disputed_transaction_id, TransactionSearch.dispute_date.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(disputed_transaction_id, collection.first.id) def test_advanced_search_range_node_authorization_expired_at(self): two_days_ago = datetime.today() - timedelta(days=2) yesterday = datetime.today() - timedelta(days=1) tomorrow = datetime.today() + timedelta(days=1) collection = Transaction.search( TransactionSearch.authorization_expired_at.between(two_days_ago, yesterday) ) self.assertEqual(0, collection.maximum_size) collection = Transaction.search( TransactionSearch.authorization_expired_at.between(yesterday, tomorrow) ) self.assertTrue(collection.maximum_size > 0) self.assertEqual(Transaction.Status.AuthorizationExpired, collection.first.status) def test_advanced_search_range_node_authorized_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_failed_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Fail, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.failed_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.failed_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_gateway_rejected_at(self): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key try: Configuration.merchant_id = "processing_rules_merchant_id" Configuration.public_key = "processing_rules_public_key" Configuration.private_key = "processing_rules_private_key" transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012", "cvv": "200" } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.gateway_rejected_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.gateway_rejected_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key def test_advanced_search_range_node_processor_declined_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Decline, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.processor_declined_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.processor_declined_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_settled_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" }, "options": { "submit_for_settlement": True } }).transaction TestHelper.settle_transaction(transaction.id) transaction = Transaction.find(transaction.id) past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.settled_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.settled_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_submitted_for_settlement_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" }, "options": { "submit_for_settlement": True } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.submitted_for_settlement_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.submitted_for_settlement_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_voided_at(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" } }).transaction transaction = Transaction.void(transaction.id).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.voided_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.voided_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_range_node_can_search_on_multiple_statuses(self): transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "credit_card": { "number": "4111111111111111", "expiration_date": "05/2012" }, "options": { "submit_for_settlement": True } }).transaction past = datetime.today() - timedelta(days=1) future = datetime.today() + timedelta(days=1) future2 = datetime.today() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(past, future), TransactionSearch.submitted_for_settlement_at.between(past, future) ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(future, future2), TransactionSearch.submitted_for_settlement_at.between(future, future2) ]) self.assertEqual(0, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.authorized_at.between(past, future), TransactionSearch.voided_at.between(past, future) ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_returns_iteratable_results(self): collection = Transaction.search([ TransactionSearch.credit_card_number.starts_with("411") ]) self.assertTrue(collection.maximum_size > 100) transaction_ids = [transaction.id for transaction in collection.items] self.assertEqual(collection.maximum_size, len(TestHelper.unique(transaction_ids))) def test_advanced_search_can_search_on_paypal_fields(self): http = ClientApiHttp.create() status_code, nonce = http.get_paypal_nonce({ "access_token": "PAYPAL-ACCESS-TOKEN", "options": {"validate": False} }) self.assertEqual(202, status_code) transaction = Transaction.sale({ "amount": TransactionAmounts.Authorize, "payment_method_nonce": nonce }).transaction collection = Transaction.search([ TransactionSearch.paypal_payer_email == transaction.paypal_details.payer_email, TransactionSearch.paypal_authorization_id == transaction.paypal_details.authorization_id, TransactionSearch.paypal_payment_id == transaction.paypal_details.payment_id, ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_advanced_search_can_search_on_store_id_1(self): transaction_id = "contact_visa_transaction" collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.store_id == "store-id" ]) self.assertEqual(1, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.store_id == "invalid-store-id" ]) self.assertEqual(0, collection.maximum_size) def test_advanced_search_can_search_on_store_ids(self): transaction_id = "contact_visa_transaction" collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.store_ids.in_list(["store-id"]) ]) self.assertEqual(1, collection.maximum_size) collection = Transaction.search([ TransactionSearch.id == transaction_id, TransactionSearch.store_ids.in_list(["invalid-store-id"]) ]) self.assertEqual(0, collection.maximum_size) def test_search_handles_a_search_timeout(self): with self.assertRaises(RequestTimeoutError): Transaction.search([ TransactionSearch.amount.between("-1100", "1600") ]) def test_search_returns_records_from_valid_daterange(self): yesterday = datetime.now() - timedelta(days=1) tomorrow = datetime.now() + timedelta(days=1) collection = Transaction.search([ TransactionSearch.ach_return_responses_created_at.between(yesterday, tomorrow) ]) self.assertEqual(2, collection.maximum_size) def test_search_returns_records_from_invalid_daterange(self): day_after_tomorrow = datetime.now() + timedelta(days=1) tomorrow = datetime.now() + timedelta(days=2) collection = Transaction.search([ TransactionSearch.ach_return_responses_created_at.between(tomorrow, day_after_tomorrow) ]) self.assertEqual(0, collection.maximum_size) def test_search_returns_records_for_one_reasoncode(self): collection = Transaction.search([ TransactionSearch.reason_code.in_list(['R01']) ]) self.assertEqual(1, collection.maximum_size) def test_search_returns_records_for_multiple_reasoncode(self): collection = Transaction.search([ TransactionSearch.reason_code.in_list(['R01', 'R02']) ]) self.assertEqual(2, collection.maximum_size) def test_search_returns_multiple_records_for_any_reason_code(self): collection = Transaction.search([ TransactionSearch.reason_code == Transaction.ReasonCode.ANY_REASON_CODE ]) self.assertEqual(2, collection.maximum_size) def test_search_retried_transaction(self): result = Transaction.sale({ "merchant_account_id": TestHelper.default_merchant_account_id, "amount": TransactionAmounts.Decline, "payment_method_token": "network_tokenized_credit_card", }) transaction = result.transaction retry_transaction_id = transaction.retry_ids[0] collection = Transaction.search( TransactionSearch.id == retry_transaction_id, TransactionSearch.amount == TransactionAmounts.Decline, ) self.assertEqual(1, collection.maximum_size) self.assertIsNotNone(collection.first.retried_transaction_id) self.assertEqual(retry_transaction_id, collection.first.id) braintree_python-4.31.0/tests/integration/test_transaction_with_us_bank_account.py000066400000000000000000000145201471021343500310510ustar00rootroot00000000000000from tests.test_helper import * from braintree.payment_instrument_type import PaymentInstrumentType from braintree.us_bank_account_verification import UsBankAccountVerification class TestTransactionWithUsBankAccount(unittest.TestCase): def test_nonce_transactions(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "submit_for_settlement": True, "store_in_vault": True } }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.us_bank_account.routing_number, "021000021") self.assertEqual(result.transaction.us_bank_account.last_4, "1234") self.assertEqual(result.transaction.us_bank_account.account_type, "checking") self.assertEqual(result.transaction.us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", result.transaction.us_bank_account.bank_name)) self.assertEqual(result.transaction.us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(result.transaction.us_bank_account.ach_mandate.accepted_at, datetime) def test_nonce_transactions_with_vaulted_token(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "submit_for_settlement": True, "store_in_vault": True } }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.us_bank_account.routing_number, "021000021") self.assertEqual(result.transaction.us_bank_account.last_4, "1234") self.assertEqual(result.transaction.us_bank_account.account_type, "checking") self.assertEqual(result.transaction.us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", result.transaction.us_bank_account.bank_name)) self.assertEqual(result.transaction.us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(result.transaction.us_bank_account.ach_mandate.accepted_at, datetime) token = result.transaction.us_bank_account.token result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, "payment_method_token": token, "options": { "submit_for_settlement": True, } }) self.assertTrue(result.is_success) self.assertEqual(result.transaction.us_bank_account.routing_number, "021000021") self.assertEqual(result.transaction.us_bank_account.last_4, "1234") self.assertEqual(result.transaction.us_bank_account.account_type, "checking") self.assertEqual(result.transaction.us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", result.transaction.us_bank_account.bank_name)) self.assertEqual(result.transaction.us_bank_account.ach_mandate.text, "cl mandate text") self.assertIsInstance(result.transaction.us_bank_account.ach_mandate.accepted_at, datetime) def test_token_transactions_not_found(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, "payment_method_nonce": TestHelper.generate_invalid_us_bank_account_nonce(), "options": { "submit_for_settlement": True, "store_in_vault": True } }) self.assertFalse(result.is_success) error_code = result.errors.for_object("transaction").on("payment_method_nonce")[0].code self.assertEqual(error_code, ErrorCodes.Transaction.PaymentMethodNonceUnknown) @unittest.skip("until we have a more stable ci env") def test_verification_create_with_plaid_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, "payment_method_nonce": TestHelper.generate_plaid_us_bank_account_nonce(), "options": { "submit_for_settlement": True, "store_in_vault": True } }) self.assertTrue(result.is_success) token = result.transaction.us_bank_account.token us_bank_account = PaymentMethod.find(token) self.assertEqual(result.transaction.payment_instrument_type, PaymentInstrumentType.UsBankAccount) self.assertEqual(len(us_bank_account.verifications), 1) self.assertEqual(us_bank_account.verifications[0].verification_method, UsBankAccountVerification.VerificationMethod.TokenizedCheck) self.assertEqual(us_bank_account.verifications[0].status, UsBankAccountVerification.Status.Verified) class TestTransactionWithUsBankAccountCompliantMerchant(unittest.TestCase): def setUp(self): braintree.Configuration.configure( braintree.Environment.Development, "integration2_merchant_id", "integration2_public_key", "integration2_private_key" ) def tearDown(self): braintree.Configuration.configure( braintree.Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) def test_reject_non_plaid_nonce(self): result = Transaction.sale({ "amount": TransactionAmounts.Authorize, "merchant_account_id": "another_us_bank_merchant_account", "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "submit_for_settlement": True, "store_in_vault": True } }) self.assertFalse(result.is_success) error_code = result.errors.for_object("transaction").on("payment_method_nonce")[0].code self.assertEqual(ErrorCodes.Transaction.UsBankAccountNonceMustBePlaidVerified, error_code) braintree_python-4.31.0/tests/integration/test_us_bank_account.py000066400000000000000000000050001471021343500254020ustar00rootroot00000000000000from tests.test_helper import * class TestUsBankAccount(unittest.TestCase): def test_find_returns_us_bank_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } }) self.assertTrue(result.is_success) found_account = UsBankAccount.find(result.payment_method.token) self.assertEqual(found_account.routing_number, "021000021") self.assertEqual(found_account.last_4, "1234") self.assertEqual(found_account.account_type, "checking") self.assertEqual(found_account.account_holder_name, "Dan Schulman") self.assertRegex(found_account.bank_name, r".*CHASE.*") self.assertEqual(found_account.default, True) self.assertEqual(found_account.ach_mandate.text, "cl mandate text") self.assertIsNotNone(found_account.ach_mandate.accepted_at) self.assertIsInstance(found_account.ach_mandate.accepted_at, datetime) def test_find_does_not_return_invalid_us_bank_account(self): self.assertRaises(NotFoundError, UsBankAccount.find, TestHelper.generate_invalid_us_bank_account_nonce()) def test_sale_transacts_us_bank_account(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id } }) self.assertTrue(result.is_success) params = { "amount": TransactionAmounts.Authorize, "merchant_account_id": TestHelper.us_bank_merchant_account_id, } result = UsBankAccount.sale(result.payment_method.token, params) self.assertTrue(result.is_success) self.assertEqual(result.transaction.us_bank_account.routing_number, "021000021") self.assertEqual(result.transaction.us_bank_account.last_4, "1234") self.assertEqual(result.transaction.us_bank_account.account_type, "checking") self.assertEqual(result.transaction.us_bank_account.account_holder_name, "Dan Schulman") self.assertTrue(re.match(r".*CHASE.*", result.transaction.us_bank_account.bank_name)) braintree_python-4.31.0/tests/integration/test_us_bank_account_verification.py000066400000000000000000000250021471021343500301500ustar00rootroot00000000000000from tests.test_helper import * from braintree.us_bank_account_verification import UsBankAccountVerification from braintree.us_bank_account_verification_search import UsBankAccountVerificationSearch class TestUsBankAccountVerification(unittest.TestCase): def test_find_by_id(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.IndependentCheck } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) created_verification = result.payment_method.verifications[0] found_verification = UsBankAccountVerification.find(created_verification.id) self.assertEqual(created_verification, found_verification) def test_search_by_verification_method(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.IndependentCheck } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) created_verification = result.payment_method.verifications[0] found_verifications = UsBankAccountVerification.search( UsBankAccountVerificationSearch.verification_method.in_list( [UsBankAccountVerification.VerificationMethod.IndependentCheck] ), UsBankAccountVerificationSearch.customer_id == customer_id, ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(created_verification, found_verifications.first) def test_search_by_status(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.IndependentCheck } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) created_verification = result.payment_method.verifications[0] found_verifications = UsBankAccountVerification.search( UsBankAccountVerificationSearch.status.in_list([UsBankAccountVerification.Status.Verified]), UsBankAccountVerificationSearch.customer_id == customer_id, ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(created_verification, found_verifications.first) def test_search_by_account_number(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(account_number="1000000000"), "options": { "verification_merchant_account_id": TestHelper.us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.IndependentCheck } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) created_verification = result.payment_method.verifications[0] found_verifications = UsBankAccountVerification.search( UsBankAccountVerificationSearch.account_number.ends_with("0000"), UsBankAccountVerificationSearch.customer_id == customer_id, ) self.assertEqual(1, found_verifications.maximum_size) self.assertEqual(created_verification, found_verifications.first) class TestUsBankAccountVerificationCompliant(unittest.TestCase): def setUp(self): braintree.Configuration.configure( braintree.Environment.Development, "integration2_merchant_id", "integration2_public_key", "integration2_private_key" ) def tearDown(self): braintree.Configuration.configure( braintree.Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) def test_successfully_confirm_settled_micro_transfer_amounts(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(account_number="1000000000"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.MicroTransfers } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) verification = result.payment_method.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Pending) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.MicroTransfers) result = UsBankAccountVerification.confirm_micro_transfer_amounts(verification.id, [17, 29]) self.assertTrue(result.is_success) self.assertEqual(result.us_bank_account_verification.status, UsBankAccountVerification.Status.Verified) us_bank_account = UsBankAccount.find(result.us_bank_account_verification.us_bank_account.token) self.assertTrue(us_bank_account.verified) def test_successfully_confirm_unsettled_micro_transfer_amounts(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(account_number="1000000001"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.MicroTransfers } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) verification = result.payment_method.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Pending) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.MicroTransfers) result = UsBankAccountVerification.confirm_micro_transfer_amounts(verification.id, [17, 29]) self.assertTrue(result.is_success) self.assertEqual(result.us_bank_account_verification.status, UsBankAccountVerification.Status.Pending) us_bank_account = UsBankAccount.find(result.us_bank_account_verification.us_bank_account.token) self.assertFalse(us_bank_account.verified) def test_attempt_confirm_micro_transfer_amounts(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(account_number="1000000000"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.MicroTransfers } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) verification = result.payment_method.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Pending) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.MicroTransfers) result = UsBankAccountVerification.confirm_micro_transfer_amounts(verification.id, [1, 1]) self.assertFalse(result.is_success) error_code = result.errors.for_object("us_bank_account_verification").on("base")[0].code self.assertEqual(ErrorCodes.UsBankAccountVerification.AmountsDoNotMatch, error_code) def test_gateway_reject_confirm_micro_transfer_amounts(self): customer_id = Customer.create().customer.id result = PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": TestHelper.generate_valid_us_bank_account_nonce(account_number="1000000000"), "options": { "verification_merchant_account_id": TestHelper.another_us_bank_merchant_account_id, "us_bank_account_verification_method": UsBankAccountVerification.VerificationMethod.MicroTransfers } }) self.assertTrue(result.is_success) self.assertEqual(len(result.payment_method.verifications), 1) verification = result.payment_method.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Pending) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.MicroTransfers) for i in range(4): result = UsBankAccountVerification.confirm_micro_transfer_amounts(verification.id, [1, 1]) self.assertFalse(result.is_success) error_code = result.errors.for_object("us_bank_account_verification").on("base")[0].code self.assertEqual(ErrorCodes.UsBankAccountVerification.AmountsDoNotMatch, error_code) result = UsBankAccountVerification.confirm_micro_transfer_amounts(verification.id, [1, 1]) self.assertFalse(result.is_success) error_code = result.errors.for_object("us_bank_account_verification").on("base")[0].code self.assertEqual(ErrorCodes.UsBankAccountVerification.TooManyConfirmationAttempts, error_code) braintree_python-4.31.0/tests/integration/test_visa_checkout.py000066400000000000000000000122401471021343500250770ustar00rootroot00000000000000from tests.test_helper import * class TestVisaCheckout(unittest.TestCase): def test_create_from_nonce(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.VisaCheckoutVisa }) self.assertTrue(result.is_success) visa_checkout_card = result.payment_method self.assertEqual("abc123", visa_checkout_card.call_id) self.assertIsNotNone(visa_checkout_card.billing_address) self.assertIsNotNone(visa_checkout_card.bin) self.assertIsNotNone(visa_checkout_card.card_type) self.assertIsNotNone(visa_checkout_card.cardholder_name) self.assertIsNotNone(visa_checkout_card.commercial) self.assertIsNotNone(visa_checkout_card.country_of_issuance) self.assertIsNotNone(visa_checkout_card.created_at) self.assertIsNotNone(visa_checkout_card.customer_id) self.assertIsNotNone(visa_checkout_card.customer_location) self.assertIsNotNone(visa_checkout_card.debit) self.assertIsNotNone(visa_checkout_card.default) self.assertIsNotNone(visa_checkout_card.durbin_regulated) self.assertIsNotNone(visa_checkout_card.expiration_date) self.assertIsNotNone(visa_checkout_card.expiration_month) self.assertIsNotNone(visa_checkout_card.expiration_year) self.assertIsNotNone(visa_checkout_card.expired) self.assertIsNotNone(visa_checkout_card.healthcare) self.assertIsNotNone(visa_checkout_card.image_url) self.assertIsNotNone(visa_checkout_card.issuing_bank) self.assertIsNotNone(visa_checkout_card.last_4) self.assertIsNotNone(visa_checkout_card.masked_number) self.assertIsNotNone(visa_checkout_card.payroll) self.assertIsNotNone(visa_checkout_card.prepaid) self.assertIsNotNone(visa_checkout_card.product_id) self.assertIsNotNone(visa_checkout_card.subscriptions) self.assertIsNotNone(visa_checkout_card.token) self.assertIsNotNone(visa_checkout_card.unique_number_identifier) self.assertIsNotNone(visa_checkout_card.updated_at) customer = Customer.find(customer.id) self.assertEqual(len(customer.visa_checkout_cards), 1) self.assertEqual(result.payment_method.token, customer.visa_checkout_cards[0].token) def test_create_with_verification(self): customer = Customer.create().customer result = PaymentMethod.create({ "customer_id": customer.id, "payment_method_nonce": Nonces.VisaCheckoutVisa, "options": { "verify_card": "true" } }) self.assertTrue(result.is_success) verification = result.payment_method.verification self.assertEqual(CreditCardVerification.Status.Verified, verification.status) def test_search_for_transaction(self): result = Transaction.sale({ "payment_method_nonce": Nonces.VisaCheckoutVisa, "amount": "1.23" }) self.assertTrue(result.is_success) transaction = result.transaction collection = Transaction.search([ TransactionSearch.id == transaction.id, TransactionSearch.payment_instrument_type == PaymentInstrumentType.VisaCheckoutCard ]) self.assertEqual(1, collection.maximum_size) self.assertEqual(transaction.id, collection.first.id) def test_create_transaction_from_nonce_and_vault(self): customer = Customer.create().customer result = Transaction.sale({ "payment_method_nonce": Nonces.VisaCheckoutVisa, "customer_id": customer.id, "amount": "1.23", "options": { "store_in_vault": "true" } }) self.assertTrue(result.is_success) visa_checkout_card_details = result.transaction.visa_checkout_card_details self.assertEqual("abc123", visa_checkout_card_details.call_id) self.assertIsNotNone(visa_checkout_card_details.bin) self.assertIsNotNone(visa_checkout_card_details.card_type) self.assertIsNotNone(visa_checkout_card_details.cardholder_name) self.assertIsNotNone(visa_checkout_card_details.commercial) self.assertIsNotNone(visa_checkout_card_details.country_of_issuance) self.assertIsNotNone(visa_checkout_card_details.debit) self.assertIsNotNone(visa_checkout_card_details.durbin_regulated) self.assertIsNotNone(visa_checkout_card_details.expiration_date) self.assertIsNotNone(visa_checkout_card_details.expiration_year) self.assertIsNotNone(visa_checkout_card_details.expiration_month) self.assertIsNotNone(visa_checkout_card_details.healthcare) self.assertIsNotNone(visa_checkout_card_details.image_url) self.assertIsNotNone(visa_checkout_card_details.issuing_bank) self.assertIsNotNone(visa_checkout_card_details.last_4) self.assertIsNotNone(visa_checkout_card_details.payroll) self.assertIsNotNone(visa_checkout_card_details.prepaid) self.assertIsNotNone(visa_checkout_card_details.product_id) self.assertIsNotNone(visa_checkout_card_details.token) braintree_python-4.31.0/tests/test_helper.py000066400000000000000000000457211471021343500212160ustar00rootroot00000000000000from base64 import b64decode, encodebytes from contextlib import contextmanager from datetime import date, datetime, timedelta from decimal import Decimal from enum import Enum from http.client import HTTPConnection from subprocess import Popen, PIPE from urllib.parse import urlencode, quote_plus import json import os import random import re import requests import subprocess import sys import time import unittest import warnings from braintree import * from braintree.exceptions import * from braintree.test.credit_card_numbers import CreditCardNumbers from braintree.test.nonces import Nonces from braintree.testing_gateway import * from braintree.util import * def reset_braintree_configuration(): Configuration.configure( Environment.Development, "integration_merchant_id", "integration_public_key", "integration_private_key" ) reset_braintree_configuration() class AdvancedFraudKountIntegrationMerchant: def __enter__(self): Configuration.configure( Environment.Development, "advanced_fraud_integration_merchant_id", "advanced_fraud_integration_public_key", "advanced_fraud_integration_private_key" ) def __exit__(self, type, value, trace): reset_braintree_configuration() class FraudProtectionEnterpriseIntegrationMerchant: def __enter__(self): Configuration.configure( Environment.Development, "fraud_protection_enterprise_integration_merchant_id", "fraud_protection_enterprise_integration_public_key", "fraud_protection_enterprise_integration_private_key" ) def __exit__(self, type, value, trace): reset_braintree_configuration() class EffortlessChargebackProtectionMerchant: def __enter__(self): Configuration.configure( Environment.Development, "fraud_protection_effortless_chargeback_protection_merchant_id", "effortless_chargeback_protection_public_key", "effortless_chargeback_protection_private_key" ) def __exit__(self, type, value, trace): reset_braintree_configuration() class DuplicateCheckingMerchant: def __enter__(self): Configuration.configure( Environment.Development, "dup_checking_integration_merchant_id", "dup_checking_integration_public_key", "dup_checking_integration_private_key" ) def __exit__(self, type, value, trace): reset_braintree_configuration() def showwarning(*_): pass warnings.showwarning = showwarning class TestHelper(object): adyen_merchant_account_id = "adyen_ma" aib_swe_ma_merchant_account_id = "aib_swe_ma" another_us_bank_merchant_account_id = "another_us_bank_merchant_account" card_processor_brl_merchant_account_id = "card_processor_brl" default_merchant_account_id = "sandbox_credit_card" fake_amex_direct_merchant_account_id = "fake_amex_direct_usd" fake_first_data_merchant_account_id = "fake_first_data_merchant_account" fake_venmo_account_merchant_account_id = "fake_first_data_venmo_account" hiper_brl_merchant_account_id = "hiper_brl" non_default_merchant_account_id = "sandbox_credit_card_non_default" non_default_sub_merchant_account_id = "sandbox_sub_merchant_account" pinless_debit_merchant_account_id = "pinless_debit" three_d_secure_merchant_account_id = "three_d_secure_merchant_account" us_bank_merchant_account_id = "us_bank_merchant_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 } valid_token_characters = list("bcdfghjkmnpqrstvwxyz23456789") text_type = str raw_type = bytes @staticmethod def make_past_due(subscription, number_of_days_past_due=1): Configuration.gateway().testing.make_past_due(subscription.id, number_of_days_past_due) @staticmethod def escrow_transaction(transaction_id): Configuration.gateway().testing.escrow_transaction(transaction_id) @staticmethod def settle_transaction(transaction_id): return Configuration.gateway().testing.settle_transaction(transaction_id) @staticmethod def settlement_confirm_transaction(transaction_id): return Configuration.gateway().testing.settlement_confirm_transaction(transaction_id) @staticmethod def settlement_decline_transaction(transaction_id): return Configuration.gateway().testing.settlement_decline_transaction(transaction_id) @staticmethod def settlement_pending_transaction(transaction_id): return Configuration.gateway().testing.settlement_pending_transaction(transaction_id) @staticmethod def create_3ds_verification(merchant_account_id, params): return Configuration.gateway().testing.create_3ds_verification(merchant_account_id, params) @staticmethod @contextmanager def other_merchant(merchant_id, public_key, private_key): old_merchant_id = Configuration.merchant_id old_public_key = Configuration.public_key old_private_key = Configuration.private_key Configuration.merchant_id = merchant_id Configuration.public_key = public_key Configuration.private_key = private_key try: yield finally: Configuration.merchant_id = old_merchant_id Configuration.public_key = old_public_key Configuration.private_key = old_private_key @staticmethod def includes(collection, expected): for item in collection.items: if item.id == expected.id: return True return False @staticmethod def in_list(collection, expected): for item in collection: if item == expected: return True return False @staticmethod def includes_status(collection, status): for item in collection.items: if item.status == status: return True return False @staticmethod def now_minus_offset(offset): now = datetime.utcnow() return (now - timedelta(hours=offset)).strftime("%Y-%m-%d") @staticmethod def unique(some_list): return set(some_list) @staticmethod def __headers(): return { "Accept": "application/xml", "Content-type": "application/x-www-form-urlencoded", } @staticmethod def generate_decoded_client_token(params=None): client_token = None if params: client_token = ClientToken.generate(params) else: client_token = ClientToken.generate() decoded_client_token = b64decode(client_token).decode() return decoded_client_token @staticmethod def nonce_for_paypal_account(paypal_account_details): client_token = json.loads(TestHelper.generate_decoded_client_token()) client = ClientApiHttp(Configuration.instantiate(), { "authorization_fingerprint": client_token["authorizationFingerprint"] }) _, nonce = client.get_paypal_nonce(paypal_account_details) return nonce @staticmethod def random_token_block(x): string = "" for i in range(6): string += random.choice(TestHelper.valid_token_characters) return string @staticmethod def generate_valid_us_bank_account_nonce(routing_number="021000021", account_number="567891234"): query = ''' mutation TokenizeUsBankAccount($input: TokenizeUsBankAccountInput!) { tokenizeUsBankAccount(input: $input) { paymentMethod { id } } } ''' variables = { "input": { "usBankAccount": { "accountNumber": account_number, "routingNumber": routing_number, "accountType": "CHECKING", "individualOwner": { "firstName": "Dan", "lastName": "Schulman" }, "achMandate": "cl mandate text", "billingAddress": { "streetAddress": "123 Ave", "state": "CA", "city": "San Francisco", "zipCode": "94112" } } } } graphql_request = { "query": query, "variables": variables } response = TestHelper.__send_graphql_request(graphql_request) return response["data"]["tokenizeUsBankAccount"]["paymentMethod"]["id"] @staticmethod def generate_plaid_us_bank_account_nonce(): query = ''' mutation TokenizeUsBankLogin($input: TokenizeUsBankLoginInput!) { tokenizeUsBankLogin(input: $input) { paymentMethod { id } } } ''' variables = { "input": { "usBankLogin": { "publicToken": "good", "accountId": "plaid_account_id", "accountType": "CHECKING", "businessOwner": { "businessName": "PayPal, Inc." }, "achMandate": "cl mandate text", "billingAddress": { "streetAddress": "123 Ave", "state": "CA", "city": "San Francisco", "zipCode": "94112" } } } } graphql_request = { "query": query, "variables": variables } response = TestHelper.__send_graphql_request(graphql_request) return response["data"]["tokenizeUsBankLogin"]["paymentMethod"]["id"] @staticmethod def generate_invalid_us_bank_account_nonce(): token = "tokenusbankacct" for i in range(4): token += "_" + TestHelper.random_token_block('d') token += "_xxx" return token @staticmethod def generate_three_d_secure_nonce(gateway, params): url = gateway.config.base_merchant_path() + "/three_d_secure/create_nonce/" + TestHelper.three_d_secure_merchant_account_id response = gateway.config.http().post(url, params) return response["payment_method_nonce"]["nonce"] @staticmethod def create_disputed_transaction(): if hasattr(TestHelper, 'disputed_transaction'): return TestHelper.disputed_transaction disputed_transaction = Transaction.sale({ "amount": "10.00", "credit_card": { "number": CreditCardNumbers.Disputes.Chargeback, "expiration_date": "04/2018" } }) for _ in range(1, 60): transactions = Transaction.search([ TransactionSearch.id == disputed_transaction.transaction.id, TransactionSearch.dispute_date == datetime.today() ]) if transactions.maximum_size == 1: TestHelper.disputed_transaction = transactions.first return TestHelper.disputed_transaction else: time.sleep(1) raise ValueError('Disputed transaction could not be found') @staticmethod def create_grant(gateway, params): config = gateway.config response = config.http().post("/oauth_testing/grants", { "grant": params }) return response["grant"]["code"] @staticmethod def create_payment_method_grant_fixtures(): config = Configuration( merchant_id="integration_merchant_public_id", public_key="oauth_app_partner_user_public_key", private_key="oauth_app_partner_user_private_key", environment=Environment.Development ) gateway = BraintreeGateway(config) customer = gateway.customer.create().customer credit_card = gateway.credit_card.create( params={ "customer_id": customer.id, "number": "4111111111111111", "expiration_date": "05/2009", "billing_address": { "first_name": "Jon", "last_name": "Doe", "postal_code": "95131" } } ).credit_card oauth_app_gateway = BraintreeGateway( client_id="client_id$development$integration_client_id", client_secret="client_secret$development$integration_client_secret", environment=Environment.Development ) code = TestHelper.create_grant(oauth_app_gateway, { "merchant_public_id": "integration_merchant_id", "scope": "grant_payment_method" }) access_token = oauth_app_gateway.oauth.create_token_from_code({ "code": code }).credentials.access_token granting_gateway = BraintreeGateway( access_token=access_token, ) return (granting_gateway, credit_card) @staticmethod def sample_notification_from_xml(xml): gateway = Configuration.gateway() payload = encodebytes(xml) hmac_payload = Crypto.sha1_hmac_hash(gateway.config.private_key, payload) signature = "%s|%s" % (gateway.config.public_key, hmac_payload) return {'bt_signature': signature, 'bt_payload': payload} @staticmethod def __send_graphql_request(graphql_request): client_token = json.loads(TestHelper.generate_decoded_client_token()) headers = { "Content-Type": "application/json", "Braintree-Version": "2016-10-07", "Authorization": "Bearer " + client_token["braintree_api"]["access_token"] } resp = requests.post(client_token["braintree_api"]["url"] + "/graphql", headers=headers, data=json.dumps(graphql_request)) return json.loads(resp.text) class ClientApiHttp(Http): def __init__(self, config, options): self.config = config self.options = options self.http = Http(config) @staticmethod def create(): config = Configuration.instantiate() client_token = TestHelper.generate_decoded_client_token() authorization_fingerprint = json.loads(client_token)["authorizationFingerprint"] return ClientApiHttp(config, { "authorization_fingerprint": authorization_fingerprint, "shared_customer_identifier": "fake_identifier", "shared_customer_identifier_type": "testing" }) def get(self, path): return self._make_request("GET", path) def post(self, path, params=None): return self._make_request("POST", path, params) def put(self, path, params=None): return self._make_request("PUT", path, params) def _make_request(self, http_verb, path, params=None): http_strategy = self.config.http_strategy() request_body = json.dumps(params) if params else None return http_strategy.http_do(http_verb, path, self.__headers(), request_body) def set_authorization_fingerprint(self, authorization_fingerprint): self.options['authorization_fingerprint'] = authorization_fingerprint def get_configuration(self): encoded_fingerprint = quote_plus(self.options["authorization_fingerprint"]) url = "/merchants/%s/client_api/v1/configuration" % self.config.merchant_id url += "?authorizationFingerprint=%s" % encoded_fingerprint url += "&configVersion=3" return self.get(url) def get_cards(self): encoded_fingerprint = quote_plus(self.options["authorization_fingerprint"]) url = "/merchants/%s/client_api/v1/payment_methods.json" % self.config.merchant_id url += "?authorizationFingerprint=%s" % encoded_fingerprint url += "&sharedCustomerIdentifier=%s" % self.options["shared_customer_identifier"] url += "&sharedCustomerIdentifierType=%s" % self.options["shared_customer_identifier_type"] return self.get(url) def add_card(self, params): url = "/merchants/%s/client_api/v1/payment_methods/credit_cards.json" % self.config.merchant_id if 'authorization_fingerprint' in self.options: params['authorizationFingerprint'] = self.options['authorization_fingerprint'] if 'shared_customer_identifier' in self.options: params['sharedCustomerIdentifier'] = self.options['shared_customer_identifier'] if 'shared_customer_identifier_type' in self.options: params['sharedCustomerIdentifierType'] = self.options['shared_customer_identifier_type'] return self.post(url, params) def get_paypal_nonce(self, paypal_params): url = "/merchants/%s/client_api/v1/payment_methods/paypal_accounts" % self.config.merchant_id params = {"paypal_account": paypal_params} if 'authorization_fingerprint' in self.options: params['authorizationFingerprint'] = self.options['authorization_fingerprint'] status_code, response = self.post(url, params) nonce = None if status_code == 202: nonce = json.loads(response)["paypalAccounts"][0]["nonce"] return [status_code, nonce] def get_credit_card_nonce(self, credit_card_params): url = "/merchants/%s/client_api/v1/payment_methods/credit_cards" % self.config.merchant_id params = {"credit_card": credit_card_params} if 'authorization_fingerprint' in self.options: params['authorizationFingerprint'] = self.options['authorization_fingerprint'] status_code, response = self.post(url, params) nonce = None if status_code in [201, 202]: nonce = json.loads(response)["creditCards"][0]["nonce"] return [status_code, nonce] def __headers(self): return { "Content-type": "application/json", "User-Agent": "Braintree Python " + version.Version, #pylint: disable=E0602 "X-ApiVersion": Configuration.api_version() } class ExpirationHelper(Enum): ADYEN = "03/2030" braintree_python-4.31.0/tests/unit/000077500000000000000000000000001471021343500172745ustar00rootroot00000000000000braintree_python-4.31.0/tests/unit/__init__.py000066400000000000000000000000001471021343500213730ustar00rootroot00000000000000braintree_python-4.31.0/tests/unit/merchant_account/000077500000000000000000000000001471021343500226115ustar00rootroot00000000000000braintree_python-4.31.0/tests/unit/merchant_account/__init__.py000066400000000000000000000000001471021343500247100ustar00rootroot00000000000000braintree_python-4.31.0/tests/unit/merchant_account/test_address_details.py000066400000000000000000000011271471021343500273550ustar00rootroot00000000000000from tests.test_helper import * from braintree.merchant_account.address_details import AddressDetails class TestAddressDetails(unittest.TestCase): def test_repr_has_all_fields(self): details = AddressDetails({ "street_address": "123 First St", "region": "Las Vegas", "locality": "NV", "postal_code": "89913" }) regex = r"" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-4.31.0/tests/unit/merchant_account/test_business_details.py000066400000000000000000000015271471021343500275670ustar00rootroot00000000000000from tests.test_helper import * from braintree.merchant_account.business_details import BusinessDetails class TestBusinessDetails(unittest.TestCase): def test_repr_has_all_fields(self): details = BusinessDetails({ "dba_name": "Bar Suenami", "legal_name": "Suenami Restaurant Group", "tax_id": "123001234", "address": { "street_address": "123 First St", "region": "Las Vegas", "locality": "NV", } }) regex = r"} at \w+>" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-4.31.0/tests/unit/merchant_account/test_funding_details.py000066400000000000000000000012751471021343500273660ustar00rootroot00000000000000from tests.test_helper import * from braintree.merchant_account.funding_details import FundingDetails class TestFundingDetails(unittest.TestCase): def test_repr_has_all_fields(self): details = FundingDetails({ "destination": "bank", "routing_number": "11112222", "account_number_last_4": "3333", "email": "lucyloo@work.com", "mobile_phone": "9998887777" }) regex = r"" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-4.31.0/tests/unit/merchant_account/test_individual_details.py000066400000000000000000000015771471021343500300710ustar00rootroot00000000000000from tests.test_helper import * from braintree.merchant_account.individual_details import IndividualDetails class TestIndividualDetails(unittest.TestCase): def test_repr_has_all_fields(self): details = IndividualDetails({ "first_name": "Sue", "last_name": "Smith", "email": "sue@hotmail.com", "phone": "1112223333", "date_of_birth": "1980-12-05", "ssn_last_4": "5555", "address": { "street_address": "123 First St", } }) regex = r"} at \w+>" matches = re.match(regex, repr(details)) self.assertTrue(matches) braintree_python-4.31.0/tests/unit/test_address.py000066400000000000000000000054731471021343500223430ustar00rootroot00000000000000from tests.test_helper import * class TestAddress(unittest.TestCase): def test_create_raise_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): Address.create({"customer_id": "12345", "bad_key": "value"}) def test_create_raises_error_if_no_customer_id_given(self): with self.assertRaisesRegex(KeyError, "'customer_id must be provided'"): Address.create({"country_name": "United States of America"}) def test_create_raises_key_error_if_given_invalid_customer_id(self): with self.assertRaisesRegex(KeyError, "'customer_id contains invalid characters'"): Address.create({"customer_id": "!@#$%"}) def test_update_raise_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): Address.update("customer_id", "address_id", {"bad_key": "value"}) def test_update_raises_key_error_if_given_invalid_customer_id(self): with self.assertRaisesRegex(KeyError, "'customer_id contains invalid characters'"): Address.update("!@#$%", "foo") def test_update_raises_key_error_if_given_invalid_address_id(self): with self.assertRaisesRegex(KeyError, "'address_id contains invalid characters'"): Address.update("foo", "!@#$%") def test_delete_raises_key_error_if_given_invalid_customer_id(self): with self.assertRaisesRegex(KeyError, "'customer_id contains invalid characters'"): Address.delete("!@#$%", "foo") def test_delete_raises_key_error_if_given_invalid_address_id(self): with self.assertRaisesRegex(KeyError, "'address_id contains invalid characters'"): Address.delete("foo", "!@#$%") def test_finding_address_with_empty_customer_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): Address.find(" ", "address_id") def test_finding_address_with_none_customer_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): Address.find(None, "address_id") def test_finding_address_with_empty_address_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): Address.find("customer_id", " ") def test_finding_address_with_none_address_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): Address.find("customer_id", None) def test_find_raises_key_error_if_given_invalid_customer_id(self): with self.assertRaisesRegex(KeyError, "'customer_id contains invalid characters'"): Address.find("!@#$%", "foo") def test_find_raises_key_error_if_given_invalid_address_id(self): with self.assertRaisesRegex(KeyError, "'address_id contains invalid characters'"): Address.find("foo", "!@#$%") braintree_python-4.31.0/tests/unit/test_android_pay_card.py000066400000000000000000000022411471021343500241660ustar00rootroot00000000000000from tests.test_helper import * class TestAndroidPayCard(unittest.TestCase): def test_expiration_date(self): card = AndroidPayCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual("05/2014", card.expiration_date) def test_expiration_date_no_month(self): card = AndroidPayCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual(None, card.expiration_date) def test_expiration_date_no_year(self): card = AndroidPayCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "05", "expiration_year": "", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual(None, card.expiration_date)braintree_python-4.31.0/tests/unit/test_apple_pay_card.py000066400000000000000000000022311471021343500236460ustar00rootroot00000000000000from tests.test_helper import * class TestApplePayCard(unittest.TestCase): def test_expiration_date(self): card = ApplePayCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual("05/2014", card.expiration_date) def test_expiration_date_no_month(self): card = ApplePayCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual(None, card.expiration_date) def test_expiration_date_no_year(self): card = ApplePayCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "05", "expiration_year": "", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual(None, card.expiration_date)braintree_python-4.31.0/tests/unit/test_apple_pay_gateway.py000066400000000000000000000027651471021343500244120ustar00rootroot00000000000000from tests.test_helper import * from braintree.apple_pay_gateway import ApplePayGateway from unittest.mock import MagicMock class TestApplePayGateway(unittest.TestCase): @staticmethod def setup_apple_pay_gateway_and_mock_http(): braintree_gateway = BraintreeGateway(Configuration.instantiate()) apple_pay_gateway = ApplePayGateway(braintree_gateway) http_mock = MagicMock(name='config.http') braintree_gateway.config.http = http_mock return apple_pay_gateway, http_mock def test_registered_domains(self): apple_pay_gateway, http_mock = self.setup_apple_pay_gateway_and_mock_http() apple_pay_gateway.registered_domains() self.assertTrue("get('/merchants/integration_merchant_id/processing/apple_pay/registered_domains')" in str(http_mock.mock_calls)) def test_register_domain(self): apple_pay_gateway, http_mock = self.setup_apple_pay_gateway_and_mock_http() apple_pay_gateway.register_domain('test.example.com') self.assertTrue("post('/merchants/integration_merchant_id/processing/apple_pay/validate_domains', {'url': 'test.example.com'})" in str(http_mock.mock_calls)) def test_unregister_domain(self): apple_pay_gateway, http_mock = self.setup_apple_pay_gateway_and_mock_http() apple_pay_gateway.unregister_domain('test.example.com') self.assertTrue("delete('/merchants/integration_merchant_id/processing/apple_pay/unregister_domain?url=test.example.com')" in str(http_mock.mock_calls)) braintree_python-4.31.0/tests/unit/test_authorization_adjustment.py000066400000000000000000000042761471021343500260540ustar00rootroot00000000000000from tests.test_helper import * from datetime import datetime from braintree.authorization_adjustment import AuthorizationAdjustment class TestAuthorizationAdjustment(unittest.TestCase): def test_constructor(self): attributes = { "amount": "-20.00", "timestamp": datetime(2017, 7, 12, 1, 2, 3), "success": True, "processor_response_code": "1000", "processor_response_text": "Approved", } authorization_adjustment = AuthorizationAdjustment(attributes) self.assertEqual(authorization_adjustment.amount, Decimal("-20.00")) self.assertEqual(authorization_adjustment.timestamp, datetime(2017, 7, 12, 1, 2, 3)) self.assertEqual(authorization_adjustment.success, True) self.assertEqual(authorization_adjustment.processor_response_code, "1000") self.assertEqual(authorization_adjustment.processor_response_text, "Approved") def test_constructor_with_amount_as_None(self): attributes = { "amount": None, "timestamp": datetime(2017, 7, 12, 1, 2, 3), "success": True, "processor_response_code": "1000", } authorization_adjustment = AuthorizationAdjustment(attributes) self.assertEqual(authorization_adjustment.amount, None) self.assertEqual(authorization_adjustment.timestamp, datetime(2017, 7, 12, 1, 2, 3)) self.assertEqual(authorization_adjustment.success, True) self.assertEqual(authorization_adjustment.processor_response_code, "1000") def test_constructor_without_amount(self): attributes = { "timestamp": datetime(2017, 7, 12, 1, 2, 3), "success": True, "processor_response_code": "1000", "processor_response_text": "Approved", } authorization_adjustment = AuthorizationAdjustment(attributes) self.assertEqual(authorization_adjustment.timestamp, datetime(2017, 7, 12, 1, 2, 3)) self.assertEqual(authorization_adjustment.success, True) self.assertEqual(authorization_adjustment.processor_response_code, "1000") self.assertEqual(authorization_adjustment.processor_response_text, "Approved") braintree_python-4.31.0/tests/unit/test_client_token.py000066400000000000000000000014301471021343500233610ustar00rootroot00000000000000from tests.test_helper import * class TestClientToken(unittest.TestCase): def test_credit_card_options_require_customer_id(self): for option in ["fail_on_duplicate_payment_method", "fail_on_duplicate_payment_method_for_customer", "make_default", "verify_card"]: with self.assertRaisesRegex(InvalidSignatureError, option): ClientToken.generate({ "options": {option: True} }) def test_generate_delegates_client_token_generation_to_gateway(self): class MockGateway: def generate(self, _): return "mock_client_token" mock_gateway = MockGateway() client_token = ClientToken.generate({}, mock_gateway) self.assertEqual("mock_client_token", client_token) braintree_python-4.31.0/tests/unit/test_configuration.py000066400000000000000000000145621471021343500235640ustar00rootroot00000000000000from tests.test_helper import * import braintree import os import importlib class TestConfiguration(unittest.TestCase): def test_works_with_unconfigured_configuration(self): try: # reset class level attributes on Configuration set in test helper importlib.reload(braintree.configuration) config = Configuration( environment=braintree.Environment.Sandbox, merchant_id='my_merchant_id', public_key='public_key', private_key='private_key' ) config.http_strategy() except AttributeError as e: print(e) self.fail() finally: # repopulate class level attributes on Configuration import tests.test_helper importlib.reload(tests.test_helper) def test_base_merchant_path_for_development(self): self.assertEqual("/merchants/integration_merchant_id", Configuration.instantiate().base_merchant_path()) def test_configuration_construction_for_merchant(self): config = Configuration( environment=braintree.Environment.Sandbox, merchant_id='my_merchant_id', public_key='public_key', private_key='private_key' ) self.assertEqual(config.merchant_id, 'my_merchant_id') self.assertEqual(config.public_key, 'public_key') self.assertEqual(config.private_key, 'private_key') def test_configuration_configure_allows_strings_for_environment(self): try: for environment_string, environment_object in braintree.Environment.All.items(): braintree.Configuration.configure( environment_string, 'my_merchant_id', 'public_key', 'private_key' ) self.assertEqual(braintree.Configuration.environment, environment_object) finally: reset_braintree_configuration() def test_configuration_construction_allows_strings_for_environment(self): config = Configuration( environment='sandbox', merchant_id='my_merchant_id', public_key='public_key', private_key='private_key' ) self.assertEqual(config.environment, braintree.Environment.Sandbox) def test_configuration_construction_allows_empty_parameter_list(self): config = Configuration() self.assertIsInstance(config, braintree.Configuration) def test_configuration_raises_configuration_error_for_invalid_environment(self): for environment in [42, 'not_an_env', '']: def setup_bad_configuration(): Configuration( environment=environment, merchant_id='my_merchant_id', public_key='public_key', private_key='private_key' ) self.assertRaises(ConfigurationError, setup_bad_configuration) def test_configuration_raises_configuration_error_for_empty_merchant_id(self): def setup_bad_configuration(): Configuration( environment=braintree.Environment.Sandbox, merchant_id='', public_key='public_key', private_key='private_key' ) self.assertRaises(ConfigurationError, setup_bad_configuration) def test_configuration_raises_configuration_error_for_empty_public_key(self): def setup_bad_configuration(): Configuration( environment=braintree.Environment.Sandbox, merchant_id='my_merchant_id', public_key='', private_key='private_key' ) self.assertRaises(ConfigurationError, setup_bad_configuration) def test_configuration_raises_configuration_error_for_empty_private_key(self): def setup_bad_configuration(): Configuration( environment=braintree.Environment.Sandbox, merchant_id='my_merchant_id', public_key='public_key', private_key='' ) self.assertRaises(ConfigurationError, setup_bad_configuration) def test_configuration_construction_for_partner(self): config = Configuration.for_partner( braintree.Environment.Sandbox, 'my_partner_id', 'public_key', 'private_key' ) self.assertEqual(config.merchant_id, 'my_partner_id') self.assertEqual(config.public_key, 'public_key') self.assertEqual(config.private_key, 'private_key') def test_configuring_with_an_http_strategy(self): class FakeStrategy(object): def __init__(self, config, environment): pass strategy = Configuration(http_strategy=FakeStrategy).http_strategy() self.assertIsInstance(strategy, FakeStrategy) def test_partner_configuration_does_not_use_default_http_strategy(self): old_http_strategy = Configuration.default_http_strategy class FakeStrategy(object): def __init__(self, config, environment): pass try: Configuration.default_http_strategy = FakeStrategy config = Configuration.for_partner( braintree.Environment.Sandbox, 'my_partner_id', 'public_key', 'private_key' ) self.assertNotIsInstance(config.http_strategy(), FakeStrategy) finally: Configuration.default_http_strategy = old_http_strategy def test_instantiate_with_a_default_http_strategy(self): old_http_strategy = Configuration.default_http_strategy class FakeStrategy(object): def __init__(self, config, environment): pass try: Configuration.default_http_strategy = FakeStrategy strategy = Configuration.instantiate().http_strategy() self.assertIsInstance(strategy, FakeStrategy) finally: Configuration.default_http_strategy = old_http_strategy def test_configuring_with_partial_client_credentials(self): with self.assertRaises(ConfigurationError) as error: Configuration(client_id='client_id$development$integration_client_id') self.assertIn("Missing client_secret when constructing BraintreeGateway", str(error.exception)) braintree_python-4.31.0/tests/unit/test_credit_card.py000066400000000000000000000145501471021343500231550ustar00rootroot00000000000000from tests.test_helper import * import datetime class TestCreditCard(unittest.TestCase): def test_create_raises_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): CreditCard.create({"bad_key": "value"}) def test_update_raises_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): CreditCard.update("token", {"bad_key": "value"}) def test_create_signature(self): expected = ["billing_address_id", "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", "number", "token", "venmo_sdk_payment_method_code", # NEXT_MJOR_VERSION remove venmo_sdk_payment_method_code "device_data", "payment_method_nonce", "device_session_id", "fraud_merchant_id", { "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", "phone_number" ] }, {"options": [ "fail_on_duplicate_payment_method", "fail_on_duplicate_payment_method_for_customer", "make_default", "skip_advanced_fraud_checking", "venmo_sdk_session", # NEXT_MJOR_VERSION remove venmo_sdk_session "verification_account_type", "verification_amount", "verification_merchant_account_id", "verify_card", {"adyen":["overwrite_brand", "selected_brand"]} ]}, { "three_d_secure_pass_thru": [ "cavv", "ds_transaction_id", "eci_flag", "three_d_secure_version", "xid" ] }, "customer_id" ] self.assertEqual(expected, CreditCard.create_signature()) def test_update_signature(self): expected = ["billing_address_id", "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", "number", "token", "venmo_sdk_payment_method_code", # NEXT_MJOR_VERSION remove venmo_sdk_payment_method_code "device_data", "payment_method_nonce", "device_session_id", "fraud_merchant_id", { "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", "phone_number", {"options": ["update_existing"]} ] }, {"options": [ "fail_on_duplicate_payment_method", "fail_on_duplicate_payment_method_for_customer", "make_default", "skip_advanced_fraud_checking", "venmo_sdk_session", # NEXT_MJOR_VERSION remove venmo_sdk_session "verification_account_type", "verification_amount", "verification_merchant_account_id", "verify_card", {"adyen":["overwrite_brand", "selected_brand"]} ]}, { "three_d_secure_pass_thru": [ "cavv", "ds_transaction_id", "eci_flag", "three_d_secure_version", "xid" ] }, ] self.assertEqual(expected, CreditCard.update_signature()) def test_finding_empty_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): CreditCard.find(" ") def test_finding_none_raises_not_found_exception(self): with self.assertRaises(NotFoundError): CreditCard.find(None) def test_from_nonce_empty_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): CreditCard.from_nonce(" ") def test_from_nonce_none_raises_not_found_exception(self): with self.assertRaises(NotFoundError): CreditCard.from_nonce(None) def test_multiple_verifications_sort(self): verification1 = {"created_at": datetime.datetime(2014, 11, 18, 23, 20, 20), "id": 123, "amount": "0.00"} verification2 = {"created_at": datetime.datetime(2014, 11, 18, 23, 20, 21), "id": 456, "amount": "1.00"} credit_card = CreditCard(Configuration.gateway(), {"verifications": [verification1, verification2]}) self.assertEqual(456, credit_card.verification.id) self.assertEqual(1.00, credit_card.verification.amount) def test_expiration_date(self): credit_card = CreditCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual("05/2014", credit_card.expiration_date) def test_expiration_date_no_month(self): credit_card = CreditCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual(None, credit_card.expiration_date) def test_expiration_date_no_year(self): credit_card = CreditCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "05", "expiration_year": "", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual(None, credit_card.expiration_date) def test_masked_number_with_standard_bin(self): credit_card = CreditCard( None, { "bin": "411111", "last_4": "1111", }, ) self.assertEqual(credit_card.masked_number, "411111******1111") def test_masked_number_with_extended_bin(self): credit_card = CreditCard( None, { "bin": "411111", "bin_extended": "41111111", "last_4": "1111", }, ) self.assertEqual(credit_card.masked_number, "41111111****1111") braintree_python-4.31.0/tests/unit/test_credit_card_verification.py000066400000000000000000000107771471021343500257260ustar00rootroot00000000000000from tests.test_helper import * class TestCreditCardVerification(unittest.TestCase): def test_create_raises_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): CreditCardVerification.create({"bad_key": "value", "credit_card": {"number": "value"}}) def test_create_signature(self): billing_address_params = [ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "extended_address", "first_name", "last_name", "locality", "postal_code", "region", "street_address" ] credit_card_params = [ "number", "cvv", "cardholder_name", "cvv", "expiration_date", "expiration_month", "expiration_year", {"billing_address": billing_address_params} ] external_vault_params = [ "previous_network_transaction_id", "status" ] options_params = [ "account_type", "amount", "merchant_account_id" ] risk_data_params = [ "customer_browser", "customer_ip" ] three_d_secure_pass_thru_params = [ "eci_flag", "cavv", "xid", "authentication_response", "directory_response", "cavv_algorithm", "ds_transaction_id", "three_d_secure_version" ] expected = [ {"credit_card": credit_card_params}, {"external_vault": external_vault_params}, "intended_transaction_source", {"options": options_params}, "payment_method_nonce", {"risk_data": risk_data_params}, "three_d_secure_authentication_id", {"three_d_secure_pass_thru": three_d_secure_pass_thru_params}] self.assertEqual(expected, CreditCardVerification.create_signature()) def test_constructor_with_amount(self): attributes = { 'amount': '27.00', 'currency_iso_code': 'USD' } verification = CreditCardVerification(None, attributes) self.assertEqual(verification.amount, Decimal('27.00')) self.assertEqual(verification.currency_iso_code, 'USD') def test_constructor_with_bad_amount(self): attributes = { 'amount': None } verification = CreditCardVerification(None, attributes) self.assertEqual(verification.amount, None) def test_constructor_without_amount(self): verification = CreditCardVerification(None, {}) self.assertEqual(verification.amount, None) self.assertEqual(verification.currency_iso_code, None) def test_constructor_when_risk_data_is_not_included(self): verification = CreditCardVerification(None, {"amount": "1.00"}) self.assertEqual(verification.risk_data, None) def test_constructor_when_network_response_is_included(self): attributes = { 'amount': '1.00', 'network_response_code': '00', 'network_response_text': 'Successful approval/completion or V.I.P. PIN verification is successful' } verification = CreditCardVerification(None, attributes) self.assertEqual(verification.network_response_code, '00') self.assertEqual(verification.network_response_text, 'Successful approval/completion or V.I.P. PIN verification is successful') def test_constructor_when_network_response_is_not_included(self): verification = CreditCardVerification(None, {'amount': '1.00'}) self.assertEqual(verification.network_response_code, None) self.assertEqual(verification.network_response_text, None) def test_constructor_when_ani_result_code_is_included(self): attributes = { 'ani_first_name_response_code': 'M', 'ani_last_name_response_code': 'N' } verification = CreditCardVerification(None, attributes) self.assertEqual(verification.ani_first_name_response_code, 'M') self.assertEqual(verification.ani_last_name_response_code, 'N') def test_finding_empty_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): CreditCardVerification.find(" ") def test_finding_none_raises_not_found_exception(self): with self.assertRaises(NotFoundError): CreditCardVerification.find(None) braintree_python-4.31.0/tests/unit/test_crypto.py000066400000000000000000000015701471021343500222300ustar00rootroot00000000000000from tests.test_helper import * class TestCrypto(unittest.TestCase): def test_sha1_hmac_hash(self): actual = Crypto.sha1_hmac_hash("secretKey", "hello world") self.assertEqual("d503d7a1a6adba1e6474e9ff2c4167f9dfdf4247", actual) def test_sha256_hmac_hash(self): actual = Crypto.sha256_hmac_hash("secret-key", "secret-message") self.assertEqual("68e7f2ecab71db67b1aca2a638f5122810315c3013f27c2196cd53e88709eecc", actual) def test_secure_compare_returns_true_when_same(self): self.assertTrue(Crypto.secure_compare("a_string", "a_string")) def test_secure_compare_returns_false_when_different_lengths(self): self.assertFalse(Crypto.secure_compare("a_string", "a_string_that_is_longer")) def test_secure_compare_returns_false_when_different(self): self.assertFalse(Crypto.secure_compare("a_string", "a_strong")) braintree_python-4.31.0/tests/unit/test_customer.py000066400000000000000000000036321471021343500225520ustar00rootroot00000000000000from tests.test_helper import * class TestCustomer(unittest.TestCase): def test_create_raise_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): Customer.create({"bad_key": "value"}) def test_create_raise_exception_with_bad_nested_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: credit_card\[bad_key\]'"): Customer.create({"credit_card": {"bad_key": "value"}}) def test_update_raise_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): Customer.update("id", {"bad_key": "value"}) def test_update_raise_exception_with_bad_nested_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: credit_card\[bad_key\]'"): Customer.update("id", {"credit_card": {"bad_key": "value"}}) def test_finding_empty_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): Customer.find(" ") def test_finding_none_raises_not_found_exception(self): with self.assertRaises(NotFoundError): Customer.find(None) def test_initialize_sets_paypal_accounts(self): customer = Customer("gateway", { "paypal_accounts": [ {"token": "token1"}, {"token": "token2"} ], "sepa_debit_accounts": [ {"token": "sdd1"}, {"token": "sdd2"} ] }) self.assertEqual(2, len(customer.paypal_accounts)) self.assertEqual("token1", customer.paypal_accounts[0].token) self.assertEqual("token2", customer.paypal_accounts[1].token) self.assertEqual(2, len(customer.sepa_direct_debit_accounts)) self.assertEqual("sdd1", customer.sepa_direct_debit_accounts[0].token) self.assertEqual("sdd2", customer.sepa_direct_debit_accounts[1].token) braintree_python-4.31.0/tests/unit/test_disbursement.py000066400000000000000000000026531471021343500234170ustar00rootroot00000000000000from tests.test_helper import * from datetime import date class TestDisbursement(unittest.TestCase): attributes = { "merchant_account": { "id": "sub_merchant_account", "status": "active", "master_merchant_account": { "id": "master_merchant_account", "status": "active" }, }, "id": "123456", "exception_message": "invalid_account_number", "amount": "100.00", "disbursement_date": date(2013, 4, 10), "follow_up_action": "update", "transaction_ids": ["asdf", "qwer"], "disbursement_type": "credit" } def test_constructor(self): disbursement = Disbursement(None, TestDisbursement.attributes) self.assertEqual("123456", disbursement.id) self.assertEqual(Decimal("100.00"), disbursement.amount) self.assertEqual(["asdf", "qwer"], disbursement.transaction_ids) self.assertEqual("master_merchant_account", disbursement.merchant_account.master_merchant_account.id) def test_credit(self): disbursement = Disbursement(None, TestDisbursement.attributes) self.assertTrue(disbursement.is_credit()) def test_debit(self): thing = TestDisbursement.attributes thing["disbursement_type"] = "debit" disbursement = Disbursement(None, TestDisbursement.attributes) self.assertTrue(disbursement.is_debit()) braintree_python-4.31.0/tests/unit/test_disbursement_detail.py000066400000000000000000000020501471021343500247300ustar00rootroot00000000000000from tests.test_helper import * from braintree.disbursement_detail import DisbursementDetail class TestDisbursementDetail(unittest.TestCase): def test_is_valid_true(self): detail_hash = { 'settlement_amount': '27.00', 'settlement_currency_iso_code': 'USD', 'settlement_currency_exchange_rate': '1', 'disbursed_at': datetime(2013, 4, 11, 0, 0, 0), 'disbursement_date': date(2013, 4, 10), 'funds_held': False } disbursement_details = DisbursementDetail(detail_hash) self.assertTrue(disbursement_details.is_valid) def test_is_valid_false(self): detail_hash = { 'settlement_amount': None, 'settlement_currency_iso_code': None, 'settlement_currency_exchange_rate': None, 'disbursed_at': None, 'disbursement_date': None, 'funds_held': None } disbursement_details = DisbursementDetail(detail_hash) self.assertEqual(False, disbursement_details.is_valid) braintree_python-4.31.0/tests/unit/test_dispute.py000066400000000000000000000364551471021343500223770ustar00rootroot00000000000000from tests.test_helper import * from datetime import date from braintree.dispute import Dispute class TestDispute(unittest.TestCase): legacy_attributes = { "transaction": { "id": "transaction_id", "amount": "100.00", }, "id": "123456", "currency_iso_code": "USD", "status": "open", "amount": "100.00", "received_date": date(2013, 4, 10), "reply_by_date": date(2013, 4, 10), "reason": "fraud", "transaction_ids": ["asdf", "qwer"], "date_opened": date(2013, 4, 1), "date_won": date(2013, 4, 2), "kind": "chargeback", } attributes = { "amount": "100.00", "amount_disputed": "100.00", "amount_won": "0.00", "case_number": "CB123456", "chargeback_protection_level": "effortless", "created_at": datetime(2013, 4, 10, 10, 50, 39), "currency_iso_code": "USD", "date_opened": date(2013, 4, 1), "date_won": date(2013, 4, 2), "processor_comments": "Forwarded comments", "id": "123456", "kind": "chargeback", "merchant_account_id": "abc123", "original_dispute_id": "original_dispute_id", "pre_dispute_program": "none", "reason": "fraud", "reason_code": "83", "reason_description": "Reason code 83 description", "received_date": date(2013, 4, 10), "reference_number": "123456", "reply_by_date": date(2013, 4, 17), "status": "open", "updated_at": datetime(2013, 4, 10, 10, 50, 39), "evidence": [{ "comment": None, "created_at": datetime(2013, 4, 11, 10, 50, 39), "id": "evidence1", "sent_to_processor_at": None, "url": "url_of_file_evidence", },{ "comment": "text evidence", "created_at": datetime(2013, 4, 11, 10, 50, 39), "id": "evidence2", "sent_to_processor_at": "2009-04-11", "url": None, }], "status_history": [{ "disbursement_date": "2013-04-11", "effective_date": "2013-04-10", "status": "open", "timestamp": datetime(2013, 4, 10, 10, 50, 39), }], "transaction": { "id": "transaction_id", "amount": "100.00", "created_at": datetime(2013, 3, 19, 10, 50, 39), "installment_count": None, "order_id": None, "purchase_order_number": "po", "payment_instrument_subtype": "Visa", }, "paypal_messages": [{ "message": "message", "sender": "seller", "sent_at": datetime(2013, 4, 10, 10, 50, 39), }], # NEXT_MAJOR_VERSION remove deprecated evidence_submittable # DEPRECATED The evidence_submittable attribute is deprecated "evidence_submittable": True, } def test_legacy_constructor(self): dispute = Dispute(dict(self.legacy_attributes)) self.assertEqual(dispute.id, "123456") self.assertEqual(dispute.amount, Decimal("100.00")) self.assertEqual(dispute.currency_iso_code, "USD") self.assertEqual(dispute.reason, Dispute.Reason.Fraud) self.assertEqual(dispute.status, Dispute.Status.Open) self.assertEqual(dispute.transaction_details.id, "transaction_id") self.assertEqual(dispute.transaction_details.amount, Decimal("100.00")) self.assertEqual(dispute.date_opened, date(2013, 4, 1)) self.assertEqual(dispute.date_won, date(2013, 4, 2)) self.assertEqual(dispute.kind, Dispute.Kind.Chargeback) def test_legacy_params_with_new_attributes(self): dispute = Dispute(dict(self.attributes)) self.assertEqual(dispute.id, "123456") self.assertEqual(dispute.amount, Decimal("100.00")) self.assertEqual(dispute.currency_iso_code, "USD") self.assertEqual(dispute.reason, Dispute.Reason.Fraud) self.assertEqual(dispute.status, Dispute.Status.Open) self.assertEqual(dispute.transaction_details.id, "transaction_id") self.assertEqual(dispute.transaction_details.amount, Decimal("100.00")) self.assertEqual(dispute.date_opened, date(2013, 4, 1)) self.assertEqual(dispute.date_won, date(2013, 4, 2)) self.assertEqual(dispute.kind, Dispute.Kind.Chargeback) def test_constructor_populates_new_fields(self): attributes = dict(self.attributes) del attributes["amount"] dispute = Dispute(attributes) self.assertEqual(dispute.amount_disputed, 100.0) self.assertEqual(dispute.amount_won, 0.00) self.assertEqual(dispute.case_number, "CB123456") # NEXT_MAJOR_VERSION Remove this assertion when chargeback_protection_level is removed from the SDK self.assertEqual(dispute.chargeback_protection_level, "effortless") self.assertEqual(dispute.protection_level, braintree.Dispute.ProtectionLevel.EffortlessCBP) self.assertEqual(dispute.created_at, datetime(2013, 4, 10, 10, 50, 39)) self.assertEqual(dispute.forwarded_comments, "Forwarded comments") self.assertEqual(dispute.processor_comments, "Forwarded comments") self.assertEqual(dispute.merchant_account_id, "abc123") self.assertEqual(dispute.original_dispute_id, "original_dispute_id") self.assertEqual(dispute.pre_dispute_program, Dispute.PreDisputeProgram.NONE) self.assertEqual(dispute.reason_code, "83") self.assertEqual(dispute.reason_description, "Reason code 83 description") self.assertEqual(dispute.reference_number, "123456") self.assertEqual(dispute.updated_at, datetime(2013, 4, 10, 10, 50, 39)) self.assertIsNone(dispute.evidence[0].comment) self.assertEqual(dispute.evidence[0].created_at, datetime(2013, 4, 11, 10, 50, 39)) self.assertEqual(dispute.evidence[0].id, "evidence1") self.assertIsNone(dispute.evidence[0].sent_to_processor_at) self.assertEqual(dispute.evidence[0].url, "url_of_file_evidence") self.assertEqual(dispute.evidence[1].comment, "text evidence") self.assertEqual(dispute.evidence[1].created_at, datetime(2013, 4, 11, 10, 50, 39)) self.assertEqual(dispute.evidence[1].id, "evidence2") self.assertEqual(dispute.evidence[1].sent_to_processor_at, "2009-04-11") self.assertIsNone(dispute.evidence[1].url) self.assertEqual(dispute.paypal_messages[0].message, "message") self.assertEqual(dispute.paypal_messages[0].sender, "seller") self.assertEqual(dispute.paypal_messages[0].sent_at, datetime(2013, 4, 10, 10, 50, 39)) self.assertEqual(dispute.status_history[0].disbursement_date, "2013-04-11") self.assertEqual(dispute.status_history[0].effective_date, "2013-04-10") self.assertEqual(dispute.status_history[0].status, "open") self.assertEqual(dispute.status_history[0].timestamp, datetime(2013, 4, 10, 10, 50, 39)) # NEXT_MAJOR_VERSION remove deprecated evidence_submittable # DEPRECATED The evidence_submittable attribute is deprecated self.assertEqual(dispute.evidence_submittable, True) def test_constructor_populates_standard_cbp_level(self): attributes = dict(self.attributes) del attributes["amount"] attributes["chargeback_protection_level"] = "standard" dispute = Dispute(attributes) # NEXT_MAJOR_VERSION Remove this assertion when chargeback_protection_level is removed from the SDK self.assertEqual(dispute.chargeback_protection_level, braintree.Dispute.ChargebackProtectionLevel.Standard) self.assertEqual(dispute.protection_level, braintree.Dispute.ProtectionLevel.StandardCBP) def test_constructor_populates_none_cbp_level(self): attributes = dict(self.attributes) del attributes["amount"] attributes["chargeback_protection_level"] = None dispute = Dispute(attributes) # NEXT_MAJOR_VERSION Remove this assertion when chargeback_protection_level is removed from the SDK self.assertEqual(dispute.chargeback_protection_level, None) self.assertEqual(dispute.protection_level, braintree.Dispute.ProtectionLevel.NoProtection) def test_constructor_populates_empty_cbp_level(self): attributes = dict(self.attributes) del attributes["amount"] attributes["chargeback_protection_level"] = "" dispute = Dispute(attributes) # NEXT_MAJOR_VERSION Remove this assertion when chargeback_protection_level is removed from the SDK self.assertEqual(dispute.chargeback_protection_level, "") self.assertEqual(dispute.protection_level, braintree.Dispute.ProtectionLevel.NoProtection) def test_constructor_populates_not_protected_cbp_level(self): attributes = dict(self.attributes) del attributes["amount"] attributes["chargeback_protection_level"] = "not_protected" dispute = Dispute(attributes) # NEXT_MAJOR_VERSION Remove this assertion when chargeback_protection_level is removed from the SDK self.assertEqual(dispute.chargeback_protection_level, braintree.Dispute.ChargebackProtectionLevel.NotProtected) self.assertEqual(dispute.protection_level, braintree.Dispute.ProtectionLevel.NoProtection) def test_constructor_handles_none_fields(self): attributes = dict(self.attributes) attributes.update({ "amount": None, "date_opened": None, "date_won": None, "evidence": None, "paypal_messages": None, "reply_by_date": None, "status_history": None }) dispute = Dispute(attributes) self.assertIsNone(dispute.amount) self.assertIsNone(dispute.date_opened) self.assertIsNone(dispute.date_won) self.assertIsNone(dispute.evidence) self.assertIsNone(dispute.paypal_messages) self.assertIsNone(dispute.reply_by_date) self.assertIsNone(dispute.status_history) def test_constructor_populates_transaction(self): dispute = Dispute(dict(self.attributes)) self.assertEqual(dispute.transaction.id, "transaction_id") self.assertEqual(dispute.transaction.amount, Decimal("100.00")) self.assertEqual(dispute.transaction.created_at, datetime(2013, 3, 19, 10, 50, 39)) self.assertIsNone(dispute.transaction.installment_count) self.assertIsNone(dispute.transaction.order_id) self.assertEqual(dispute.transaction.purchase_order_number, "po") self.assertEqual(dispute.transaction.payment_instrument_subtype, "Visa") def test_accept_none_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "dispute with id None not found"): Dispute.accept(None) def test_accept_empty_id_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "dispute with id ' ' not found"): Dispute.accept(" ") def test_add_text_evidence_empty_id_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "dispute_id cannot be blank"): Dispute.add_text_evidence(" ", "evidence") def test_add_text_evidence_none_id_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "dispute_id cannot be blank"): Dispute.add_text_evidence(None, "evidence") def test_add_text_evidence_empty_evidence_raises_value_exception(self): with self.assertRaisesRegex(ValueError, "content cannot be blank"): Dispute.add_text_evidence("dispute_id", " ") def test_add_text_evidence_sequence_number_not_number_evidence_raises_value_exception(self): with self.assertRaisesRegex(ValueError, "sequence_number must be an integer"): Dispute.add_text_evidence("dispute_id", { "content": "content", "sequence_number": "a" }) def test_add_text_evidence_sequence_number_number_and_letter_evidence_raises_value_exception(self): with self.assertRaisesRegex(ValueError, "sequence_number must be an integer"): Dispute.add_text_evidence("dispute_id", { "content": "content", "sequence_number": "1abc" }) def test_add_text_evidence_category_is_number_evidence_raises_value_exception(self): with self.assertRaisesRegex(ValueError, "category must be a string"): Dispute.add_text_evidence("dispute_id", { "content": "content", "category": 5 }) def test_add_file_evidence_empty_id_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "dispute with id ' ' not found"): Dispute.add_file_evidence(" ", 1) def test_add_file_evidence_none_id_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "dispute with id None not found"): Dispute.add_file_evidence(None, 1) def test_add_file_evidence_empty_evidence_raises_value_exception(self): with self.assertRaisesRegex(ValueError, "document_id cannot be blank"): Dispute.add_file_evidence("dispute_id", " ") def test_add_file_evidence_none_evidence_raises_value_exception(self): with self.assertRaisesRegex(ValueError, "document_id cannot be blank"): Dispute.add_file_evidence("dispute_id", None) def test_add_file_evidence_categorized_document_id_must_be_a_string(self): with self.assertRaisesRegex(ValueError, "category must be a string"): Dispute.add_file_evidence("dispute_id", { "document_id": "213", "category": 5 }) def test_add_file_evidence_empty_categorized_evidence_raises_value_exception(self): with self.assertRaisesRegex(ValueError, "document_id cannot be blank"): Dispute.add_file_evidence("dispute_id", { "category": "DEVICE_ID" }) def test_finalize_none_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "dispute with id None not found"): Dispute.finalize(None) def test_finalize_empty_id_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "dispute with id ' ' not found"): Dispute.finalize(" ") def test_finding_none_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "dispute with id None not found"): Dispute.find(None) def test_finding_empty_id_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "dispute with id ' ' not found"): Dispute.find(" ") def test_remove_evidence_empty_dispute_id_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "evidence with id 'evidence' for dispute with id ' ' not found"): Dispute.remove_evidence(" ", "evidence") def test_remove_evidence_none_dispute_id_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "evidence with id 'evidence' for dispute with id None not found"): Dispute.remove_evidence(None, "evidence") def test_remove_evidence_evidence_none_id_raises_not_found_exception(self): with self.assertRaisesRegex(NotFoundError, "evidence with id None for dispute with id 'dispute_id' not found"): Dispute.remove_evidence("dispute_id", None) def test_remove_evidence_empty_evidence_id_raises_value_exception(self): with self.assertRaisesRegex(NotFoundError, "evidence with id ' ' for dispute with id 'dispute_id' not found"): Dispute.remove_evidence("dispute_id", " ") braintree_python-4.31.0/tests/unit/test_document_upload.py000066400000000000000000000004121471021343500240640ustar00rootroot00000000000000from tests.test_helper import * class TestDocumentUpload(unittest.TestCase): def test_create_raises_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): DocumentUpload.create({"bad_key": "value"}) braintree_python-4.31.0/tests/unit/test_environment.py000066400000000000000000000043671471021343500232630ustar00rootroot00000000000000from tests.test_helper import * class TestEnvironment(unittest.TestCase): def test_server_and_port_for_development(self): port = os.getenv("GATEWAY_PORT") or "3000" self.assertEqual("localhost:" + port, Environment.Development.server_and_port) def test_base_url(self): self.assertEqual("https://api.sandbox.braintreegateway.com:443", Environment.Sandbox.base_url) self.assertEqual("https://api.braintreegateway.com:443", Environment.Production.base_url) def test_server_and_port_for_sandbox(self): self.assertEqual("api.sandbox.braintreegateway.com:443", Environment.Sandbox.server_and_port) def test_server_and_port_for_production(self): self.assertEqual("api.braintreegateway.com:443", Environment.Production.server_and_port) def test_server_for_development(self): self.assertEqual("localhost", Environment.Development.server) def test_server_for_sandbox(self): self.assertEqual("api.sandbox.braintreegateway.com", Environment.Sandbox.server) def test_server_for_production(self): self.assertEqual("api.braintreegateway.com", Environment.Production.server) def test_port_for_development(self): port = os.getenv("GATEWAY_PORT") or "3000" port = int(port) self.assertEqual(port, Environment.Development.port) def test_port_for_sandbox(self): self.assertEqual(443, Environment.Sandbox.port) def test_port_for_production(self): self.assertEqual(443, Environment.Production.port) def test_is_ssl_for_development(self): self.assertFalse(Environment.Development.is_ssl) def test_is_ssl_for_sandbox(self): self.assertTrue(Environment.Sandbox.is_ssl) def test_is_ssl_for_production(self): self.assertTrue(Environment.Production.is_ssl) def test_protocol_for_development(self): self.assertEqual("http://", Environment.Development.protocol) def test_protocol_for_sandbox(self): self.assertEqual("https://", Environment.Sandbox.protocol) def test_protocol_for_production(self): self.assertEqual("https://", Environment.Production.protocol) def test_ssl_certificate_for_development(self): self.assertEqual(None, Environment.Development.ssl_certificate) braintree_python-4.31.0/tests/unit/test_error_result.py000066400000000000000000000031251471021343500234350ustar00rootroot00000000000000from tests.test_helper import * class TestErrorResult(unittest.TestCase): def test_it_initializes_params_and_errors(self): errors = { "scope": { "errors": [{"code": 123, "message": "something is invalid", "attribute": "something"}] } } result = ErrorResult("gateway", {"errors": errors, "params": "params", "message": "brief description"}) self.assertFalse(result.is_success) self.assertEqual("params", result.params) self.assertEqual(1, result.errors.size) self.assertEqual("something is invalid", result.errors.for_object("scope")[0].message) self.assertEqual("something", result.errors.for_object("scope")[0].attribute) self.assertEqual(123, result.errors.for_object("scope")[0].code) def test_it_ignores_other_params(self): errors = { "scope": { "errors": [{"code": 123, "message": "something is invalid", "attribute": "something"}] } } result = ErrorResult("gateway", {"errors": errors, "params": "params", "message": "brief description", "other": "stuff"}) self.assertFalse(result.is_success) def test_transaction_is_none_if_not_set(self): result = ErrorResult("gateway", {"errors": {}, "params": {}, "message": "brief description"}) self.assertTrue(result.transaction is None) def test_verification_is_none_if_not_set(self): result = ErrorResult("gateway", {"errors": {}, "params": {}, "message": "brief description"}) self.assertTrue(result.credit_card_verification is None) braintree_python-4.31.0/tests/unit/test_errors.py000066400000000000000000000043001471021343500222160ustar00rootroot00000000000000from tests.test_helper import * class TestErrors(unittest.TestCase): def test_errors_for_the_given_scope(self): errors = Errors({"level1": {"errors": [{"code": "code1", "attribute": "attr", "message": "message"}]}}) self.assertEqual(1, errors.for_object("level1").size) self.assertEqual(1, len(errors.for_object("level1"))) def test_for_object_returns_empty_errors_collection_if_no_errors_at_given_scope(self): errors = Errors({"level1": {"errors": [{"code": "code1", "attribute": "attr", "message": "message"}]}}) self.assertEqual(0, errors.for_object("no_errors_here").size) self.assertEqual(0, len(errors.for_object("no_errors_here"))) def test_size_returns_number_of_errors_at_first_level_if_only_one_level_exists(self): test_hash = { "level1": {"errors": [{"code": "code1", "attribute": "attr", "message": "message"}]} } self.assertEqual(1, Errors(test_hash).size) self.assertEqual(1, len(Errors(test_hash))) def test_size_returns_number_of_errors_at_all_levels(self): test_hash = { "level1": { "errors": [{"code": "code1", "attribute": "attr", "message": "message"}], "level2": { "errors": [ {"code": "code2", "attribute": "attr", "message": "message"}, {"code": "code3", "attribute": "attr", "message": "message"} ] } } } self.assertEqual(3, Errors(test_hash).size) self.assertEqual(3, len(Errors(test_hash))) def test_deep_errors_returns_all_errors(self): test_hash = { "level1": { "errors": [{"code": "code1", "attribute": "attr", "message": "message"}], "level2": { "errors": [ {"code": "code2", "attribute": "attr", "message": "message"}, {"code": "code3", "attribute": "attr", "message": "message"} ] } } } errors = Errors(test_hash).deep_errors self.assertEqual(["code1", "code2", "code3"], [error.code for error in errors]) braintree_python-4.31.0/tests/unit/test_europe_bank_account.py000066400000000000000000000004261471021343500247150ustar00rootroot00000000000000from tests.test_helper import * class TestEuropeBankAccount(unittest.TestCase): def test_mandate_type_constants(self): self.assertEqual("business", EuropeBankAccount.MandateType.Business) self.assertEqual("consumer", EuropeBankAccount.MandateType.Consumer) braintree_python-4.31.0/tests/unit/test_exchange_rate_quote_gateway.py000066400000000000000000000102251471021343500264400ustar00rootroot00000000000000from braintree.exchange_rate_quote_gateway import ExchangeRateQuoteGateway from braintree.exchange_rate_quote_request import ExchangeRateQuoteRequest from tests.test_helper import * from unittest.mock import Mock class TestExchangeRateQuoteGateway(unittest.TestCase): @staticmethod def get_gateway(): config = Configuration("development", "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key") return BraintreeGateway(config) def test_generate_success(self): attribute1 = {"base_currency":"USD", "quote_currency":"EUR", "base_amount":"12.19", "markup":"1.89"} request = ExchangeRateQuoteRequest().add_exchange_rate_quote_input(attribute1).done() raw_response = """ { "data": { "generateExchangeRateQuote": { "quotes": [ { "id": "ZXhjaGFuZ2VyYXRlcXVvdGVfMDEyM0FCQw", "baseAmount": { "value": "12.19", "currencyCode": "USD" }, "quoteAmount": { "value": "12.16", "currencyCode": "EUR" }, "exchangeRate": "0.997316360864", "expiresAt": "2021-06-16T02:00:00.000000Z", "refreshesAt": "2021-06-16T00:00:00.000000Z" } ] } }, "extensions": { "requestId": "5ef2e69a-fb0e-4d71-82a3-ea59722ac64d" } } """ response = json.loads(raw_response) self.graphql_client = self.get_gateway().graphql_client self.graphql_client.query = Mock(return_value=response) exchange_rate_quote_gateway = ExchangeRateQuoteGateway(self.get_gateway(),self.graphql_client) result = exchange_rate_quote_gateway.generate(request) quotes = result.exchange_rate_quote_payload.get_quotes() self.assertIsNotNone(quotes) self.assertEqual(1,len(quotes)) quote1 = quotes[0] self.assertEqual("12.19", str(quote1.base_amount.value)) self.assertEqual("USD", quote1.base_amount.currency_code) self.assertEqual("12.16", str(quote1.quote_amount.value)) self.assertEqual("EUR", quote1.quote_amount.currency_code) self.assertEqual("0.997316360864", quote1.exchange_rate) self.assertEqual("2021-06-16T02:00:00.000000Z", quote1.expires_at) self.assertEqual("2021-06-16T00:00:00.000000Z", quote1.refreshes_at) self.assertEqual("ZXhjaGFuZ2VyYXRlcXVvdGVfMDEyM0FCQw", quote1.id) def test_generate_error(self): attribute1 = {"base_currency":"USD"} request = ExchangeRateQuoteRequest().add_exchange_rate_quote_input(attribute1).done() raw_response = """ { "errors": [ { "message": "Field 'quoteCurrency' of variable 'exchangeRateQuoteRequest' has coerced Null value for NonNull type 'CurrencyCodeAlpha!'", "locations": [ { "line": 1, "column": 11 } ] } ], "extensions": { "requestId": "96c023c9-0192-4008-8f28-25a7f8714bab" } } """ response = json.loads(raw_response) self.graphql_client = self.get_gateway().graphql_client self.graphql_client.query = Mock(return_value=response) exchange_rate_quote_gateway = ExchangeRateQuoteGateway(self.get_gateway(),self.graphql_client) result = exchange_rate_quote_gateway.generate(request) self.assertTrue("'quoteCurrency'" in result.message)braintree_python-4.31.0/tests/unit/test_exchange_rate_quote_input.py000066400000000000000000000027671471021343500261520ustar00rootroot00000000000000from braintree.exchange_rate_quote_request import ExchangeRateQuoteInput from tests.test_helper import * class TestExchangeRateQuoteInput(unittest.TestCase): def test_to_graphql_variables(self): attributes = {"base_currency":"USD", "quote_currency":"EUR", "base_amount":"10.15", "markup":"5.00"} input = ExchangeRateQuoteInput(None,attributes) map = input.to_graphql_variables() self.assertEqual(map.get("baseCurrency"), "USD") self.assertEqual(map.get("quoteCurrency"), "EUR") self.assertEqual(map.get("baseAmount"), "10.15") self.assertEqual(map.get("markup"), "5.00") def test_to_graphql_variables_without_markup_and_base_amount(self): attributes = {"base_currency":"USD", "quote_currency":"CAD"} input = ExchangeRateQuoteInput(None,attributes) map = input.to_graphql_variables() self.assertEqual(map.get("baseCurrency"), "USD") self.assertEqual(map.get("quoteCurrency"), "CAD") self.assertIsNone(map.get("baseAmount")) self.assertIsNone(map.get("markup")) def test_to_graphql_variables_with_all_empty_fields(self): input = ExchangeRateQuoteInput(None, None) map = input.to_graphql_variables() self.assertIsNone(map.get("baseCurrency")) self.assertIsNone(map.get("quoteCurrency")) self.assertIsNone(map.get("baseAmount")) self.assertIsNone(map.get("markup"))braintree_python-4.31.0/tests/unit/test_exchange_rate_quote_request.py000066400000000000000000000052221471021343500264700ustar00rootroot00000000000000from braintree.exchange_rate_quote_request import ExchangeRateQuoteRequest from tests.test_helper import * class TestExchangeRateQuoteRequest(unittest.TestCase): def test_to_graphql_variables(self): attribute1 = {"base_currency":"USD", "quote_currency":"EUR", "base_amount":"5.00", "markup":"3.00"} attribute2 = {"base_currency":"EUR", "quote_currency":"CAD", "base_amount":"15.00", "markup":"2.64"} request = ExchangeRateQuoteRequest().add_exchange_rate_quote_input( attribute1).done().add_exchange_rate_quote_input(attribute2).done() request_map = request.to_graphql_variables().get("exchangeRateQuoteRequest") self.assertIsNotNone(request_map) quotes = request_map.get("quotes") self.assertIsNotNone(quotes) self.assertEqual(2,len(quotes)) quote1 = quotes[0] self.assertEqual("USD", quote1.get("baseCurrency")) self.assertEqual("EUR", quote1.get("quoteCurrency")) self.assertEqual("5.00", quote1.get("baseAmount")) self.assertEqual("3.00", quote1.get("markup")) quote2 = quotes[1] self.assertEqual("EUR", quote2.get("baseCurrency")) self.assertEqual("CAD", quote2.get("quoteCurrency")) self.assertEqual("15.00", quote2.get("baseAmount")) self.assertEqual("2.64", quote2.get("markup")) def test_to_graphql_variables_with_missing_fields(self): attribute1 = {"base_currency":"USD", "quote_currency":"EUR", "base_amount":"5.00"} attribute2 = {"base_currency":"EUR", "quote_currency":"CAD"} request = ExchangeRateQuoteRequest().add_exchange_rate_quote_input(attribute1 ).done().add_exchange_rate_quote_input(attribute2).done() request_map = request.to_graphql_variables().get("exchangeRateQuoteRequest") self.assertIsNotNone(request_map) quotes = request_map.get("quotes") self.assertIsNotNone(quotes) self.assertEqual(2,len(quotes)) quote1 = quotes[0] self.assertEqual("USD", quote1.get("baseCurrency")) self.assertEqual("EUR", quote1.get("quoteCurrency")) self.assertEqual("5.00", quote1.get("baseAmount")) self.assertIsNone(quote1.get("markup")) quote2 = quotes[1] self.assertEqual("EUR", quote2.get("baseCurrency")) self.assertEqual("CAD", quote2.get("quoteCurrency")) self.assertIsNone(quote2.get("baseAmount")) self.assertIsNone(quote2.get("markup"))braintree_python-4.31.0/tests/unit/test_exports.py000066400000000000000000000077371471021343500224270ustar00rootroot00000000000000from tests.test_helper import * import braintree class TestExports(unittest.TestCase): def test_exports_properties(self): self.assertNotEqual(braintree.AchMandate, None) self.assertNotEqual(braintree.AddOn, None) self.assertNotEqual(braintree.AddOnGateway, None) self.assertNotEqual(braintree.Address, None) self.assertNotEqual(braintree.AddressGateway, None) self.assertNotEqual(braintree.AmexExpressCheckoutCard, None) self.assertNotEqual(braintree.AndroidPayCard, None) self.assertNotEqual(braintree.ApplePayCard, None) self.assertNotEqual(braintree.BraintreeGateway, None) self.assertNotEqual(braintree.ClientToken, None) self.assertNotEqual(braintree.Configuration, None) self.assertNotEqual(braintree.CredentialsParser, None) self.assertNotEqual(braintree.CreditCard, None) self.assertNotEqual(braintree.CreditCardGateway, None) self.assertNotEqual(braintree.CreditCardVerification, None) self.assertNotEqual(braintree.CreditCardVerificationSearch, None) self.assertNotEqual(braintree.Customer, None) self.assertNotEqual(braintree.CustomerGateway, None) self.assertNotEqual(braintree.CustomerSearch, None) self.assertNotEqual(braintree.Descriptor, None) self.assertNotEqual(braintree.Disbursement, None) self.assertNotEqual(braintree.Discount, None) self.assertNotEqual(braintree.DiscountGateway, None) self.assertNotEqual(braintree.Environment, None) self.assertNotEqual(braintree.ErrorCodes, None) self.assertNotEqual(braintree.ErrorResult, None) self.assertNotEqual(braintree.Errors, None) self.assertNotEqual(braintree.EuropeBankAccount, None) self.assertNotEqual(braintree.Merchant, None) self.assertNotEqual(braintree.MerchantAccount, None) self.assertNotEqual(braintree.MerchantAccountGateway, None) self.assertNotEqual(braintree.PartnerMerchant, None) self.assertNotEqual(braintree.PaymentInstrumentType, None) self.assertNotEqual(braintree.PaymentMethod, None) self.assertNotEqual(braintree.PaymentMethodNonce, None) self.assertNotEqual(braintree.PayPalAccount, None) self.assertNotEqual(braintree.Plan, None) self.assertNotEqual(braintree.PlanGateway, None) self.assertNotEqual(braintree.ResourceCollection, None) self.assertNotEqual(braintree.RiskData, None) self.assertNotEqual(braintree.Search, None) self.assertNotEqual(braintree.SettlementBatchSummary, None) self.assertNotEqual(braintree.SignatureService, None) self.assertNotEqual(braintree.StatusEvent, None) self.assertNotEqual(braintree.Subscription, None) self.assertNotEqual(braintree.SubscriptionGateway, None) self.assertNotEqual(braintree.SubscriptionSearch, None) self.assertNotEqual(braintree.SubscriptionStatusEvent, None) self.assertNotEqual(braintree.SuccessfulResult, None) self.assertNotEqual(braintree.TestingGateway, None) self.assertNotEqual(braintree.ThreeDSecureInfo, None) self.assertNotEqual(braintree.Transaction, None) self.assertNotEqual(braintree.TransactionAmounts, None) self.assertNotEqual(braintree.TransactionDetails, None) self.assertNotEqual(braintree.TransactionGateway, None) self.assertNotEqual(braintree.TransactionSearch, None) self.assertNotEqual(braintree.UnknownPaymentMethod, None) self.assertNotEqual(braintree.UsBankAccount, None) self.assertNotEqual(braintree.ValidationErrorCollection, None) self.assertNotEqual(braintree.VenmoAccount, None) self.assertNotEqual(braintree.Version, None) self.assertNotEqual(braintree.WebhookNotification, None) self.assertNotEqual(braintree.WebhookNotificationGateway, None) self.assertNotEqual(braintree.WebhookTesting, None) self.assertNotEqual(braintree.WebhookTestingGateway, None) braintree_python-4.31.0/tests/unit/test_graphql_client.py000066400000000000000000000047111471021343500237040ustar00rootroot00000000000000from tests.test_helper import * class TestGraphQLClient(unittest.TestCase): def test_raise_exception_from_status_service_unavailable(self): response = { "errors": [ { "message": "error message", "extensions": { "errorClass": "SERVICE_AVAILABILITY" } } ] } with self.assertRaises(ServiceUnavailableError): GraphQLClient.raise_exception_for_graphql_error(response) def test_raise_exception_from_status_for_upgrade_required(self): response = { "errors": [ { "message": "error message", "extensions": { "errorClass": "UNSUPPORTED_CLIENT" } } ] } with self.assertRaises(UpgradeRequiredError): GraphQLClient.raise_exception_for_graphql_error(response) def test_raise_exception_from_too_many_requests(self): response = { "errors": [ { "message": "error message", "extensions": { "errorClass": "RESOURCE_LIMIT" } } ] } with self.assertRaises(TooManyRequestsError): GraphQLClient.raise_exception_for_graphql_error(response) def test_does_not_raise_exception_from_validation_error(self): response = { "errors": [ { "message": "error message", "extensions": { "errorClass": "VALIDATION" } } ] } GraphQLClient.raise_exception_for_graphql_error(response) def test_raise_exception_from_validation_error_and_legitimate_error(self): response = { "errors": [ { "message": "error message", "extensions": { "errorClass": "VALIDATION" } }, { "message": "error message 2", "extensions": { "errorClass": "INTERNAL" } } ] } with self.assertRaises(ServerError): GraphQLClient.raise_exception_for_graphql_error(response) braintree_python-4.31.0/tests/unit/test_http.py000066400000000000000000000157521471021343500216760ustar00rootroot00000000000000import traceback from tests.test_helper import * from braintree.exceptions.http.timeout_error import * from braintree.attribute_getter import AttributeGetter from unittest.mock import patch class TestHttp(unittest.TestCase): def test_raise_exception_from_request_timeout(self): with self.assertRaises(RequestTimeoutError): Http.raise_exception_from_status(408) def test_raise_exception_from_status_for_upgrade_required(self): with self.assertRaises(UpgradeRequiredError): Http.raise_exception_from_status(426) def test_raise_exception_from_too_many_requests(self): with self.assertRaises(TooManyRequestsError): Http.raise_exception_from_status(429) def test_raise_exception_from_service_unavailable(self): with self.assertRaises(ServiceUnavailableError): Http.raise_exception_from_status(503) def test_raise_exception_from_gateway_timeout(self): with self.assertRaises(GatewayTimeoutError): Http.raise_exception_from_status(504) def test_header_includes_gzip_accept_encoding(self): config = AttributeGetter({ "base_url": (lambda: ""), "has_access_token": (lambda: False), "has_client_credentials": (lambda: False), "public_key": "", "private_key": ""}) headers = Http(config, "fake_environment")._Http__headers(Http.ContentType.Xml) self.assertTrue('Accept-Encoding' in headers) self.assertEqual('gzip', headers["Accept-Encoding"]) def test_backtrace_preserved_when_not_wrapping_exceptions(self): class Error(Exception): pass def raise_error(*_): raise Error http_strategy = AttributeGetter({"http_do": raise_error}) config = AttributeGetter({ "base_url": (lambda: ""), "has_access_token": (lambda: False), "has_client_credentials": (lambda: False), "http_strategy": (lambda: http_strategy), "public_key": "", "private_key": "", "wrap_http_exceptions": False}) try: Http(config, "fake_environment").post("/example/path/to/reach") except Error: _, _, tb = sys.exc_info() self.assertEqual('raise_error', traceback.extract_tb(tb)[-1][2]) def test_request_body_returns_string_for_post(self): def test_http_do_strategy(http_verb, path, headers, request_body): self.assertTrue(isinstance(request_body, str)) self.assertEqual("post", request_body) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.post("/some_path", {"method": "post"}) def test_request_body_returns_string_for_delete(self): def test_http_do_strategy(http_verb, path, headers, request_body): self.assertTrue(isinstance(request_body, str)) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.delete("/some_path") def test_request_body_returns_string_for_get(self): def test_http_do_strategy(http_verb, path, headers, request_body): self.assertTrue(isinstance(request_body, str)) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.get("/some_path") def test_request_body_returns_string_for_put(self): def test_http_do_strategy(http_verb, path, headers, request_body): self.assertTrue(isinstance(request_body, str)) self.assertEqual("put", request_body) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.put("/some_path", {"method": "put"}) def test_request_body_returns_string_for_post_multipart_when_no_files(self): params = {"method": "post_multipart"} def test_http_do_strategy(http_verb, path, headers, request_body): self.assertEqual(params, request_body) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.post_multipart("/some_path", None, params) def test_request_body_returns_tuple_for_post_multipart_when_files(self): params = {"method": "post_multipart"} def test_http_do_strategy(http_verb, path, headers, request_body): self.assertEqual(params, request_body[0]) self.assertEqual("files", request_body[1]) return (200, "") http = self.setup_http_strategy(test_http_do_strategy) http.post_multipart("/some_path", "files", params) def setup_http_strategy(self, http_do): config = AttributeGetter({ "base_url": (lambda: ""), "has_access_token": (lambda: False), "has_client_credentials": (lambda: False), "http_strategy": (lambda: AttributeGetter({"http_do": http_do})), "public_key": "", "private_key": "", "wrap_http_exceptions": False}) return Http(config, "fake_environment") def test_raise_read_timeout_error(self): def test_http_do_strategy(http_verb, path, headers, request_body): return (200, "") with self.assertRaises(ReadTimeoutError): http = self.setup_http_strategy(test_http_do_strategy) http.handle_exception(requests.exceptions.ReadTimeout()) def test_raise_connect_timeout_error(self): def test_http_do_strategy(http_verb, path, headers, request_body): return (200, "") with self.assertRaises(ConnectTimeoutError): http = self.setup_http_strategy(test_http_do_strategy) http.handle_exception(requests.exceptions.ConnectTimeout()) def test_request_urls_retain_dots(self): with patch('requests.Session.send') as send: send.return_value.status_code = 200 config = Configuration( Environment.Development, "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key", wrap_http_exceptions=True ) http = config.http() http.get("/../../customers/") prepared_request = send.call_args[0][0] request_url = prepared_request.url self.assertTrue(request_url.endswith("/../../customers/")) def test_sessions_close_after_request(self): with patch('requests.Session.send') as send, patch('requests.Session.close') as close: send.return_value.status_code = 200 config = Configuration( Environment.Development, "integration_merchant_id", public_key="integration_public_key", private_key="integration_private_key", wrap_http_exceptions=True ) http = config.http() http.get("/../../customers/") self.assertTrue(close.called) braintree_python-4.31.0/tests/unit/test_liability_shift.py000066400000000000000000000007371471021343500240730ustar00rootroot00000000000000from tests.test_helper import * from braintree import * class TestLiabilityShift(unittest.TestCase): def test_initialization_of_attributes(self): liability_shift = LiabilityShift( { "responsible_party": "paypal", "conditions": ["unauthorized"], } ) self.assertEqual("paypal", liability_shift.responsible_party) self.assertEqual(["unauthorized"], liability_shift.conditions) braintree_python-4.31.0/tests/unit/test_merchant_account.py000066400000000000000000000055361471021343500242330ustar00rootroot00000000000000from tests.test_helper import * class TestMerchantAccount(unittest.TestCase): def test_create_new_merchant_account_with_all_params(self): params = { "id": "sub_merchant_account", "status": "active", "master_merchant_account": { "id": "master_merchant_account", "status": "active" }, "individual": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "date_of_birth": "1970-01-01", "phone": "3125551234", "ssn_last_4": "6789", "address": { "street_address": "123 Fake St", "locality": "Chicago", "region": "IL", "postal_code": "60622", } }, "business": { "dba_name": "James's Bloggs", "tax_id": "123456789", }, "funding": { "account_number_last_4": "8798", "routing_number": "071000013", "descriptor": "Joes Bloggs MI", } } merchant_account = MerchantAccount(None, params) self.assertEqual(merchant_account.status, "active") self.assertEqual(merchant_account.id, "sub_merchant_account") self.assertEqual(merchant_account.master_merchant_account.id, "master_merchant_account") self.assertEqual(merchant_account.master_merchant_account.status, "active") self.assertEqual(merchant_account.individual_details.first_name, "John") self.assertEqual(merchant_account.individual_details.last_name, "Doe") self.assertEqual(merchant_account.individual_details.email, "john.doe@example.com") self.assertEqual(merchant_account.individual_details.date_of_birth, "1970-01-01") self.assertEqual(merchant_account.individual_details.phone, "3125551234") self.assertEqual(merchant_account.individual_details.ssn_last_4, "6789") self.assertEqual(merchant_account.individual_details.address_details.street_address, "123 Fake St") self.assertEqual(merchant_account.individual_details.address_details.locality, "Chicago") self.assertEqual(merchant_account.individual_details.address_details.region, "IL") self.assertEqual(merchant_account.individual_details.address_details.postal_code, "60622") self.assertEqual(merchant_account.business_details.dba_name, "James's Bloggs") self.assertEqual(merchant_account.business_details.tax_id, "123456789") self.assertEqual(merchant_account.funding_details.account_number_last_4, "8798") self.assertEqual(merchant_account.funding_details.routing_number, "071000013") self.assertEqual(merchant_account.funding_details.descriptor, "Joes Bloggs MI") braintree_python-4.31.0/tests/unit/test_meta_checkout_card.py000066400000000000000000000034771471021343500245240ustar00rootroot00000000000000from tests.test_helper import * from braintree.meta_checkout_card import MetaCheckoutCard class TestMetaCheckoutCard(unittest.TestCase): def test_initialization(self): card = MetaCheckoutCard(None, { "bin": "abc1234", "card_type": "Visa", "cardholder_name": "John Doe", "container_id": "a-container-id", "expiration_month": "05", "expiration_year": "2024", "is_network_tokenized": False, "last_4": "5678" }) self.assertEqual(card.bin, "abc1234") self.assertEqual(card.card_type, "Visa") self.assertEqual(card.cardholder_name, "John Doe") self.assertEqual(card.container_id, "a-container-id") self.assertEqual(card.expiration_month, "05") self.assertEqual(card.expiration_year, "2024") self.assertEqual(card.is_network_tokenized, False) self.assertEqual(card.last_4, "5678") def test_expiration_date(self): card = MetaCheckoutCard(None, { "bin": "abc123", "card_type": "Visa", "cardholder_name": "John Doe", "container_id": "a-container-id", "expiration_month": "05", "expiration_year": "2024", "is_network_tokenized": False, "last_4": "5678" }) self.assertEqual(card.expiration_date, "05/2024") def test_masked_number(self): card = MetaCheckoutCard(None, { "bin": "abc123", "card_type": "Visa", "cardholder_name": "John Doe", "container_id": "a-container-id", "expiration_month": "05", "expiration_year": "2024", "is_network_tokenized": False, "last_4": "5678" }) self.assertEqual(card.masked_number, "abc123******5678") braintree_python-4.31.0/tests/unit/test_meta_checkout_token.py000066400000000000000000000040021471021343500247140ustar00rootroot00000000000000from tests.test_helper import * from braintree.meta_checkout_card import MetaCheckoutCard class TestMetaCheckoutToken(unittest.TestCase): def test_initialization(self): card = MetaCheckoutCard(None, { "bin": "abc1234", "card_type": "Visa", "cardholder_name": "John Doe", "container_id": "a-container-id", "cryptogram": "a-cryptogram", "ecommerce_indicator": "01", "expiration_month": "05", "expiration_year": "2024", "is_network_tokenized": True, "last_4": "5678" }) self.assertEqual(card.bin, "abc1234") self.assertEqual(card.card_type, "Visa") self.assertEqual(card.cardholder_name, "John Doe") self.assertEqual(card.container_id, "a-container-id") self.assertEqual(card.cryptogram, "a-cryptogram") self.assertEqual(card.ecommerce_indicator, "01") self.assertEqual(card.expiration_month, "05") self.assertEqual(card.expiration_year, "2024") self.assertEqual(card.is_network_tokenized, True) self.assertEqual(card.last_4, "5678") def test_expiration_date(self): card = MetaCheckoutCard(None, { "bin": "abc123", "card_type": "Visa", "cardholder_name": "John Doe", "container_id": "a-container-id", "expiration_month": "05", "expiration_year": "2024", "is_network_tokenized": True, "last_4": "5678" }) self.assertEqual(card.expiration_date, "05/2024") def test_masked_number(self): card = MetaCheckoutCard(None, { "bin": "abc123", "card_type": "Visa", "cardholder_name": "John Doe", "container_id": "a-container-id", "expiration_month": "05", "expiration_year": "2024", "is_network_tokenized": True, "last_4": "5678" }) self.assertEqual(card.masked_number, "abc123******5678") braintree_python-4.31.0/tests/unit/test_oauth_access_revocation.py000066400000000000000000000004251471021343500256000ustar00rootroot00000000000000from tests.test_helper import * import datetime class TestOAuthAccessRevocation(unittest.TestCase): def test_assigns_merchant_id(self): revocation = OAuthAccessRevocation({"merchant_id": "abc123xyz"}) self.assertEqual(revocation.merchant_id, "abc123xyz") braintree_python-4.31.0/tests/unit/test_paginated_collection.py000066400000000000000000000030111471021343500250470ustar00rootroot00000000000000from tests.test_helper import * from braintree.paginated_collection import PaginatedCollection from braintree.paginated_result import PaginatedResult class TestPaginatedCollection(unittest.TestCase): def test_fetches_once_when_page_and_total_sizes_match(self): def paging_function(current_page): if current_page > 1: raise "too many pages fetched" else: return PaginatedResult(1, 1, [1]) collection = PaginatedCollection(paging_function) items = [i for i in collection.items] self.assertEqual(1, len(items)) def test_fetches_collections_less_than_one_page(self): def paging_function(current_page): if current_page > 1: raise "too many pages fetched" else: return PaginatedResult(2, 5, [1, 2]) collection = PaginatedCollection(paging_function) items = [i for i in collection.items] self.assertEqual(2, len(items)) self.assertEqual(1, items[0]) self.assertEqual(2, items[1]) def test_fetches_multiple_pages(self): def paging_function(current_page): if current_page > 2: raise "too many pages fetched" else: return PaginatedResult(2, 1, [current_page]) collection = PaginatedCollection(paging_function) items = [i for i in collection.items] self.assertEqual(2, len(items)) self.assertEqual(1, items[0]) self.assertEqual(2, items[1]) braintree_python-4.31.0/tests/unit/test_partner_merchant.py000066400000000000000000000015551471021343500242470ustar00rootroot00000000000000from 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-4.31.0/tests/unit/test_payment_method_gateway.py000066400000000000000000000171141471021343500254470ustar00rootroot00000000000000from tests.test_helper import * from braintree.payment_method_gateway import PaymentMethodGateway from unittest.mock import MagicMock class TestPaymentMethodGateway(unittest.TestCase): def test_create_signature(self): actual_signature = PaymentMethod.signature("create") expected_signature = [ "billing_address_id", "cardholder_name", "customer_id", "cvv", "device_data", "expiration_date", "expiration_month", "expiration_year", "number", "payment_method_nonce", "paypal_refresh_token", "token", "device_session_id", { "billing_address": Address.create_signature()}, { "options": [ "fail_on_duplicate_payment_method", "fail_on_duplicate_payment_method_for_customer", "make_default", "skip_advanced_fraud_checking", "us_bank_account_verification_method", "verification_account_type", "verification_add_ons", "verification_amount", "verification_merchant_account_id", "verify_card", { "adyen":[ "overwrite_brand", "selected_brand" ] }, { "paypal":[ "payee_email", "order_id", "custom_field", "description", "amount", { "shipping":[ "company", "country_code_alpha2", "country_code_alpha3", "country_code_numeric", "country_name", "customer_id", "extended_address", "first_name", {"international_phone": ["country_code", "national_number"]}, "last_name", "locality", "phone_number", "postal_code", "region", "street_address", ] }, ] }, ] }, { "three_d_secure_pass_thru": [ "cavv", "ds_transaction_id", "eci_flag", "three_d_secure_version", "xid" ] }, ] 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_data", "expiration_date", "expiration_month", "expiration_year", "number", "payment_method_nonce", "token", "venmo_sdk_payment_method_code", # NEXT_MJOR_VERSION remove venmo_sdk_payment_method_code "device_session_id", "fraud_merchant_id", { "options": [ "fail_on_duplicate_payment_method_for_customer", "make_default", "skip_advanced_fraud_checking", "us_bank_account_verification_method", "venmo_sdk_session", # NEXT_MJOR_VERSION remove venmo_sdk_session "verification_account_type", "verification_add_ons", "verification_amount", "verification_merchant_account_id", "verify_card", { "adyen":[ "overwrite_brand", "selected_brand" ] } ] }, { "billing_address" : Address.update_signature() + [{"options": ["update_existing"]}] }, { "three_d_secure_pass_thru": [ "cavv", "ds_transaction_id", "eci_flag", "three_d_secure_version", "xid" ] }, ] self.assertEqual(expected_signature, actual_signature) def test_nonce_grant_params(self): """ We validate parameters to PaymentMethod.grant properly """ payment_method_gateway = PaymentMethodGateway(BraintreeGateway(None)) options = { "include_billing_postal_code": True } with self.assertRaises(ValueError): payment_method_gateway.grant("", options) with self.assertRaises(ValueError): payment_method_gateway.grant("\t", False) with self.assertRaises(ValueError): payment_method_gateway.grant(None, True) def test_nonce_revoke_params(self): payment_method_gateway = PaymentMethodGateway(BraintreeGateway(None)) with self.assertRaises(ValueError): payment_method_gateway.revoke("") with self.assertRaises(ValueError): payment_method_gateway.revoke("\t") with self.assertRaises(ValueError): payment_method_gateway.revoke(None) def test_delete_with_revoke_all_grants_value_as_true(self): payment_method_gateway, http_mock = self.setup_payment_method_gateway_and_mock_http() payment_method_gateway.delete("some_token", {"revoke_all_grants": True}) self.assertTrue("delete('/merchants/integration_merchant_id/payment_methods/any/some_token?revoke_all_grants=true')" in str(http_mock.mock_calls)) def test_delete_with_revoke_all_grants_value_as_false(self): payment_method_gateway, http_mock = self.setup_payment_method_gateway_and_mock_http() payment_method_gateway.delete("some_token", {"revoke_all_grants": False}) self.assertTrue("delete('/merchants/integration_merchant_id/payment_methods/any/some_token?revoke_all_grants=false')" in str(http_mock.mock_calls)) def test_delete_without_revoke_all_grants(self): payment_method_gateway, http_mock = self.setup_payment_method_gateway_and_mock_http() payment_method_gateway.delete("some_token") self.assertTrue("delete('/merchants/integration_merchant_id/payment_methods/any/some_token')" in str(http_mock.mock_calls)) def test_delete_with_invalid_keys_to_raise_error(self): payment_method_gateway, http_mock = self.setup_payment_method_gateway_and_mock_http() with self.assertRaises(KeyError): payment_method_gateway.delete("some_token", {"invalid_keys": False}) def setup_payment_method_gateway_and_mock_http(self): braintree_gateway = BraintreeGateway(Configuration.instantiate()) payment_method_gateway = PaymentMethodGateway(braintree_gateway) http_mock = MagicMock(name='config.http.delete') braintree_gateway.config.http = http_mock return payment_method_gateway, http_mock braintree_python-4.31.0/tests/unit/test_payment_method_nonce.py000066400000000000000000000006031471021343500251030ustar00rootroot00000000000000from tests.test_helper import * class TestPaymentMethodNonce(unittest.TestCase): def test_finding_empty_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): PaymentMethodNonce.find(" ") def test_finding_None_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): PaymentMethodNonce.find(None) braintree_python-4.31.0/tests/unit/test_payment_method_parser.py000066400000000000000000000035011471021343500252750ustar00rootroot00000000000000from tests.test_helper import * from braintree.payment_method_parser import parse_payment_method from unittest.mock import MagicMock class TestPaymentMethodParser(unittest.TestCase): def test_parse_response_returns_a_credit_card(self): credit_card = parse_payment_method(BraintreeGateway(None), { "credit_card": {"bin": "411111", "last_4": "1111"} }) self.assertEqual(CreditCard, credit_card.__class__) self.assertEqual("411111", credit_card.bin) self.assertEqual("1111", credit_card.last_4) def test_parse_response_returns_a_paypal_account(self): paypal_account = parse_payment_method(BraintreeGateway(None), { "paypal_account": {"token": "1234", "default": False} }) self.assertEqual(PayPalAccount, paypal_account.__class__) self.assertEqual("1234", paypal_account.token) self.assertFalse(paypal_account.default) def test_parse_response_returns_a_sepa_direct_debit_account(self): sdd_account = parse_payment_method(BraintreeGateway(None), { "sepa_debit_account": {"token": "1234", "default": False} }) self.assertEqual(SepaDirectDebitAccount, sdd_account.__class__) self.assertEqual("1234", sdd_account.token) self.assertFalse(sdd_account.default) def test_parse_response_returns_an_unknown_payment_method(self): unknown_payment_method = parse_payment_method(BraintreeGateway(None), { "new_fancy_payment_method": { "token": "1234", "default": True, "other_fancy_thing": "is-shiny" } }) self.assertEqual(UnknownPaymentMethod, unknown_payment_method.__class__) self.assertEqual("1234", unknown_payment_method.token) self.assertTrue(unknown_payment_method.default) braintree_python-4.31.0/tests/unit/test_resource.py000066400000000000000000000064561471021343500225470ustar00rootroot00000000000000from 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) def test_verify_keys_escapes_brackets_in_signature(self): signature = [ {"customer": [{"custom_fields": ["__any_key__"]}]} ] params = { "customer_id": "value", } with self.assertRaises(KeyError): 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) def test_verify_keys_raises_on_bad_array_param(self): signature = [ {"customer": ["one", "two"]} ] params = { "customer": { "invalid": "foo" } } with self.assertRaises(KeyError): 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) 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 } ] } } with self.assertRaises(KeyError): Resource.verify_keys(params, signature) def test_verify_keys_allows_text(self): text_string = u"text_string" assert isinstance(text_string, TestHelper.text_type) signature = [ {"customer": [{"custom_fields": [text_string]}]} ] params = { "customer": { "custom_fields": { text_string : text_string } } } Resource.verify_keys(params, signature) def test_verify_keys_allows_raw_data(self): raw_string = str.encode("raw_string") assert isinstance(raw_string, TestHelper.raw_type) signature = [ {"customer": [{"custom_fields": [raw_string]}]} ] params = { "customer": { "custom_fields": { raw_string : raw_string } } } Resource.verify_keys(params, signature) braintree_python-4.31.0/tests/unit/test_resource_collection.py000066400000000000000000000040411471021343500247460ustar00rootroot00000000000000from tests.test_helper import * class TestResourceCollection(unittest.TestCase): collection_data = { "search_results": { "page_size": 2, "ids": ["0", "1", "2", "3", "4"] } } class TestResource: items = ["a", "b", "c", "d", "e"] @staticmethod def fetch(_, ids): return [TestResourceCollection.TestResource.items[int(resource_id)] for resource_id in ids] def test_iterating_over_contents(self): collection = ResourceCollection("some_query", self.collection_data, TestResourceCollection.TestResource.fetch) new_items = [] index = 0 for item in collection.items: self.assertEqual(TestResourceCollection.TestResource.items[index], item) new_items.append(item) index += 1 self.assertEqual(5, len(new_items)) def test_iterate_using_iterator_protocol(self): collection = ResourceCollection("some_query", self.collection_data, TestResourceCollection.TestResource.fetch) for test_elem, coll_elem in zip(self.TestResource.items, collection): self.assertEqual(test_elem, coll_elem) def test_ids_returns_array_of_ids(self): collection = ResourceCollection("some_query", self.collection_data, TestResourceCollection.TestResource.fetch) self.assertEqual(collection.ids, self.collection_data['search_results']['ids']) def test_ids_returns_array_of_empty_ids(self): empty_collection_data = { "search_results": { "page_size": 2, "ids": [] } } collection = ResourceCollection("some_query", empty_collection_data, TestResourceCollection.TestResource.fetch) self.assertEqual(collection.ids, []) def test_no_search_results(self): bad_collection_data = {} with self.assertRaisesRegex(UnexpectedError, "Unprocessable entity due to an invalid request"): ResourceCollection("some_query", bad_collection_data, TestResourceCollection.TestResource.fetch) braintree_python-4.31.0/tests/unit/test_risk_data.py000066400000000000000000000023701471021343500226500ustar00rootroot00000000000000from tests.test_helper import * from braintree import * class TestRiskData(unittest.TestCase): def test_initialization_of_attributes(self): risk_data = RiskData( { "id": "123", "decision": "Unknown", "device_data_captured": True, "fraud_service_provider": "some_fraud_provider", "transaction_risk_score": "42", "decision_reasons": ["reason"], "liability_shift": { "responsible_party": "paypal", "conditions": ["unauthorized"], } } ) self.assertEqual("123", risk_data.id) self.assertEqual("Unknown", risk_data.decision) self.assertEqual(True, risk_data.device_data_captured) self.assertEqual("some_fraud_provider", risk_data.fraud_service_provider) self.assertEqual("42", risk_data.transaction_risk_score) self.assertEqual(["reason"], risk_data.decision_reasons) self.assertEqual("paypal", risk_data.liability_shift.responsible_party) self.assertEqual(["unauthorized"], risk_data.liability_shift.conditions) braintree_python-4.31.0/tests/unit/test_samsung_pay_card.py000066400000000000000000000023431471021343500242260ustar00rootroot00000000000000from tests.test_helper import * # NEXT_MAJOR_VERSION remove this class # SamsungPay is deprecated class TestSamsungPayCard(unittest.TestCase): def test_expiration_date(self): card = SamsungPayCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual("05/2014", card.expiration_date) def test_expiration_date_no_month(self): card = SamsungPayCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual(None, card.expiration_date) def test_expiration_date_no_year(self): card = SamsungPayCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "05", "expiration_year": "", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual(None, card.expiration_date)braintree_python-4.31.0/tests/unit/test_search.py000066400000000000000000000126261471021343500221610ustar00rootroot00000000000000from tests.test_helper import * class TestSearch(unittest.TestCase): def test_text_node_is(self): node = Search.TextNodeBuilder("name") self.assertEqual({"is": "value"}, (node == "value").to_param()) def test_text_node_is_not(self): node = Search.TextNodeBuilder("name") self.assertEqual({"is_not": "value"}, (node != "value").to_param()) def test_text_node_starts_with(self): node = Search.TextNodeBuilder("name") self.assertEqual({"starts_with": "value"}, (node.starts_with("value")).to_param()) def test_text_node_ends_with(self): node = Search.TextNodeBuilder("name") self.assertEqual({"ends_with": "value"}, (node.ends_with("value")).to_param()) def test_text_node_contains(self): node = Search.TextNodeBuilder("name") self.assertEqual({"contains": "value"}, (node.contains("value")).to_param()) def test_multiple_value_node_in_list(self): node = Search.MultipleValueNodeBuilder("name") self.assertEqual(["value1", "value2"], (node.in_list(["value1", "value2"])).to_param()) def test_multiple_value_node_in_list_as_arg_list(self): node = Search.MultipleValueNodeBuilder("name") self.assertEqual(["value1", "value2"], (node.in_list("value1", "value2")).to_param()) def test_multiple_value_node_is(self): node = Search.MultipleValueNodeBuilder("name") self.assertEqual(["value1"], (node == "value1").to_param()) def test_multiple_value_node_with_value_in_whitelist(self): node = Search.MultipleValueNodeBuilder("name", ["okay"]) self.assertEqual(["okay"], (node == "okay").to_param()) def test_multiple_value_node_with_value_not_in_whitelist(self): with self.assertRaises(AttributeError): node = Search.MultipleValueNodeBuilder("name", ["okay", "also okay"]) node == "not okay" def test_multiple_value_or_text_node_is(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual({"is": "value"}, (node == "value").to_param()) def test_multiple_value_or_text_node_is_not(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual({"is_not": "value"}, (node != "value").to_param()) def test_multiple_value_or_text_node_starts_with(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual({"starts_with": "value"}, (node.starts_with("value")).to_param()) def test_multiple_value_or_text_node_ends_with(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual({"ends_with": "value"}, (node.ends_with("value")).to_param()) def test_multiple_value_or_text_node_contains(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual({"contains": "value"}, (node.contains("value")).to_param()) def test_multiple_value_or_text_node_in_list(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual(["value1", "value2"], (node.in_list(["value1", "value2"])).to_param()) def test_multiple_value_or_text_node_in_list_as_arg_list(self): node = Search.MultipleValueOrTextNodeBuilder("name") self.assertEqual(["value1", "value2"], (node.in_list("value1", "value2")).to_param()) def test_multiple_value_or_text_node_with_value_in_whitelist(self): node = Search.MultipleValueOrTextNodeBuilder("name", ["okay"]) self.assertEqual(["okay"], node.in_list("okay").to_param()) def test_multiple_value_or_text_node_with_value_not_in_whitelist(self): with self.assertRaises(AttributeError): node = Search.MultipleValueOrTextNodeBuilder("name", ["okay"]) node.in_list("not okay").to_param() def test_range_node_min_ge(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"min": "value"}, (node >= "value").to_param()) def test_range_node_min_greater_than_or_equal_to(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"min": "value"}, (node.greater_than_or_equal_to("value")).to_param()) def test_range_node_max_le(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"max": "value"}, (node <= "value").to_param()) def test_range_node_max_less_than_or_equal_to(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"max": "value"}, (node.less_than_or_equal_to("value")).to_param()) def test_range_node_between(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"min": "min_value", "max": "max_value"}, (node.between("min_value", "max_value")).to_param()) def test_range_node_is(self): node = Search.RangeNodeBuilder("name") self.assertEqual({"is": "value"}, (node == "value").to_param()) def test_key_value_node_is_eq(self): node = Search.KeyValueNodeBuilder("name") self.assertTrue((node == True).to_param()) def test_key_value_node_is_equal(self): node = Search.KeyValueNodeBuilder("name") self.assertEqual(True, (node.is_equal(True)).to_param()) def test_key_value_node_is_not_equal(self): node = Search.KeyValueNodeBuilder("name") self.assertEqual(False, (node.is_not_equal(True)).to_param()) def test_key_value_node_symbols_is_not_equal(self): node = Search.KeyValueNodeBuilder("name") self.assertEqual(False, (node != True).to_param()) braintree_python-4.31.0/tests/unit/test_sepa_direct_debit_account.py000066400000000000000000000034241471021343500260550ustar00rootroot00000000000000from tests.test_helper import * from datetime import date class TestSepaDirectDebitAccount(unittest.TestCase): def test_constructor(self): attributes = { "bank_reference_token": "a-reference-token", "created_at": date(2013, 4, 10), "customer_global_id": "a-customer-global-id", "global_id": "a-global-id", "image_url": "a-image-url", "last_4": "4321", "mandate_type": "ONE_OFF", "merchant_or_partner_customer_id": "a-mp-customer-id", "subscriptions": [{"price": "10.00"}], "updated_at": date(2013, 4, 10), "view_mandate_url": "a-view-mandate-url", } sepa_direct_debit_account = SepaDirectDebitAccount({}, attributes) self.assertEqual(sepa_direct_debit_account.bank_reference_token, "a-reference-token") self.assertEqual(sepa_direct_debit_account.created_at, date(2013, 4, 10)) self.assertEqual(sepa_direct_debit_account.customer_global_id, "a-customer-global-id") self.assertEqual(sepa_direct_debit_account.global_id, "a-global-id") self.assertEqual(sepa_direct_debit_account.image_url, "a-image-url") self.assertEqual(sepa_direct_debit_account.last_4, "4321") self.assertEqual(sepa_direct_debit_account.mandate_type, "ONE_OFF") self.assertEqual(sepa_direct_debit_account.merchant_or_partner_customer_id, "a-mp-customer-id") subscription = sepa_direct_debit_account.subscriptions[0] self.assertEqual(type(subscription), Subscription) self.assertEqual(subscription.price, Decimal("10.00")) self.assertEqual(sepa_direct_debit_account.updated_at, date(2013, 4, 10)) self.assertEqual(sepa_direct_debit_account.view_mandate_url, "a-view-mandate-url") braintree_python-4.31.0/tests/unit/test_setup.py000066400000000000000000000022301471021343500220420ustar00rootroot00000000000000from tests.test_helper import * import os class TestSetup(unittest.TestCase): def test_packages_includes_all_packages(self): with open('setup.py', 'r') as f: setup_contents = f.read() packages_line = re.findall('packages=.*', setup_contents) packages_from_setup = re.findall('"(.*?)"', str(packages_line)) packages_from_directories = ['braintree'] directories_that_dont_have_packages = ['braintree.ssl'] for dirname, dirnames, _ in os.walk('braintree'): for subdirname in dirnames: package_from_directory = re.sub('/', '.', os.path.join(dirname, subdirname)) if package_from_directory not in directories_that_dont_have_packages and subdirname != '__pycache__': packages_from_directories.append(package_from_directory) mismatch_message = "List of packages in setup.py doesn't match subdirectories of 'braintree' - " \ + "add your new directory to 'packages, or if none, `git clean -df` to remove a stale directory" self.assertEqual(sorted(packages_from_directories), sorted(packages_from_setup), mismatch_message) braintree_python-4.31.0/tests/unit/test_signature_service.py000066400000000000000000000007051471021343500244300ustar00rootroot00000000000000from tests.test_helper import * class FakeDigest(object): @staticmethod def hmac_hash(key, data): return "%s_signed_with_%s" % (data, key) class TestSignatureService(unittest.TestCase): def test_hashes_with_digest(self): signature_service = SignatureService("fake_key", FakeDigest.hmac_hash) signed = signature_service.sign({"foo": "bar"}) self.assertEqual("foo=bar_signed_with_fake_key|foo=bar", signed) braintree_python-4.31.0/tests/unit/test_subscription.py000066400000000000000000000013551471021343500234350ustar00rootroot00000000000000from tests.test_helper import * class TestSubscription(unittest.TestCase): def test_create_raises_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): Subscription.create({"bad_key": "value"}) def test_update_raises_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): Subscription.update("id", {"bad_key": "value"}) def test_finding_empty_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): Subscription.find(" ") def test_finding_None_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): Subscription.find(None) braintree_python-4.31.0/tests/unit/test_subscription_search.py000066400000000000000000000040741471021343500247630ustar00rootroot00000000000000from tests.test_helper import * class TestSubscriptionSearch(unittest.TestCase): def test_billing_cycles_remaining_is_a_range_node(self): self.assertEqual(Search.RangeNodeBuilder, type(SubscriptionSearch.billing_cycles_remaining)) def test_created_at_is_a_range_node(self): self.assertEqual(Search.RangeNodeBuilder, type(SubscriptionSearch.created_at)) def test_days_past_due_is_a_range_node(self): self.assertEqual(Search.RangeNodeBuilder, type(SubscriptionSearch.days_past_due)) def test_id_is_a_text_node(self): self.assertEqual(Search.TextNodeBuilder, type(SubscriptionSearch.id)) def test_merchant_account_id_is_a_multiple_value_node(self): self.assertEqual(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.merchant_account_id)) def test_plan_id_is_a_multiple_value_or_text_node(self): self.assertEqual(Search.MultipleValueOrTextNodeBuilder, type(SubscriptionSearch.plan_id)) def test_price_is_a_range_node(self): self.assertEqual(Search.RangeNodeBuilder, type(SubscriptionSearch.price)) def test_status_is_a_multiple_value_node(self): self.assertEqual(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.status)) def test_in_trial_period_is_multiple_value_node(self): self.assertEqual(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.in_trial_period)) def test_status_whitelist(self): SubscriptionSearch.status.in_list( Subscription.Status.Active, Subscription.Status.Canceled, Subscription.Status.Expired, Subscription.Status.PastDue ) def test_status_not_in_whitelist(self): with self.assertRaises(AttributeError): SubscriptionSearch.status.in_list( Subscription.Status.Active, Subscription.Status.Canceled, Subscription.Status.Expired, "not a status" ) def test_ids_is_a_multiple_value_node(self): self.assertEqual(Search.MultipleValueNodeBuilder, type(SubscriptionSearch.ids)) braintree_python-4.31.0/tests/unit/test_successful_result.py000066400000000000000000000004661471021343500244700ustar00rootroot00000000000000from 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-4.31.0/tests/unit/test_three_d_secure_info.py000066400000000000000000000022631471021343500247030ustar00rootroot00000000000000from tests.test_helper import * from braintree import * class TestThreeDSecureInfo(unittest.TestCase): def test_initialization_of_attributes(self): three_d_secure_info = ThreeDSecureInfo({ "enrolled": "Y", "status": "authenticate_successful", "liability_shifted": True, "liability_shift_possible": True, "cavv": "some_cavv", "xid": "some_xid", "ds_transaction_id": "some_ds_txn_id", "eci_flag": "07", "three_d_secure_version": "1.0.2", }) self.assertEqual("Y", three_d_secure_info.enrolled) self.assertEqual("authenticate_successful", three_d_secure_info.status) self.assertEqual(True, three_d_secure_info.liability_shifted) self.assertEqual(True, three_d_secure_info.liability_shift_possible) self.assertEqual("some_cavv", three_d_secure_info.cavv) self.assertEqual("some_xid", three_d_secure_info.xid) self.assertEqual("some_ds_txn_id", three_d_secure_info.ds_transaction_id) self.assertEqual("07", three_d_secure_info.eci_flag) self.assertEqual("1.0.2", three_d_secure_info.three_d_secure_version) braintree_python-4.31.0/tests/unit/test_transaction.py000066400000000000000000000366631471021343500232500ustar00rootroot00000000000000from tests.test_helper import * from braintree.test.credit_card_numbers import CreditCardNumbers from braintree.meta_checkout_card import MetaCheckoutCard from braintree.meta_checkout_token import MetaCheckoutToken from datetime import datetime from datetime import date from braintree.authorization_adjustment import AuthorizationAdjustment from unittest.mock import MagicMock class TestTransaction(unittest.TestCase): def test_clone_transaction_raises_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): Transaction.clone_transaction("an id", {"bad_key": "value"}) def test_sale_raises_exception_with_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: bad_key'"): Transaction.sale({"bad_key": "value"}) def test_sale_raises_exception_with_nested_bad_keys(self): with self.assertRaisesRegex(KeyError, "'Invalid keys: credit_card\[bad_key\]'"): Transaction.sale({"credit_card": {"bad_key": "value"}}) def test_finding_empty_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): Transaction.find(" ") def test_finding_none_raises_not_found_exception(self): with self.assertRaises(NotFoundError): Transaction.find(None) def test_constructor_includes_disbursement_information(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'order_id': '106601', 'channel': '101', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', 'disbursement_details': { 'settlement_amount': '27.00', 'settlement_currency_iso_code': 'USD', 'settlement_currency_exchange_rate': '1', 'disbursement_date': date(2013, 4, 10), 'funds_held': False } } transaction = Transaction(None, attributes) self.assertEqual(transaction.disbursement_details.settlement_amount, Decimal('27.00')) self.assertEqual(transaction.disbursement_details.settlement_currency_iso_code, 'USD') self.assertEqual(transaction.disbursement_details.settlement_currency_exchange_rate, Decimal('1')) self.assertEqual(transaction.disbursement_details.disbursement_date, date(2013, 4, 10)) self.assertEqual(transaction.disbursement_details.funds_held, False) self.assertEqual(transaction.is_disbursed, True) def test_constructor_includes_sepa_direct_debit_return_code(self): attributes = { 'amount': '27.00', 'sepa_direct_debit_return_code': 'AM04' } transaction = Transaction(None, attributes) self.assertEqual(transaction.sepa_direct_debit_return_code, 'AM04') def test_transaction_handles_nil_risk_data(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'order_id': '106601', 'channel': '101', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', } transaction = Transaction(None, attributes) self.assertEqual(transaction.risk_data, None) def test_is_disbursed_false(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'order_id': '106601', 'channel': '101', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', 'disbursement_details': { 'settlement_amount': None, 'settlement_currency_iso_code': None, 'settlement_currency_exchange_rate': None, 'disbursement_date': None, 'funds_held': None, } } transaction = Transaction(None, attributes) self.assertEqual(transaction.is_disbursed, False) def test_sale_with_skip_advanced_fraud_checking_value_as_true(self): attributes = { "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "skip_advanced_fraud_checking": True } } transaction_gateway = self.setup_transaction_gateway_and_mock_post() transaction_gateway.sale(attributes) transaction_param = transaction_gateway._post.call_args[0][1] self.assertTrue(transaction_param['transaction']['options']['skip_advanced_fraud_checking']) def test_sale_with_skip_advanced_fraud_checking_value_as_false(self): attributes = { "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "skip_advanced_fraud_checking": False } } transaction_gateway = self.setup_transaction_gateway_and_mock_post() transaction_gateway.sale(attributes) transaction_param = transaction_gateway._post.call_args[0][1] self.assertFalse(transaction_param['transaction']['options']['skip_advanced_fraud_checking']) def test_sale_without_skip_advanced_fraud_checking_value_option(self): attributes = { "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009" }, "options": { "submit_for_settlement": True } } transaction_gateway = self.setup_transaction_gateway_and_mock_post() transaction_gateway.sale(attributes) transaction_param = transaction_gateway._post.call_args[0][1] self.assertTrue('skip_advanced_fraud_checking' not in transaction_param['transaction']['options']) def test_sale_with_external_network_token_option(self): attributes = { "amount": TransactionAmounts.Authorize, "credit_card": { "number": CreditCardNumbers.Visa, "expiration_date": "05/2009", "network_tokenization_attributes": { "cryptogram": "/wAAAAAAAcb8AlGUF/1JQEkAAAA=", "ecommerce_indicator": "45310020105", "token_requestor_id" : "05" } } } transaction_gateway = self.setup_transaction_gateway_and_mock_post() transaction_gateway.sale(attributes) transaction_param = transaction_gateway._post.call_args[0][1] self.assertTrue('network_tokenization_attributes' in transaction_param['transaction']['credit_card']) self.assertEqual(transaction_param['transaction']['credit_card']['network_tokenization_attributes']['cryptogram'], "/wAAAAAAAcb8AlGUF/1JQEkAAAA=") self.assertEqual(transaction_param['transaction']['credit_card']['network_tokenization_attributes']['ecommerce_indicator'], "45310020105") self.assertEqual(transaction_param['transaction']['credit_card']['network_tokenization_attributes']['token_requestor_id'], "05") def setup_transaction_gateway_and_mock_post(self): transaction_gateway = TransactionGateway(BraintreeGateway(None)) transaction_gateway._post = MagicMock(name='config.http.post') return transaction_gateway def test_constructor_doesnt_includes_auth_adjustments(self): attributes = { 'amount': '27.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', 'tax_amount': '1.00', } transaction = Transaction(None, attributes) self.assertFalse(hasattr(transaction, 'authorization_adjustments')) def test_constructor_includes_auth_adjustments(self): attributes = { 'amount': '27.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', 'tax_amount': '1.00', 'authorization_adjustments': [{ "amount": "20.00", "timestamp": datetime(2017, 7, 12, 1, 2, 3), "success": True, "processor_response_code": "1000", "processor_response_text": "Approved", }], } transaction = Transaction(None, attributes) transaction_adjustment = transaction.authorization_adjustments[0] self.assertEqual(transaction_adjustment.amount, Decimal("20.00")) self.assertEqual(transaction_adjustment.timestamp, datetime(2017, 7, 12, 1, 2, 3)) self.assertEqual(transaction_adjustment.success, True) self.assertEqual(transaction_adjustment.processor_response_code, "1000") self.assertEqual(transaction_adjustment.processor_response_text, "Approved") def test_constructor_parses_shipments_into_packages(self): attributes = { 'amount': '27.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', 'tax_amount': '1.00', 'shipments': [ { 'id': 'id1', 'carrier': 'UPS', 'tracking_number': 'tracking_number_1', # NEXT_MAJOR_VERSION remove paypal_tracking_id 'paypal_tracking_id': 'pp_tracking_number_1', 'paypal_tracker_id': 'pp_tracker_id_1', }, { 'id': 'id2', 'carrier': 'FEDEX', 'tracking_number': 'tracking_number_2', # NEXT_MAJOR_VERSION remove paypal_tracking_id 'paypal_tracking_id': 'pp_tracking_number_2', 'paypal_tracker_id': 'pp_tracker_id_2', }, ], } transaction = Transaction(None, attributes) package_detail_1 = transaction.packages[0] self.assertEqual(package_detail_1.id, "id1") self.assertEqual(package_detail_1.carrier, "UPS") self.assertEqual(package_detail_1.tracking_number, "tracking_number_1") # NEXT_MAJOR_VERSION remove paypal_tracking_id assertions. self.assertEqual(package_detail_1.paypal_tracking_id, "pp_tracking_number_1") self.assertEqual(package_detail_1.paypal_tracker_id, "pp_tracker_id_1") package_detail_2 = transaction.packages[1] self.assertEqual(package_detail_2.id, "id2") self.assertEqual(package_detail_2.carrier, "FEDEX") self.assertEqual(package_detail_2.tracking_number, "tracking_number_2") # NEXT_MAJOR_VERSION remove paypal_tracking_id assertions. self.assertEqual(package_detail_2.paypal_tracking_id, "pp_tracking_number_2") self.assertEqual(package_detail_2.paypal_tracker_id, "pp_tracker_id_2") def test_constructor_works_with_empty_shipments_list(self): attributes = { 'amount': '27.00', 'customer_id': '4096', 'merchant_account_id': '8192', 'payment_method_token': 'sometoken', 'purchase_order_number': '20202', 'recurring': 'False', 'tax_amount': '1.00', 'shipments': [], } transaction = Transaction(None, attributes) self.assertEqual(len(transaction.packages), 0) def test_constructor_includes_network_transaction_id_and_response_code_and_response_text(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'network_transaction_id': '123456789012345', 'network_response_code': '00', 'network_response_text': 'Successful approval/completion or V.I.P. PIN verification is successful' } transaction = Transaction(None, attributes) self.assertEqual(transaction.network_transaction_id, "123456789012345") self.assertEqual(transaction.network_response_code, "00") self.assertEqual(transaction.network_response_text, "Successful approval/completion or V.I.P. PIN verification is successful") def test_constructor_includes_installment_count(self): attributes = { 'amount': '27.00', 'tax_amount': '1.00', 'installments': { 'count': 4 } } transaction = Transaction(None, attributes) self.assertEqual(transaction.installments["count"], 4) def test_gateway_rejection_reason_for_excessive_retry(self): attributes = { 'amount': '27.00', 'gateway_rejection_reason': 'excessive_retry' } transaction = Transaction(None, attributes) self.assertEqual(transaction.gateway_rejection_reason, braintree.Transaction.GatewayRejectionReason.ExcessiveRetry) def test_merchant_advice_code(self): attributes = { 'amount': TransactionAmounts.Decline, 'merchant_advice_code': "01", 'merchant_advice_code_text': "New account information available" } transaction = Transaction(None, attributes) self.assertEqual(transaction.merchant_advice_code, "01") self.assertEqual(transaction.merchant_advice_code_text, "New account information available") def test_retry_ids_and_retried_transaction_id(self): attributes = { 'amount': TransactionAmounts.Decline, 'retry_ids': ['retry_id_1','retry_id2'], 'retried_transaction_id': '12345', 'retried': True } transaction = Transaction(None, attributes) self.assertEqual(transaction.retry_ids, ['retry_id_1','retry_id2']) self.assertEqual(transaction.retried_transaction_id, "12345") self.assertTrue(transaction.retried) def test_debit_network(self): attributes = { 'amount': '27.00', 'debit_network' : CreditCard.DebitNetwork.Star } transaction = Transaction(None, attributes) self.assertEqual(transaction.debit_network, CreditCard.DebitNetwork.Star) def test_transaction_meta_checkout_card_attributes(self): attributes = { 'amount': '420', 'meta_checkout_card': {} } transaction = Transaction(None, attributes) self.assertIsInstance(transaction.meta_checkout_card_details, MetaCheckoutCard) def test_transaction_meta_checkout_token_attributes(self): attributes = { 'amount': '69', 'meta_checkout_token': {} } transaction = Transaction(None, attributes) self.assertIsInstance(transaction.meta_checkout_token_details, MetaCheckoutToken) def test_foreign_retailer(self): attributes = { 'amount': TransactionAmounts.Authorize, 'foreign_retailer': True, } transaction = Transaction(None, attributes) self.assertTrue(transaction.foreign_retailer)braintree_python-4.31.0/tests/unit/test_unknown_payment_method.py000066400000000000000000000005131471021343500255000ustar00rootroot00000000000000from tests.test_helper import * class TestUnknownPaymentMethod(unittest.TestCase): def test_image_url(self): unknown_payment_method = UnknownPaymentMethod("gateway", {"token": "TOKEN"}) self.assertEqual("https://assets.braintreegateway.com/payment_method_logo/unknown.png", unknown_payment_method.image_url()) braintree_python-4.31.0/tests/unit/test_us_bank_account.py000066400000000000000000000041711471021343500240460ustar00rootroot00000000000000from tests.test_helper import * from datetime import date from braintree.us_bank_account import UsBankAccount from braintree.us_bank_account_verification import UsBankAccountVerification class TestUsBankAccount(unittest.TestCase): def test_constructor(self): attributes = { "last_four": "1234", "routing_number": "55555", "account_type": "fake-account", "account_holder_name": "John Doe", "token": "7777-7777", "image_url": "some.png", "bank_name": "Chase", "ach_mandate": None, } us_bank_account = UsBankAccount({}, attributes) self.assertEqual(us_bank_account.last_four, "1234") self.assertEqual(us_bank_account.routing_number, "55555") self.assertEqual(us_bank_account.account_type, "fake-account") self.assertEqual(us_bank_account.account_holder_name, "John Doe") self.assertEqual(us_bank_account.token, "7777-7777") self.assertEqual(us_bank_account.image_url, "some.png") self.assertEqual(us_bank_account.bank_name, "Chase") self.assertEqual(us_bank_account.ach_mandate, None) attributes["ach_mandate"] = {"text":"Some mandate", "accepted_at": date(2013, 4, 10)} us_bank_account_mandated = UsBankAccount({}, attributes) self.assertEqual(us_bank_account_mandated.ach_mandate.text, "Some mandate") self.assertEqual(us_bank_account_mandated.ach_mandate.accepted_at, date(2013, 4, 10)) def test_converts_verifications_to_objects(self): attributes = { "verifications": [ { "status": "verified", "verification_method": "network_check", }, ], } us_bank_account = UsBankAccount({}, attributes) self.assertEqual(len(us_bank_account.verifications), 1) verification = us_bank_account.verifications[0] self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_method, UsBankAccountVerification.VerificationMethod.NetworkCheck) braintree_python-4.31.0/tests/unit/test_us_bank_account_verification.py000066400000000000000000000031521471021343500266060ustar00rootroot00000000000000from datetime import datetime from tests.test_helper import * from braintree.us_bank_account_verification import UsBankAccountVerification class TestUsBankAccountVerification(unittest.TestCase): def test_finding_empty_id_raises_not_found_exception(self): with self.assertRaises(NotFoundError): UsBankAccountVerification.find(" ") def test_finding_none_raises_not_found_exception(self): with self.assertRaises(NotFoundError): UsBankAccountVerification.find(None) def test_attributes(self): attributes = { "id": "my_favorite_id", "status": "verified", "verification_method": "independent_check", "verification_determined_at": datetime(2018, 11, 11, 23, 59, 59), "us_bank_account": { "token": "abc123", "last_4": 9999, }, "additional_processor_response": "Yikes" } verification = UsBankAccountVerification({}, attributes) self.assertEqual(verification.id, "my_favorite_id") self.assertEqual(verification.status, UsBankAccountVerification.Status.Verified) self.assertEqual(verification.verification_determined_at, datetime(2018, 11, 11, 23, 59, 59)) self.assertEqual(verification.additional_processor_response, "Yikes") self.assertEqual( verification.verification_method, UsBankAccountVerification.VerificationMethod.IndependentCheck ) self.assertEqual(verification.us_bank_account.token, "abc123") self.assertEqual(verification.us_bank_account.last_4, 9999) braintree_python-4.31.0/tests/unit/test_validation_error_collection.py000066400000000000000000000120541471021343500264650ustar00rootroot00000000000000from tests.test_helper import * class TestValidationErrorCollection(unittest.TestCase): def test_it_builds_an_array_of_errors_given_an_array_of_hashes(self): test_hash = {"errors": [{"attribute": "some model attribute", "code": 1, "message": "bad juju"}]} errors = ValidationErrorCollection(test_hash) error = errors[0] self.assertEqual("some model attribute", error.attribute) self.assertEqual(1, error.code) self.assertEqual("bad juju", error.message) def test_for_object_provides_access_to_nested_attributes(self): test_hash = { "errors": [{"attribute": "some model attribute", "code": 1, "message": "bad juju"}], "nested": { "errors": [{"attribute": "number", "code": 2, "message": "badder juju"}] } } errors = ValidationErrorCollection(test_hash) error = errors.for_object("nested").on("number")[0] self.assertEqual("number", error.attribute) self.assertEqual(2, error.code) self.assertEqual("badder juju", error.message) def test_deep_size_non_nested(self): test_hash = { "errors": [ {"attribute": "one", "code": 1, "message": "is too long"}, {"attribute": "two", "code": 2, "message": "contains invalid chars"}, {"attribute": "thr", "code": 3, "message": "is invalid"} ] } self.assertEqual(3, ValidationErrorCollection(test_hash).deep_size) def test_deep_size_nested(self): test_hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}] } } self.assertEqual(2, ValidationErrorCollection(test_hash).deep_size) def test_deep_size_multiple_nestings(self): test_hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}], "nested_again": { "errors": [ {"attribute": "three", "code": 3, "message": "super nested"}, {"attribute": "four", "code": 4, "message": "super nested 2"} ] } } } self.assertEqual(4, ValidationErrorCollection(test_hash).deep_size) def test_len_multiple_nestings(self): test_hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}], "nested_again": { "errors": [ {"attribute": "three", "code": 3, "message": "super nested"}, {"attribute": "four", "code": 4, "message": "super nested 2"} ] } } } validation_error_collection = ValidationErrorCollection(test_hash) self.assertEqual(1, len(validation_error_collection)) self.assertEqual(1, len(validation_error_collection.for_object("nested"))) self.assertEqual(2, len(validation_error_collection.for_object("nested").for_object("nested_again"))) def test_deep_errors(self): test_hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}], "nested_again": { "errors": [ {"attribute": "three", "code": 3, "message": "super nested"}, {"attribute": "four", "code": 4, "message": "super nested 2"} ] } } } validation_error_collection = ValidationErrorCollection(test_hash) self.assertEqual([1, 2, 3, 4], [error.code for error in validation_error_collection.deep_errors]) def test_errors(self): test_hash = { "errors": [{"attribute": "one", "code": 1, "message": "is too long"}], "nested": { "errors": [{"attribute": "two", "code": 2, "message": "contains invalid chars"}], "nested_again": { "errors": [ {"attribute": "three", "code": 3, "message": "super nested"}, {"attribute": "four", "code": 4, "message": "super nested 2"} ] } } } validation_error_collection = ValidationErrorCollection(test_hash) self.assertEqual([1], [error.code for error in validation_error_collection.errors]) self.assertEqual([2], [error.code for error in validation_error_collection.for_object("nested").errors]) self.assertEqual([3, 4], [error.code for error in validation_error_collection.for_object("nested").for_object("nested_again").errors]) braintree_python-4.31.0/tests/unit/test_visa_checkout_card.py000066400000000000000000000023431471021343500245270ustar00rootroot00000000000000from tests.test_helper import * from braintree.visa_checkout_card import VisaCheckoutCard class TestVisaCheckoutCard(unittest.TestCase): def test_expiration_date(self): card = VisaCheckoutCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "05", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual("05/2014", card.expiration_date) def test_expiration_date_no_month(self): card = VisaCheckoutCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "", "expiration_year": "2014", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual(None, card.expiration_date) def test_expiration_date_no_year(self): card = VisaCheckoutCard(None, { "customer_id": "12345", "number": "4111111111111111", "expiration_month": "05", "expiration_year": "", "cvv": "100", "cardholder_name": "John Doe" }) self.assertEqual(None, card.expiration_date)braintree_python-4.31.0/tests/unit/test_webhooks.py000066400000000000000000001376731471021343500225470ustar00rootroot00000000000000from tests.test_helper import * from datetime import date from braintree.dispute import Dispute from braintree.credit_card import CreditCard from braintree.paypal_account import PayPalAccount from braintree.venmo_account import VenmoAccount class TestWebhooks(unittest.TestCase): def test_granted_payment_method_revoked(self): webhook_testing_gateway = WebhookTestingGateway(BraintreeGateway(Configuration.instantiate())) sample_notification = webhook_testing_gateway.sample_notification(WebhookNotification.Kind.GrantedPaymentMethodRevoked, 'granted_payment_method_revoked_id') notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) metadata = notification.revoked_payment_method_metadata self.assertEqual(WebhookNotification.Kind.GrantedPaymentMethodRevoked, notification.kind) self.assertEqual("venmo_customer_id", metadata.customer_id) self.assertEqual("granted_payment_method_revoked_id", metadata.token) self.assertEqual(type(metadata.revoked_payment_method), VenmoAccount) def test_sample_notification_builds_a_parsable_notification(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubscriptionWentPastDue, notification.kind) self.assertEqual("my_id", notification.subscription.id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) self.assertIsNone(notification.source_merchant_id) def test_sample_notification_with_source_merchant_id(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, 'my_id', 'my_source_merchant_id' ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual('my_source_merchant_id', notification.source_merchant_id) def test_completely_invalid_signature(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) with self.assertRaises(InvalidSignatureError): WebhookNotification.parse("bad_stuff", sample_notification['bt_payload']) def test_parse_raises_when_public_key_is_wrong(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) config = Configuration( environment=Environment.Development, merchant_id="integration_merchant_id", public_key="wrong_public_key", private_key="wrong_private_key" ) gateway = BraintreeGateway(config) try: gateway.webhook_notification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) except InvalidSignatureError as e: self.assertEqual("no matching public key", str(e)) else: self.assertFalse("raises exception") def test_invalid_signature_when_payload_modified(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) try: WebhookNotification.parse(sample_notification['bt_signature'], b"badstuff" + sample_notification['bt_payload']) except InvalidSignatureError as e: self.assertEqual("signature does not match payload - one has been modified", str(e)) else: self.assertFalse("raises exception") def test_parse_raise_exception_if_signature_is_blank(self): try: WebhookNotification.parse(None, "payload") except InvalidSignatureError as e: self.assertEqual("signature cannot be blank", str(e)) else: self.assertFalse("raises exception") def test_parse_raise_exception_if_payload_is_blank(self): try: WebhookNotification.parse("signature", None) except InvalidSignatureError as e: self.assertEqual("payload cannot be blank", str(e)) else: self.assertFalse("raises exception") def test_invalid_signature_when_bontains_invalid_characters(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) try: WebhookNotification.parse(sample_notification['bt_signature'], "~* invalid! *~") except InvalidSignatureError as e: self.assertEqual("payload contains illegal characters", str(e)) else: self.assertFalse("raises exception") def test_parse_allows_all_valid_characters(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) try: WebhookNotification.parse(sample_notification['bt_signature'], "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+=/\n") except InvalidSignatureError as e: self.assertNotEqual("payload contains illegal characters", str(e)) def test_parse_retries_payload_with_a_newline(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionWentPastDue, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload'].rstrip()) self.assertEqual(WebhookNotification.Kind.SubscriptionWentPastDue, notification.kind) self.assertEqual("my_id", notification.subscription.id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) def test_verify_returns_a_correct_challenge_response(self): response = WebhookNotification.verify("20f9f8ed05f77439fe955c977e4c8a53") self.assertEqual("integration_public_key|d9b899556c966b3f06945ec21311865d35df3ce4", response) def test_verify_raises_when_challenge_is_invalid(self): try: WebhookNotification.verify("bad challenge") except InvalidChallengeError as e: self.assertEqual("challenge contains non-hex characters", str(e)) else: self.assertFalse("raises exception") def test_builds_notification_for_approved_sub_merchant_account(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubMerchantAccountApproved, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubMerchantAccountApproved, notification.kind) self.assertEqual("my_id", notification.merchant_account.id) self.assertEqual(MerchantAccount.Status.Active, notification.merchant_account.status) self.assertEqual("master_ma_for_my_id", notification.merchant_account.master_merchant_account.id) self.assertEqual(MerchantAccount.Status.Active, notification.merchant_account.master_merchant_account.status) def test_builds_notification_for_declined_sub_merchant_account(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubMerchantAccountDeclined, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubMerchantAccountDeclined, notification.kind) self.assertEqual("my_id", notification.merchant_account.id) self.assertEqual(MerchantAccount.Status.Suspended, notification.merchant_account.status) self.assertEqual("master_ma_for_my_id", notification.merchant_account.master_merchant_account.id) self.assertEqual(MerchantAccount.Status.Suspended, notification.merchant_account.master_merchant_account.status) self.assertEqual("Credit score is too low", notification.message) self.assertEqual(ErrorCodes.MerchantAccount.DeclinedOFAC, notification.errors.for_object("merchant_account").on("base")[0].code) def test_builds_notification_for_disbursed_transactions(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.TransactionDisbursed, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.TransactionDisbursed, notification.kind) self.assertEqual("my_id", notification.transaction.id) self.assertEqual(100, notification.transaction.amount) self.assertEqual(datetime(2013, 7, 9, 18, 23, 29), notification.transaction.disbursement_details.disbursement_date) def test_builds_notification_for_reviewed_transactions(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.TransactionReviewed, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.TransactionReviewed, notification.kind) self.assertEqual("my_id", notification.transaction_review.transaction_id) self.assertEqual("a smart decision", notification.transaction_review.decision) self.assertEqual("hey@girl.com", notification.transaction_review.reviewer_email) self.assertEqual("I reviewed this", notification.transaction_review.reviewer_note) self.assertEqual(datetime(2021, 4, 20, 6, 9, 0), notification.transaction_review.reviewed_time) def test_builds_notification_for_settled_transactions(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.TransactionSettled, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.TransactionSettled, notification.kind) self.assertEqual("my_id", notification.transaction.id) self.assertEqual("settled", notification.transaction.status) self.assertEqual(100, notification.transaction.amount) self.assertEqual(notification.transaction.us_bank_account.routing_number, "123456789") self.assertEqual(notification.transaction.us_bank_account.last_4, "1234") self.assertEqual(notification.transaction.us_bank_account.account_type, "checking") self.assertEqual(notification.transaction.us_bank_account.account_holder_name, "Dan Schulman") def test_builds_notification_for_settlement_declined_transactions(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.TransactionSettlementDeclined, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.TransactionSettlementDeclined, notification.kind) self.assertEqual("my_id", notification.transaction.id) self.assertEqual("settlement_declined", notification.transaction.status) self.assertEqual(100, notification.transaction.amount) self.assertEqual(notification.transaction.us_bank_account.routing_number, "123456789") self.assertEqual(notification.transaction.us_bank_account.last_4, "1234") self.assertEqual(notification.transaction.us_bank_account.account_type, "checking") self.assertEqual(notification.transaction.us_bank_account.account_holder_name, "Dan Schulman") def test_builds_notification_for_disbursements(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.Disbursement, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.Disbursement, notification.kind) self.assertEqual("my_id", notification.disbursement.id) self.assertEqual(100, notification.disbursement.amount) self.assertEqual(None, notification.disbursement.exception_message) self.assertEqual(None, notification.disbursement.follow_up_action) self.assertEqual(date(2014, 2, 9), notification.disbursement.disbursement_date) def test_builds_notification_for_disbursement_exceptions(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisbursementException, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisbursementException, notification.kind) self.assertEqual("my_id", notification.disbursement.id) self.assertEqual(100, notification.disbursement.amount) self.assertEqual("bank_rejected", notification.disbursement.exception_message) self.assertEqual("update_funding_information", notification.disbursement.follow_up_action) self.assertEqual(date(2014, 2, 9), notification.disbursement.disbursement_date) def test_builds_notification_for_old_dispute_under_review(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeUnderReview, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeUnderReview, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.UnderReview, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) def test_builds_notification_for_old_dispute_opened(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeOpened, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeOpened, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.Open, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) def test_builds_notification_for_old_dispute_lost(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeLost, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeLost, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.Lost, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) def test_builds_notification_for_old_dispute_won(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeWon, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeWon, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.Won, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) self.assertEqual(notification.dispute.date_won, date(2014, 9, 1)) def test_builds_notification_for_old_dispute_accepted(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeAccepted, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeAccepted, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.Accepted, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) def test_builds_notification_for_old_dispute_auto_accepted(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeAutoAccepted, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeAutoAccepted, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.AutoAccepted, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) def test_builds_notification_for_old_dispute_disputed(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeDisputed, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeDisputed, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.Disputed, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) def test_builds_notification_for_old_dispute_expired(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeExpired, "legacy_dispute_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeExpired, notification.kind) self.assertEqual("legacy_dispute_id", notification.dispute.id) self.assertEqual(Dispute.Status.Expired, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) def test_builds_notification_for_new_dispute_under_review(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeUnderReview, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeUnderReview, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.UnderReview, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) def test_builds_notification_for_new_dispute_opened(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeOpened, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeOpened, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.Open, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) def test_builds_notification_for_new_dispute_lost(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeLost, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeLost, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.Lost, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) def test_builds_notification_for_new_dispute_won(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeWon, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeWon, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.Won, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) self.assertEqual(notification.dispute.date_opened, date(2014, 3, 28)) self.assertEqual(notification.dispute.date_won, date(2014, 9, 1)) def test_builds_notification_for_new_dispute_accepted(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeAccepted, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeAccepted, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.Accepted, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) def test_builds_notification_for_new_dispute_auto_accepted(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeAutoAccepted, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeAutoAccepted, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.AutoAccepted, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) def test_builds_notification_for_new_dispute_disputed(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeDisputed, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeDisputed, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.Disputed, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) def test_builds_notification_for_new_dispute_expired(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.DisputeExpired, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.DisputeExpired, notification.kind) self.assertEqual("my_id", notification.dispute.id) self.assertEqual(Dispute.Status.Expired, notification.dispute.status) self.assertEqual(Dispute.Kind.Chargeback, notification.dispute.kind) def test_builds_notification_for_partner_merchant_connected(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.PartnerMerchantConnected, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.PartnerMerchantConnected, notification.kind) self.assertEqual("abc123", notification.partner_merchant.partner_merchant_id) self.assertEqual("public_key", notification.partner_merchant.public_key) self.assertEqual("private_key", notification.partner_merchant.private_key) self.assertEqual("public_id", notification.partner_merchant.merchant_public_id) self.assertEqual("cse_key", notification.partner_merchant.client_side_encryption_key) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) def test_builds_notification_for_partner_merchant_disconnected(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.PartnerMerchantDisconnected, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.PartnerMerchantDisconnected, notification.kind) self.assertEqual("abc123", notification.partner_merchant.partner_merchant_id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) def test_builds_notification_for_partner_merchant_declined(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.PartnerMerchantDeclined, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.PartnerMerchantDeclined, notification.kind) self.assertEqual("abc123", notification.partner_merchant.partner_merchant_id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) def test_builds_notification_for_oauth_access_revoked(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.OAuthAccessRevoked, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) self.assertEqual(WebhookNotification.Kind.OAuthAccessRevoked, notification.kind) self.assertEqual("my_id", notification.oauth_access_revocation.merchant_id) self.assertEqual("oauth_application_client_id", notification.oauth_access_revocation.oauth_application_client_id) self.assertTrue((datetime.utcnow() - notification.timestamp).seconds < 10) def test_builds_notification_for_connected_merchant_status_transitioned(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.ConnectedMerchantStatusTransitioned, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.ConnectedMerchantStatusTransitioned, notification.kind) self.assertEqual("new_status", notification.connected_merchant_status_transitioned.status) self.assertEqual("my_id", notification.connected_merchant_status_transitioned.merchant_public_id) self.assertEqual("my_id", notification.connected_merchant_status_transitioned.merchant_id) self.assertEqual("oauth_application_client_id", notification.connected_merchant_status_transitioned.oauth_application_client_id) def test_builds_notification_for_connected_merchant_paypal_status_changed(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.ConnectedMerchantPayPalStatusChanged, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.ConnectedMerchantPayPalStatusChanged, notification.kind) self.assertEqual("link", notification.connected_merchant_paypal_status_changed.action) self.assertEqual("my_id", notification.connected_merchant_paypal_status_changed.merchant_public_id) self.assertEqual("my_id", notification.connected_merchant_paypal_status_changed.merchant_id) self.assertEqual("oauth_application_client_id", notification.connected_merchant_paypal_status_changed.oauth_application_client_id) def test_builds_notification_for_refund_failed(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.RefundFailed, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.RefundFailed, notification.kind) self.assertEqual("my_id", notification.transaction.id) def test_builds_notification_for_subscription_billing_skipped(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionBillingSkipped, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubscriptionBillingSkipped, notification.kind) self.assertEqual("my_id", notification.subscription.id) self.assertTrue(len(notification.subscription.transactions) == 0) self.assertTrue(len(notification.subscription.discounts) == 0) self.assertTrue(len(notification.subscription.add_ons) == 0) def test_builds_notification_for_subscription_charged_successfully(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionChargedSuccessfully, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubscriptionChargedSuccessfully, notification.kind) self.assertEqual("my_id", notification.subscription.id) self.assertTrue(len(notification.subscription.transactions) == 1) transaction = notification.subscription.transactions.pop() self.assertEqual("submitted_for_settlement", transaction.status) self.assertEqual(Decimal("49.99"), transaction.amount) def test_builds_notification_for_subscription_charged_unsuccessfully(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.SubscriptionChargedUnsuccessfully, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.SubscriptionChargedUnsuccessfully, notification.kind) self.assertEqual("my_id", notification.subscription.id) self.assertTrue(len(notification.subscription.transactions) == 1) transaction = notification.subscription.transactions.pop() self.assertEqual("failed", transaction.status) self.assertEqual(Decimal("49.99"), transaction.amount) def test_builds_notification_for_check(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.Check, "" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.Check, notification.kind) def test_builds_notification_for_account_updater_daily_report_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.AccountUpdaterDailyReport, "my_id" ) notification = WebhookNotification.parse(sample_notification['bt_signature'], sample_notification['bt_payload']) self.assertEqual(WebhookNotification.Kind.AccountUpdaterDailyReport, notification.kind) self.assertEqual("link-to-csv-report", notification.account_updater_daily_report.report_url) self.assertEqual(date(2016, 1, 14), notification.account_updater_daily_report.report_date) def test_grantor_updated_granted_payment_method_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.GrantorUpdatedGrantedPaymentMethod, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) update = notification.granted_payment_instrument_update self.assertEqual(WebhookNotification.Kind.GrantorUpdatedGrantedPaymentMethod, notification.kind) self.assertEqual("vczo7jqrpwrsi2px", update.grant_owner_merchant_id) self.assertEqual("cf0i8wgarszuy6hc", update.grant_recipient_merchant_id) self.assertEqual("ee257d98-de40-47e8-96b3-a6954ea7a9a4", update.payment_method_nonce) self.assertEqual("abc123z", update.token) self.assertEqual(["expiration-month", "expiration-year"], update.updated_fields) def test_recipient_updated_granted_payment_method_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.RecipientUpdatedGrantedPaymentMethod, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) update = notification.granted_payment_instrument_update self.assertEqual(WebhookNotification.Kind.RecipientUpdatedGrantedPaymentMethod, notification.kind) self.assertEqual("vczo7jqrpwrsi2px", update.grant_owner_merchant_id) self.assertEqual("cf0i8wgarszuy6hc", update.grant_recipient_merchant_id) self.assertEqual("ee257d98-de40-47e8-96b3-a6954ea7a9a4", update.payment_method_nonce) self.assertEqual("abc123z", update.token) self.assertEqual(["expiration-month", "expiration-year"], update.updated_fields) def test_granted_payment_method_revoked_credit_card_webhook(self): xml_payload = """ 12345 2018-10-10T22:46:41Z granted_payment_method_revoked 555555 MasterCard Amber Ankunding Unknown Unknown 2018-10-10T22:46:41Z credit_card_customer_id US Unknown true Unknown 06 2020 false cGF5bWVudG1ldGhvZF8zcHQ2d2hz Unknown https://assets.braintreegateway.com/payment_method_logo/mastercard.png?environment=test Unknown 4444 Unknown Unknown Unknown credit_card_token 08199d188e37460163207f714faf074a 2018-10-10T22:46:41Z false """.encode("utf-8") sample_notification = TestHelper.sample_notification_from_xml(xml_payload) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) metadata = notification.revoked_payment_method_metadata self.assertEqual(WebhookNotification.Kind.GrantedPaymentMethodRevoked, notification.kind) self.assertEqual("credit_card_customer_id", metadata.customer_id) self.assertEqual("credit_card_token", metadata.token) self.assertTrue(isinstance(metadata.revoked_payment_method, CreditCard)) def test_granted_payment_method_revoked_paypal_account_webhook(self): xml_payload = """ 12345 2018-10-10T22:46:41Z granted_payment_method_revoked billing_agreement_id 2018-10-11T21:10:33Z paypal_customer_id true johndoe@example.com cGF5bWVudG1ldGhvZF9wYXlwYWxfdG9rZW4 https://assets.braintreegateway.com/payment_method_logo/mastercard.png?environment=test paypal_token 2018-10-11T21:10:33Z a6a8e1a4 """.encode("utf-8") sample_notification = TestHelper.sample_notification_from_xml(xml_payload) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) metadata = notification.revoked_payment_method_metadata self.assertEqual(WebhookNotification.Kind.GrantedPaymentMethodRevoked, notification.kind) self.assertEqual("paypal_customer_id", metadata.customer_id) self.assertEqual("paypal_token", metadata.token) self.assertTrue(isinstance(metadata.revoked_payment_method, PayPalAccount)) def test_granted_payment_method_revoked_venmo_account_webhook(self): xml_payload = """ 12345 2018-10-10T22:46:41Z granted_payment_method_revoked 2018-10-11T21:28:37Z 2018-10-11T21:28:37Z true https://assets.braintreegateway.com/payment_method_logo/mastercard.png?environment=test venmo_token Venmo Account: venmojoe venmojoe 456 venmo_customer_id cGF5bWVudG1ldGhvZF92ZW5tb2FjY291bnQ """.encode("utf-8") sample_notification = TestHelper.sample_notification_from_xml(xml_payload) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) metadata = notification.revoked_payment_method_metadata self.assertEqual(WebhookNotification.Kind.GrantedPaymentMethodRevoked, notification.kind) self.assertEqual("venmo_customer_id", metadata.customer_id) self.assertEqual("venmo_token", metadata.token) self.assertTrue(isinstance(metadata.revoked_payment_method, VenmoAccount)) def test_payment_method_revoked_by_customer_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.PaymentMethodRevokedByCustomer, "my_payment_method_token" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) metadata = notification.revoked_payment_method_metadata self.assertEqual(WebhookNotification.Kind.PaymentMethodRevokedByCustomer, notification.kind) self.assertEqual("my_payment_method_token", metadata.token) self.assertTrue(isinstance(metadata.revoked_payment_method, PayPalAccount)) self.assertNotEqual(None, metadata.revoked_payment_method.revoked_at) def test_local_payment_completed_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.LocalPaymentCompleted, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) local_payment_completed = notification.local_payment_completed self.assertEqual(WebhookNotification.Kind.LocalPaymentCompleted, notification.kind) self.assertEqual("a-bic", local_payment_completed.bic) self.assertEqual("1234", local_payment_completed.iban_last_chars) self.assertEqual("a-payer-id", local_payment_completed.payer_id) self.assertEqual("a-payer-name", local_payment_completed.payer_name) self.assertEqual("a-payment-id", local_payment_completed.payment_id) self.assertEqual("ee257d98-de40-47e8-96b3-a6954ea7a9a4", local_payment_completed.payment_method_nonce) self.assertTrue(isinstance(local_payment_completed.transaction, Transaction)) def test_local_payment_completed_webhook_blik_one_click(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.LocalPaymentCompleted, "blik_one_click_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) local_payment_completed = notification.local_payment_completed self.assertEqual(WebhookNotification.Kind.LocalPaymentCompleted, notification.kind) self.assertEqual("1234", local_payment_completed.iban_last_chars) self.assertEqual("a-bic", local_payment_completed.bic) self.assertEqual('alias-key-1', local_payment_completed.blik_aliases[0].key) self.assertEqual('alias-label-1', local_payment_completed.blik_aliases[0].label) self.assertEqual("a-payer-id", local_payment_completed.payer_id) self.assertEqual("a-payer-name", local_payment_completed.payer_name) self.assertEqual("a-payment-id", local_payment_completed.payment_id) self.assertEqual("ee257d98-de40-47e8-96b3-a6954ea7a9a4", local_payment_completed.payment_method_nonce) self.assertTrue(isinstance(local_payment_completed.transaction, Transaction)) def test_local_payment_expired_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.LocalPaymentExpired, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) local_payment_expired = notification.local_payment_expired self.assertEqual(WebhookNotification.Kind.LocalPaymentExpired, notification.kind) self.assertEqual("a-payment-id", local_payment_expired.payment_id) self.assertEqual("a-context-payment-id", local_payment_expired.payment_context_id) def test_local_payment_funded_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.LocalPaymentFunded, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) local_payment_funded = notification.local_payment_funded self.assertEqual(WebhookNotification.Kind.LocalPaymentFunded, notification.kind) self.assertEqual("a-payment-id", local_payment_funded.payment_id) self.assertEqual("a-context-payment-id", local_payment_funded.payment_context_id) self.assertTrue(isinstance(local_payment_funded.transaction, Transaction)) self.assertEqual("1", local_payment_funded.transaction.id) self.assertEqual("settled", local_payment_funded.transaction.status) self.assertEqual("order1234", local_payment_funded.transaction.order_id) def test_local_payment_reversed_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.LocalPaymentReversed, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) local_payment_reversed = notification.local_payment_reversed self.assertEqual(WebhookNotification.Kind.LocalPaymentReversed, notification.kind) self.assertEqual("a-payment-id", local_payment_reversed.payment_id) def test_payment_method_customer_data_updated_webhook(self): sample_notification = WebhookTesting.sample_notification( WebhookNotification.Kind.PaymentMethodCustomerDataUpdated, "my_id" ) notification = WebhookNotification.parse(sample_notification["bt_signature"], sample_notification["bt_payload"]) payment_method_customer_data_updated = notification.payment_method_customer_data_updated_metadata self.assertEqual(WebhookNotification.Kind.PaymentMethodCustomerDataUpdated, notification.kind) self.assertEqual(payment_method_customer_data_updated.token, "TOKEN-12345") self.assertEqual(payment_method_customer_data_updated.datetime_updated, "2022-01-01T21:28:37Z") enriched_customer_data = payment_method_customer_data_updated.enriched_customer_data self.assertEqual(enriched_customer_data.fields_updated, ["username"]) address = { "street_address": "Street Address", "extended_address": "Extended Address", "locality": "Locality", "region": "Region", "postal_code":"Postal Code" } profile_data = enriched_customer_data.profile_data self.assertEqual(profile_data.first_name, "John") self.assertEqual(profile_data.last_name, "Doe") self.assertEqual(profile_data.username, "venmo_username") self.assertEqual(profile_data.phone_number, "1231231234") self.assertEqual(profile_data.email, "john.doe@paypal.com") self.assertEqual(profile_data.billing_address, address) self.assertEqual(profile_data.shipping_address, address) braintree_python-4.31.0/tests/unit/test_xml_util.py000066400000000000000000000162251471021343500225500ustar00rootroot00000000000000from tests.test_helper import * class TestXmlUtil(unittest.TestCase): def test_dict_from_xml_simple(self): xml = """ val """ expected = {"container": "val"} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_typecasts_ints(self): xml = """ 1 """ expected = {"container": 1} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_typecasts_nils(self): xml = """ """ expected = {"root": {"a_nil_value": None, "an_empty_string": ""}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_typecasts_booleans(self): xml = """ true 1 false anything true """ expected = { "root": { "casted_true": True, "casted_one": True, "casted_false": False, "casted_anything": False, "uncasted_true": "true" } } self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_typecasts_datetimes(self): xml = """ 2009-10-28T10:19:49Z """ expected = {"root": {"created_at": datetime(2009, 10, 28, 10, 19, 49)}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_with_dashes(self): xml = """ val """ expected = {"my_item": "val"} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_nested(self): xml = """ val """ expected = {"container": {"elem": "val"}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_array(self): xml = """ val1 val2 val3 """ expected = {"container": {"elements": ["val1", "val2", "val3"]}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_with_empty_array(self): xml = """ """ expected = {"container": {"elements": []}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_dict_from_xml_array_of_hashes(self): xml = """ val1 val2 val3 """ expected = {"container": {"elements": [{"val": "val1"}, {"val": "val2"}, {"val": "val3"}]}} self.assertEqual(expected, XmlUtil.dict_from_xml(xml)) def test_xml_from_dict_escapes_keys_and_values(self): test_dict = {"kva&lue", XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_escapes_keys_list(self): test_dict = {"k", XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_escapes_keys_bool(self): test_dict = {"ktrue", XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_escapes_keys_int(self): test_dict = {"k10", XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_escapes_keys_datetime(self): test_dict = {"k2023-01-02T03:04:05Z", XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_with_xml_injection(self): test_dict = {"12345": []} self.assertEqual("<<merchant-account-id>12345</merchant-account-id> type=\"array\">", XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_simple(self): test_dict = {"a": "b"} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_with_integer(self): test_dict = {"a": 1} self.assertEqual('1', XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_with_long(self): test_dict = {"a": 12341234123412341234} self.assertEqual('12341234123412341234', XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_with_boolean(self): test_dict = {"a": True} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_simple_xml_and_back_twice(self): test_dict = {"a": "b"} self.assertEqual(test_dict, self.__xml_and_back(self.__xml_and_back(test_dict))) def test_xml_from_dict_nested(self): test_dict = {"container": {"item": "val"}} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_with_array(self): test_dict = {"container": {"elements": ["val1", "val2", "val3"]}} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_with_array_of_hashes(self): test_dict = {"container": {"elements": [{"val": "val1"}, {"val": "val2"}, {"val": "val3"}]}} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_retains_underscores(self): test_dict = {"container": {"my_element": "val"}} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_escapes_special_chars(self): test_dict = {"container": {"element": "<&>'\""}} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_with_datetime(self): test_dict = {"a": datetime(2010, 1, 2, 3, 4, 5)} self.assertEqual(test_dict, self.__xml_and_back(test_dict)) def test_xml_from_dict_with_unicode_characters(self): test_dict = {"a": u"\u1f61hat?"} self.assertEqual('ὡhat?', XmlUtil.xml_from_dict(test_dict)) def test_xml_from_dict_with_dates_formats_as_datetime(self): test_dict = {"a": date(2010, 1, 2)} self.assertEqual('2010-01-02T00:00:00Z', XmlUtil.xml_from_dict(test_dict)) @staticmethod def __xml_and_back(test_dict): return XmlUtil.dict_from_xml(XmlUtil.xml_from_dict(test_dict)) braintree_python-4.31.0/tests/unit/util/000077500000000000000000000000001471021343500202515ustar00rootroot00000000000000braintree_python-4.31.0/tests/unit/util/__init__.py000066400000000000000000000000001471021343500223500ustar00rootroot00000000000000braintree_python-4.31.0/tests/unit/util/test_constants.py000066400000000000000000000004261471021343500237000ustar00rootroot00000000000000from tests.test_helper import * class TestConstants(unittest.TestCase): def test_get_all_constant_values_from_class(self): self.assertEqual(["Active", "Canceled", "Expired", "Past Due", "Pending"], Constants.get_all_constant_values_from_class(Subscription.Status)) braintree_python-4.31.0/tests/unit/util/test_datetime_parser.py000066400000000000000000000030601471021343500250310ustar00rootroot00000000000000import unittest from braintree.util.datetime_parser import parse_datetime as parse from datetime import datetime class TestDateParser(unittest.TestCase): def test_parses_with_zulu_and_symbols(self): self.assertEqual(parse('2017-04-19T18:51:21Z'), datetime(2017, 4, 19, 18, 51, 21)) self.assertEqual(parse('2017-04-19T18:51:21.45Z'), datetime(2017, 4, 19, 18, 51, 21, 450000)) def test_parses_with_zulu_and_no_symbols(self): self.assertEqual(parse('20170419T185121Z'), datetime(2017, 4, 19, 18, 51, 21)) self.assertEqual(parse('20170419T185121.123Z'), datetime(2017, 4, 19, 18, 51, 21, 123000)) def test_parses_with_zero_offset(self): self.assertEqual(parse('2017-04-19T18:51:21+00:00'), datetime(2017, 4, 19, 18, 51, 21)) self.assertEqual(parse('2017-04-19T18:51:21.420+00:00'), datetime(2017, 4, 19, 18, 51, 21, 420000)) def test_parses_with_negative_offset(self): self.assertEqual(parse('2017-04-19T18:51:21-01:30'), datetime(2017, 4, 19, 20, 21, 21)) self.assertEqual(parse('2017-04-19T18:51:21.987-01:30'), datetime(2017, 4, 19, 20, 21, 21, 987000)) def test_parses_with_positive_offset(self): self.assertEqual(parse('2017-04-19T18:51:21+07:00'), datetime(2017, 4, 19, 11, 51, 21)) self.assertEqual(parse('2017-04-19T18:51:21.765+07:00'), datetime(2017, 4, 19, 11, 51, 21, 765000)) def test_raises_with_bad_input(self): with self.assertRaises(ValueError): parse('20170420') with self.assertRaises(ValueError): parse('20170420Z')