Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
sincpro-payments-sdk / apps / cybersource / services / tokenization / create_customer_payment_method.py
Size: Mime:
from sincpro_payments_sdk import exceptions
from sincpro_payments_sdk.apps.cybersource import DataTransferObject, Feature, cybersource
from sincpro_payments_sdk.apps.cybersource.domain import (
    CardMonthOrDay,
    CardNumber,
    CardYear4Digits,
    convert_to_card_type,
)


class CommandCreateCustomerPaymentMethod(DataTransferObject):
    """Create a customer profile with a saved card.

    Use when you want to:
    - Create a customer in CyberSource vault
    - Associate a card to that customer
    - Allow customer to have multiple cards
    """

    external_id: str
    email: str
    card_number: str
    month: str
    year: str


class ResponseCreateCustomerPaymentMethod(DataTransferObject):
    """Response with customer_id and token_id."""

    customer_id: str
    token_id: str
    instrument_identifier_id: str
    card_type: str
    state: str
    raw_response: dict | None = None


@cybersource.feature(CommandCreateCustomerPaymentMethod)
class CreateCustomerPaymentMethod(Feature):
    """Create a customer with a saved card in CyberSource vault.

    Flow:
        1. create_customer() -> customer_id
        2. create_card() -> instrument_identifier_id
        3. associate_card_payment_method_to_customer() -> token_id

    Use Cases:
        - Customer registration with card save
        - Adding cards to customer wallet
    """

    def execute(
        self, dto: CommandCreateCustomerPaymentMethod
    ) -> ResponseCreateCustomerPaymentMethod:
        card_exp_year = self._get_exp_year(dto)
        card_exp_month = CardMonthOrDay(dto.month)
        card_number = CardNumber(dto.card_number)
        card_type = convert_to_card_type(card_number)

        customer = self.token_adapter.create_customer(dto.external_id, dto.email)

        tokenized_card = self.token_adapter.create_card(card_number)
        if tokenized_card.state != "ACTIVE":
            raise exceptions.SincproValidationError("Card not active")

        payment_instrument = self.token_adapter.associate_card_payment_method_to_customer(
            tokenized_customer_id=customer.id,
            tokenized_card_id=tokenized_card.id,
            month=card_exp_month,
            year=card_exp_year,
            card_type=card_type,
        )

        return ResponseCreateCustomerPaymentMethod(
            customer_id=customer.id,
            token_id=payment_instrument.id,
            instrument_identifier_id=tokenized_card.id,
            card_type=payment_instrument.card_type,
            state=payment_instrument.state,
            raw_response=payment_instrument.raw_response,
        )

    def _get_exp_year(self, dto) -> CardYear4Digits:
        card_exp_year = dto.year
        if len(dto.year) == 2:
            card_exp_year = f"20{dto.year}"
        return CardYear4Digits(card_exp_year)