Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Payment Contexts Support (CS2) #146

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
run: flake8 . --count --max-complexity=10 --max-line-length=127 --statistics
- name: Run unit tests
env:
CHECKOUT_PROCESSING_CHANNEL_ID: ${{ secrets.IT_CHECKOUT_PROCESSING_CHANNEL_ID }}
CHECKOUT_PREVIOUS_SECRET_KEY: ${{ secrets.IT_CHECKOUT_PREVIOUS_SECRET_KEY }}
CHECKOUT_PREVIOUS_PUBLIC_KEY: ${{ secrets.IT_CHECKOUT_PREVIOUS_PUBLIC_KEY }}
CHECKOUT_DEFAULT_SECRET_KEY: ${{ secrets.IT_CHECKOUT_DEFAULT_SECRET_KEY }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/build-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
run: pylint checkout_sdk
- name: Run unit tests
env:
CHECKOUT_PROCESSING_CHANNEL_ID: ${{ secrets.IT_CHECKOUT_PROCESSING_CHANNEL_ID }}
CHECKOUT_PREVIOUS_SECRET_KEY: ${{ secrets.IT_CHECKOUT_PREVIOUS_SECRET_KEY }}
CHECKOUT_PREVIOUS_PUBLIC_KEY: ${{ secrets.IT_CHECKOUT_PREVIOUS_PUBLIC_KEY }}
CHECKOUT_DEFAULT_SECRET_KEY: ${{ secrets.IT_CHECKOUT_DEFAULT_SECRET_KEY }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
pip install -r requirements-dev.txt
- id: testing
env:
CHECKOUT_PROCESSING_CHANNEL_ID: ${{ secrets.IT_CHECKOUT_PROCESSING_CHANNEL_ID }}
CHECKOUT_PREVIOUS_SECRET_KEY: ${{ secrets.IT_CHECKOUT_PREVIOUS_SECRET_KEY }}
CHECKOUT_PREVIOUS_PUBLIC_KEY: ${{ secrets.IT_CHECKOUT_PREVIOUS_PUBLIC_KEY }}
CHECKOUT_DEFAULT_SECRET_KEY: ${{ secrets.IT_CHECKOUT_DEFAULT_SECRET_KEY }}
Expand Down
2 changes: 2 additions & 0 deletions checkout_sdk/checkout_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from checkout_sdk.checkout_apm_api import CheckoutApmApi
from checkout_sdk.instruments.instruments_client import InstrumentsClient
from checkout_sdk.issuing.issuing_client import IssuingClient
from checkout_sdk.payments.contexts.contexts_client import PaymentContextsClient
from checkout_sdk.payments.hosted.hosted_payments_client import HostedPaymentsClient
from checkout_sdk.payments.links.payments_client import PaymentsLinksClient
from checkout_sdk.payments.payments_client import PaymentsClient
Expand Down Expand Up @@ -64,3 +65,4 @@ def __init__(self, configuration: CheckoutConfiguration):
self.card_metadata = CardMetadataClient(api_client=base_api_client, configuration=configuration)
self.financial = FinancialClient(api_client=base_api_client, configuration=configuration)
self.issuing = IssuingClient(api_client=base_api_client, configuration=configuration)
self.contexts = PaymentContextsClient(api_client=base_api_client, configuration=configuration)
2 changes: 2 additions & 0 deletions checkout_sdk/oauth_scopes.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ class OAuthScopes(str, Enum):
ISSUING_CARD_MGMT = 'issuing:card-mgmt'
ISSUING_CONTROLS_READ = 'issuing:controls-read'
ISSUING_CONTROLS_WRITE = 'issuing:controls-write'

PAYMENT_CONTEXTS = 'Payment Contexts'
Empty file.
91 changes: 91 additions & 0 deletions checkout_sdk/payments/contexts/contexts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from datetime import datetime

from checkout_sdk.common.common import Address
from checkout_sdk.common.enums import Currency, PaymentSourceType
from checkout_sdk.payments.payments import PaymentRequestSource, PaymentType, ShippingDetails, BillingPlan, \
ShippingPreference, UserAction


class PaymentContextsPartnerCustomerRiskData:
key: str
value: str


class PaymentContextsTicket:
number: str
issue_date: datetime
issuing_carrier_code: str
travel_package_indicator: str
travel_agency_name: str
travel_agency_code: str


class PaymentContextsPassenger:
first_name: str
last_name: str
date_of_birth: datetime
address: Address


class PaymentContextsFlightLegDetails:
flight_number: str
carrier_code: str
class_of_travelling: str
departure_airport: str
departure_date: datetime
departure_time: str
arrival_airport: str
stop_over_code: str
fare_basis_code: str


class PaymentContextsAirlineData:
ticket: list # payment.contexts.PaymentContextsTicket
passenger: list # payment.contexts.PaymentContextsPassenger
flight_leg_details: list # payment.contexts.PaymentContextsFlightLegDetails


class PaymentContextsProcessing:
plan: BillingPlan
shipping_amount: int
invoice_id: str
brand_name: str
locale: str
shipping_preference: ShippingPreference
user_action: UserAction
partner_customer_risk_data: PaymentContextsPartnerCustomerRiskData
airline_data: list # payment.contexts.PaymentContextsAirlineData


class PaymentContextsItems:
name: str
quantity: int
unit_price: int
reference: str
total_amount: int
tax_amount: int
discount_amount: int
url: str
image_url: str


class PaymentContextsRequest:
source: PaymentRequestSource
amount: int
currency: Currency
payment_type: PaymentType
capture: bool
shipping: ShippingDetails
processing: PaymentContextsProcessing
processing_channel_id: str
reference: str
description: str
success_url: str
failure_url: str
items: list # payments.contexts.PaymentContextsItems


class PaymentContextPayPalSource(PaymentRequestSource):

def __init__(self):
super().__init__(PaymentSourceType.PAYPAL)
24 changes: 24 additions & 0 deletions checkout_sdk/payments/contexts/contexts_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from __future__ import absolute_import

from checkout_sdk.api_client import ApiClient
from checkout_sdk.authorization_type import AuthorizationType
from checkout_sdk.checkout_configuration import CheckoutConfiguration
from checkout_sdk.client import Client
from checkout_sdk.payments.contexts.contexts import PaymentContextsRequest


class PaymentContextsClient(Client):
__PAYMENT_CONTEXTS_PATH = 'payment-contexts'

def __init__(self, api_client: ApiClient, configuration: CheckoutConfiguration):
super().__init__(api_client=api_client,
configuration=configuration,
authorization_type=AuthorizationType.SECRET_KEY_OR_OAUTH)

def create_payment_contexts(self, payment_contexts_request: PaymentContextsRequest):
return self._api_client.post(self.__PAYMENT_CONTEXTS_PATH, self._sdk_authorization(),
payment_contexts_request)

def get_payment_context_details(self, payment_context_id: str):
return self._api_client.get(self.build_path(self.__PAYMENT_CONTEXTS_PATH, payment_context_id),
self._sdk_authorization())
15 changes: 15 additions & 0 deletions checkout_sdk/payments/payments.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from checkout_sdk.common.common import AccountHolder, BankDetails, MarketplaceData, Address, Phone, CustomerRequest, \
AccountHolderIdentification
from checkout_sdk.common.enums import PaymentSourceType, Currency, Country, AccountType, ChallengeIndicator
from checkout_sdk.sessions.sessions import DeliveryTimeframe


class AuthorizationType(str, Enum):
Expand Down Expand Up @@ -62,6 +63,7 @@ class Exemption(str, Enum):
OUT_OF_SCA_SCOPE = 'out_of_sca_scope'
OTHER = 'other'
LOW_RISK_PROGRAM = 'low_risk_program'
DATA_SHARE = 'data_share'


class ThreeDSFlowType(str, Enum):
Expand Down Expand Up @@ -283,10 +285,23 @@ def __init__(self):
super().__init__(PaymentSourceType.CUSTOMER)


class PaymentContextsShippingMethod(str, Enum):
DIGITAL = 'Digital'
PICK_UP = 'PickUp'
BILLING_ADDRESS = 'BillingAddress'
OTHER_ADDRESS = 'OtherAddress'


class ShippingDetails:
first_name: str
last_name: str
email: str
address: Address
phone: Phone
from_address_zip: str
timeframe: DeliveryTimeframe
method: PaymentContextsShippingMethod
delay: int


class ThreeDsRequest:
Expand Down
20 changes: 20 additions & 0 deletions tests/payments/contexts/payment_contexts_client_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import pytest

from checkout_sdk.payments.contexts.contexts import PaymentContextsRequest
from checkout_sdk.payments.contexts.contexts_client import PaymentContextsClient


@pytest.fixture(scope='class')
def client(mock_sdk_configuration, mock_api_client):
return PaymentContextsClient(api_client=mock_api_client, configuration=mock_sdk_configuration)


class TestPaymentContextsClient:

def test_should_create_payment_contexts(self, mocker, client: PaymentContextsClient):
mocker.patch('checkout_sdk.api_client.ApiClient.post', return_value='response')
assert client.create_payment_contexts(PaymentContextsRequest()) == 'response'

def test_should_get_payment_context_details(self, mocker, client: PaymentContextsClient):
mocker.patch('checkout_sdk.api_client.ApiClient.get', return_value='response')
assert client.get_payment_context_details('payment_contexts_id') == 'response'
58 changes: 58 additions & 0 deletions tests/payments/contexts/payment_contexts_integration_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from __future__ import absolute_import

import os

from checkout_sdk.common.enums import Currency
from checkout_sdk.payments.contexts.contexts import PaymentContextsRequest, PaymentContextPayPalSource, \
PaymentContextsItems
from checkout_sdk.payments.payments import PaymentType
from tests.checkout_test_utils import assert_response


def test_should_create_and_get_payment_context_details(default_api):
request = create_payment_contexts_request()

response = default_api.contexts.create_payment_contexts(request)

assert_response(response,
'http_metadata',
'id',
'partner_metadata.order_id')

payment_contexts_details = default_api.contexts.get_payment_context_details(response.id)

assert_response(payment_contexts_details,
'http_metadata',
'payment_request',
'payment_request.source',
'payment_request.amount',
'payment_request.currency',
'payment_request.payment_type',
'payment_request.capture',
'payment_request.items',
'payment_request.success_url',
'payment_request.failure_url',
'partner_metadata',
'partner_metadata.order_id')


def create_payment_contexts_request():
source = PaymentContextPayPalSource()

items = PaymentContextsItems()
items.name = 'mask'
items.unit_price = 2000
items.quantity = 1

request = PaymentContextsRequest()
request.source = source
request.amount = 2000
request.currency = Currency.EUR
request.payment_type = PaymentType.REGULAR
request.capture = True
request.processing_channel_id = os.environ.get('CHECKOUT_PROCESSING_CHANNEL_ID')
request.success_url = 'https://example.com/payments/success'
request.failure_url = 'https://example.com/payments/failure'
request.items = [items]

return request
1 change: 1 addition & 0 deletions tests/payments/request_apm_payments_integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ def test_should_make_illicado_payment(default_api):
payment_request=payment_request)


@pytest.mark.skip(reason='not available')
def test_should_make_klarna_payment(default_api):
account_holder = AccountHolder()
account_holder.first_name = FIRST_NAME
Expand Down
Loading