All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.killbill.billing.plugin.stripe.StripePluginProperties Maven / Gradle / Ivy

There is a newer version: 8.0.2
Show newest version
/*
 * Copyright 2020-2020 Equinix, Inc
 * Copyright 2014-2020 The Billing Project, LLC
 *
 * The Billing Project licenses this file to you under the Apache License, version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at:
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package org.killbill.billing.plugin.stripe;

import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nullable;

import org.killbill.billing.payment.plugin.api.PaymentPluginStatus;

import com.google.common.base.Throwables;
import com.stripe.exception.StripeException;
import com.stripe.model.BankAccount;
import com.stripe.model.Charge;
import com.stripe.model.PaymentIntent;
import com.stripe.model.PaymentMethod;
import com.stripe.model.PaymentMethod.Card;
import com.stripe.model.PaymentSource;
import com.stripe.model.SetupIntent;
import com.stripe.model.SetupIntent.PaymentMethodOptions;
import com.stripe.model.Source;
import com.stripe.model.Source.AchDebit;
import com.stripe.model.Token;
import com.stripe.model.checkout.Session;

import static org.killbill.billing.plugin.stripe.StripePaymentPluginApi.PROPERTY_OVERRIDDEN_TRANSACTION_STATUS;

// Stripe .toJson() is definitively not GDPR-friendly...
public abstract class StripePluginProperties {

    public static Map toAdditionalDataMap(final PaymentSource stripePaymentSource) {
        final Map additionalDataMap = new HashMap();

        if (stripePaymentSource instanceof com.stripe.model.Card) {
            final com.stripe.model.Card card = (com.stripe.model.Card) stripePaymentSource;
            additionalDataMap.put("card_brand", card.getBrand());
            additionalDataMap.put("card_address_line1_check", card.getAddressLine1Check());
            additionalDataMap.put("card_address_postal_code_check", card.getAddressZipCheck());
            additionalDataMap.put("card_cvc_check", card.getCvcCheck());
            additionalDataMap.put("card_country", card.getCountry());
            additionalDataMap.put("card_description", card.getName());
            additionalDataMap.put("card_exp_month", card.getExpMonth());
            additionalDataMap.put("card_exp_year", card.getExpYear());
            additionalDataMap.put("card_fingerprint", card.getFingerprint());
            additionalDataMap.put("card_funding", card.getFunding());
            additionalDataMap.put("card_last4", card.getLast4());
        } else if (stripePaymentSource instanceof Source) {
            final Source stripeSource = (Source) stripePaymentSource;
            final Source.Card card = stripeSource.getCard();
            if (card != null) {
                additionalDataMap.put("card_brand", card.getBrand());
                additionalDataMap.put("card_address_line1_check", card.getAddressLine1Check());
                additionalDataMap.put("card_address_postal_code_check", card.getAddressZipCheck());
                additionalDataMap.put("card_cvc_check", card.getCvcCheck());
                additionalDataMap.put("card_country", card.getCountry());
                additionalDataMap.put("card_description", card.getName());
                additionalDataMap.put("card_exp_month", card.getExpMonth());
                additionalDataMap.put("card_exp_year", card.getExpYear());
                additionalDataMap.put("card_fingerprint", card.getFingerprint());
                additionalDataMap.put("card_funding", card.getFunding());
                additionalDataMap.put("card_last4", card.getLast4());
                additionalDataMap.put("card_three_d_secure_usage_support", card.getThreeDSecure());
            }
            final AchDebit achDebit = stripeSource.getAchDebit();
            if (achDebit != null) {
                additionalDataMap.put("ach_debit_bank_name", achDebit.getBankName());
                additionalDataMap.put("ach_debit_country", achDebit.getCountry());
                additionalDataMap.put("ach_debit_fingerprint", achDebit.getFingerprint());
                additionalDataMap.put("ach_debit_last4", achDebit.getLast4());
                additionalDataMap.put("ach_debit_routing_number", achDebit.getRoutingNumber());
                additionalDataMap.put("ach_debit_type", achDebit.getType());
            }
            final Source.SepaDebit sepaDebit = stripeSource.getSepaDebit();
            if (sepaDebit != null) {
                additionalDataMap.put("sepa_debit_bank_code", sepaDebit.getBankCode());
                additionalDataMap.put("sepa_debit_branch_code", sepaDebit.getBranchCode());
                additionalDataMap.put("sepa_debit_country", sepaDebit.getCountry());
                additionalDataMap.put("sepa_debit_fingerprint", sepaDebit.getFingerprint());
                additionalDataMap.put("sepa_debit_last4", sepaDebit.getLast4());
                additionalDataMap.put("sepa_debit_mandate_reference", sepaDebit.getMandateReference());
                additionalDataMap.put("sepa_debit_mandate_url", sepaDebit.getMandateUrl());
            }
            additionalDataMap.put("created", stripeSource.getCreated());
            additionalDataMap.put("customer_id", stripeSource.getCustomer());
            additionalDataMap.put("id", stripeSource.getId());
            additionalDataMap.put("livemode", stripeSource.getLivemode());
            additionalDataMap.put("metadata", stripeSource.getMetadata());
            additionalDataMap.put("object", stripeSource.getObject());
            additionalDataMap.put("type", stripeSource.getType());
        } else if (stripePaymentSource instanceof BankAccount) {
            final BankAccount stripeBankAccount = (BankAccount) stripePaymentSource;
            additionalDataMap.put("account_holder_type", stripeBankAccount.getAccountHolderType());
            additionalDataMap.put("bank_name", stripeBankAccount.getBankName());
            additionalDataMap.put("country", stripeBankAccount.getCountry());
            additionalDataMap.put("currency", stripeBankAccount.getCurrency());
            additionalDataMap.put("fingerprint", stripeBankAccount.getFingerprint());
            additionalDataMap.put("last4", stripeBankAccount.getLast4());
            additionalDataMap.put("routing_number", stripeBankAccount.getRoutingNumber());
            additionalDataMap.put("status", stripeBankAccount.getStatus());
            additionalDataMap.put("customer_id", stripeBankAccount.getCustomer());
            additionalDataMap.put("id", stripeBankAccount.getId());
            additionalDataMap.put("metadata", stripeBankAccount.getMetadata());
            additionalDataMap.put("object", stripeBankAccount.getObject());
        } else {
            throw new UnsupportedOperationException("Not yet supported: " + stripePaymentSource);
        }

        return additionalDataMap;
    }

    public static Map toAdditionalDataMap(final Token token) {
        if (token.getCard() != null) {
            return toAdditionalDataMap(token.getCard());
        } else if (token.getBankAccount() != null) {
            return toAdditionalDataMap(token.getBankAccount());
        } else {
            throw new UnsupportedOperationException("Not yet supported: " + token);
        }
    }

    public static Map toAdditionalDataMap(final PaymentMethod stripePaymentMethod) {
        final Map additionalDataMap = new HashMap();

        final Card card = stripePaymentMethod.getCard();
        if (card != null) {
            additionalDataMap.put("card_brand", card.getBrand());
            if (card.getChecks() != null) {
                additionalDataMap.put("card_address_line1_check", card.getChecks().getAddressLine1Check());
                additionalDataMap.put("card_address_postal_code_check", card.getChecks().getAddressPostalCodeCheck());
                additionalDataMap.put("card_cvc_check", card.getChecks().getCvcCheck());
            }
            additionalDataMap.put("card_country", card.getCountry());
            additionalDataMap.put("card_description", card.getDescription());
            additionalDataMap.put("card_exp_month", card.getExpMonth());
            additionalDataMap.put("card_exp_year", card.getExpYear());
            additionalDataMap.put("card_fingerprint", card.getFingerprint());
            additionalDataMap.put("card_funding", card.getFunding());
            additionalDataMap.put("card_iin", card.getIin());
            additionalDataMap.put("card_issuer", card.getIssuer());
            additionalDataMap.put("card_last4", card.getLast4());
            if (card.getThreeDSecureUsage() != null) {
                additionalDataMap.put("card_three_d_secure_usage_support", card.getThreeDSecureUsage().getSupported());
            }
            if (card.getWallet() != null) {
                additionalDataMap.put("card_wallet_type", card.getWallet().getType());
            }
        }
        final PaymentMethod.SepaDebit sepaDebit = stripePaymentMethod.getSepaDebit();
        if (sepaDebit != null) {
            additionalDataMap.put("sepa_debit_bank_code", sepaDebit.getBankCode());
            additionalDataMap.put("sepa_debit_branch_code", sepaDebit.getBranchCode());
            additionalDataMap.put("sepa_debit_country", sepaDebit.getCountry());
            additionalDataMap.put("sepa_debit_fingerprint", sepaDebit.getFingerprint());
            additionalDataMap.put("sepa_debit_last4", sepaDebit.getLast4());
        }

        additionalDataMap.put("created", stripePaymentMethod.getCreated());
        additionalDataMap.put("customer_id", stripePaymentMethod.getCustomer());
        additionalDataMap.put("id", stripePaymentMethod.getId());
        additionalDataMap.put("livemode", stripePaymentMethod.getLivemode());
        additionalDataMap.put("metadata", stripePaymentMethod.getMetadata());
        additionalDataMap.put("object", stripePaymentMethod.getObject());
        additionalDataMap.put("type", stripePaymentMethod.getType());

        return additionalDataMap;
    }

    public static Map toAdditionalDataMap(final StripeException stripeException) {
        final Map additionalDataMap = new HashMap();

        if (stripeException.getStripeError() != null) {
            // See StripePaymentTransactionInfoPlugin#getGatewayError
            additionalDataMap.put("stripe_error_message", stripeException.getStripeError().getMessage());
            // See StripePaymentTransactionInfoPlugin#getGatewayErrorCode
            additionalDataMap.put("stripe_error_code", stripeException.getStripeError().getCode());
        }
        additionalDataMap.put("code", stripeException.getCode());
        additionalDataMap.put("request_id", stripeException.getRequestId());
        additionalDataMap.put("status_code", stripeException.getStatusCode());
        additionalDataMap.put("message", stripeException.getMessage());

        additionalDataMap.put(PROPERTY_OVERRIDDEN_TRANSACTION_STATUS, mapExceptionToCallResult(stripeException).toString());

        return additionalDataMap;
    }


    /**
     * Educated guess approach to transform exceptions into error status codes.
     */
    private static PaymentPluginStatus mapExceptionToCallResult(final Exception e) {
        //noinspection ThrowableResultOfMethodCallIgnored
        final Throwable rootCause = Throwables.getRootCause(e);
        final String errorMessage = rootCause.getMessage();
        if (rootCause instanceof ConnectException) {
            return PaymentPluginStatus.CANCELED;
        } else if (rootCause instanceof SocketTimeoutException) {
            // read timeout
            if (errorMessage.contains("Read timed out")) {
                return PaymentPluginStatus.UNDEFINED;
            } else if (errorMessage.contains("Unexpected end of file from server")) {
                return PaymentPluginStatus.UNDEFINED;
            }
        } else if (rootCause instanceof SocketException) {
            if (errorMessage.contains("Unexpected end of file from server")) {
                return PaymentPluginStatus.UNDEFINED;
            }
        } else if (rootCause instanceof UnknownHostException) {
            return PaymentPluginStatus.CANCELED;
        } else if (rootCause instanceof IOException) {
            if (errorMessage.contains("Invalid Http response")) {
                // unparsable data as response
                return PaymentPluginStatus.UNDEFINED;
            } else if (errorMessage.contains("Bogus chunk size")) {
                return PaymentPluginStatus.UNDEFINED;
            }
        }

        return PaymentPluginStatus.UNDEFINED;
    }

    public static Map toAdditionalDataMap(final PaymentIntent stripePaymentIntent, @Nullable final Charge lastCharge) {
        final Map additionalDataMap = new HashMap();

        additionalDataMap.put("amount", stripePaymentIntent.getAmount());
        additionalDataMap.put("amount_capturable", stripePaymentIntent.getAmountCapturable());
        additionalDataMap.put("amount_received", stripePaymentIntent.getAmountReceived());
        additionalDataMap.put("application", stripePaymentIntent.getApplication());
        additionalDataMap.put("application_fee_amount", stripePaymentIntent.getApplicationFeeAmount());
        additionalDataMap.put("canceled_at", stripePaymentIntent.getCanceledAt());
        additionalDataMap.put("cancellation_reason", stripePaymentIntent.getCancellationReason());
        additionalDataMap.put("capture_method", stripePaymentIntent.getCaptureMethod());
        additionalDataMap.put("confirmation_method", stripePaymentIntent.getConfirmationMethod());
        additionalDataMap.put("created", stripePaymentIntent.getCreated());
        additionalDataMap.put("currency", stripePaymentIntent.getCurrency());
        additionalDataMap.put("customer_id", stripePaymentIntent.getCustomer());
        additionalDataMap.put("description", stripePaymentIntent.getDescription());
        additionalDataMap.put("id", stripePaymentIntent.getId());
        additionalDataMap.put("invoice_id", stripePaymentIntent.getInvoice());
        additionalDataMap.put("last_payment_error", stripePaymentIntent.getLastPaymentError());
        additionalDataMap.put("livemode", stripePaymentIntent.getLivemode());
        additionalDataMap.put("metadata", stripePaymentIntent.getMetadata());
        additionalDataMap.put("next_action", stripePaymentIntent.getNextAction());
        additionalDataMap.put("object", stripePaymentIntent.getObject());
        additionalDataMap.put("on_behalf_of", stripePaymentIntent.getOnBehalfOf());
        additionalDataMap.put("payment_method_id", stripePaymentIntent.getPaymentMethod());
        additionalDataMap.put("payment_method_types", stripePaymentIntent.getPaymentMethodTypes());
        additionalDataMap.put("review_id", stripePaymentIntent.getReview());
        additionalDataMap.put("statement_descriptor", stripePaymentIntent.getStatementDescriptor());
        additionalDataMap.put("status", stripePaymentIntent.getStatus());
        additionalDataMap.put("transfer_group", stripePaymentIntent.getTransferGroup());

        if (lastCharge != null) {
            // Keep the state for the last charge (maps to our payment transaction)
            additionalDataMap.put("last_charge_amount", lastCharge.getAmount());
            additionalDataMap.put("last_charge_authorization_code", lastCharge.getAuthorizationCode());
            additionalDataMap.put("last_charge_balance_transaction_id", lastCharge.getBalanceTransaction());
            additionalDataMap.put("last_charge_created", lastCharge.getCreated());
            additionalDataMap.put("last_charge_currency", lastCharge.getCurrency());
            additionalDataMap.put("last_charge_description", lastCharge.getDescription());
            additionalDataMap.put("last_charge_failure_code", lastCharge.getFailureCode());
            additionalDataMap.put("last_charge_failure_message", lastCharge.getFailureMessage());
            additionalDataMap.put("last_charge_id", lastCharge.getId());
            additionalDataMap.put("last_charge_metadata", lastCharge.getMetadata());
            additionalDataMap.put("last_charge_object", lastCharge.getObject());
            additionalDataMap.put("last_charge_outcome", lastCharge.getOutcome());
            additionalDataMap.put("last_charge_paid", lastCharge.getPaid());
            additionalDataMap.put("last_charge_payment_method_id", lastCharge.getPaymentMethod());
            if (lastCharge.getPaymentMethodDetails() != null) {
                additionalDataMap.put("last_charge_payment_method_type", lastCharge.getPaymentMethodDetails().getType());
            }
            additionalDataMap.put("last_charge_statement_descriptor", lastCharge.getStatementDescriptor());
            additionalDataMap.put("last_charge_status", lastCharge.getStatus());
        }

        return additionalDataMap;
    }

    public static Map toAdditionalDataMap(final SetupIntent stripeSetupIntent) {
        final Map additionalDataMap = new HashMap();

        additionalDataMap.put("application", stripeSetupIntent.getApplication());
        additionalDataMap.put("cancellation_reason", stripeSetupIntent.getCancellationReason());
        additionalDataMap.put("created", stripeSetupIntent.getCreated());
        additionalDataMap.put("customer_id", stripeSetupIntent.getCustomer());
        additionalDataMap.put("description", stripeSetupIntent.getDescription());
        additionalDataMap.put("id", stripeSetupIntent.getId());
        additionalDataMap.put("last_setup_error", stripeSetupIntent.getLastSetupError());
        additionalDataMap.put("latest_attempt", stripeSetupIntent.getLatestAttempt());
        additionalDataMap.put("livemode", stripeSetupIntent.getLivemode());
        additionalDataMap.put("mandate", stripeSetupIntent.getMandate());
        additionalDataMap.put("metadata", stripeSetupIntent.getMetadata());
        additionalDataMap.put("next_action", stripeSetupIntent.getNextAction());
        additionalDataMap.put("object", stripeSetupIntent.getObject());
        additionalDataMap.put("on_behalf_of", stripeSetupIntent.getOnBehalfOf());
        additionalDataMap.put("payment_method_id", stripeSetupIntent.getPaymentMethod());
        final PaymentMethodOptions paymentMethodOptions = stripeSetupIntent.getPaymentMethodOptions();
        if (paymentMethodOptions != null ) {
            final SetupIntent.PaymentMethodOptions.Card card = paymentMethodOptions.getCard();
            if (card != null) {
                additionalDataMap.put("payment_method_options_card_request_three_d_secure", card.getRequestThreeDSecure());
            }
            // paymentMethodOptions also contains "sepa_debit" which contains "mandate_options" that currently has
            // no properties, so it is ignored here (https://stripe.com/docs/api/setup_intents/object)
        }
        additionalDataMap.put("payment_method_types", stripeSetupIntent.getPaymentMethodTypes());
        additionalDataMap.put("single_use_mandate_id", stripeSetupIntent.getSingleUseMandate());
        additionalDataMap.put("status", stripeSetupIntent.getStatus());
        additionalDataMap.put("usage", stripeSetupIntent.getUsage());

        return additionalDataMap;
    }

    public static Map toAdditionalDataMap(final Session session, @Nullable final String pk) {
        final Map additionalDataMap = new HashMap();

        additionalDataMap.put("billing_address_collection", session.getBillingAddressCollection());
        additionalDataMap.put("cancel_url", session.getCancelUrl());
        additionalDataMap.put("client_reference_id", session.getClientReferenceId());
        additionalDataMap.put("customer_id", session.getCustomer());
        additionalDataMap.put("line_items", session.getLineItems());
        additionalDataMap.put("id", session.getId());
        additionalDataMap.put("livemode", session.getLivemode());
        additionalDataMap.put("locale", session.getLocale());
        additionalDataMap.put("object", session.getObject());
        additionalDataMap.put("payment_intent_id", session.getPaymentIntent());
        additionalDataMap.put("payment_method_types", session.getPaymentMethodTypes());
        additionalDataMap.put("setup_intent_id", session.getSetupIntent());
        additionalDataMap.put("subscription_id", session.getSubscription());
        additionalDataMap.put("success_url", session.getSuccessUrl());
        if (pk != null) {
            additionalDataMap.put("publishable_key", pk);
        }

        return additionalDataMap;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy