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

org.killbill.billing.plugin.stripe.dao.StripeDao 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.dao;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Nullable;
import javax.sql.DataSource;

import org.joda.time.DateTime;
import org.jooq.DSLContext;
import org.jooq.impl.DSL;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.plugin.api.PluginProperties;
import org.killbill.billing.plugin.dao.payment.PluginPaymentDao;

import com.fasterxml.jackson.annotation.JsonInclude.Include;

import org.killbill.billing.plugin.stripe.StripePluginProperties;
import org.killbill.billing.plugin.stripe.dao.gen.tables.StripePaymentMethods;
import org.killbill.billing.plugin.stripe.dao.gen.tables.StripeResponses;
import org.killbill.billing.plugin.stripe.dao.gen.tables.records.StripeHppRequestsRecord;
import org.killbill.billing.plugin.stripe.dao.gen.tables.records.StripePaymentMethodsRecord;
import org.killbill.billing.plugin.stripe.dao.gen.tables.records.StripeResponsesRecord;

import com.stripe.exception.StripeException;
import com.stripe.model.Charge;
import com.stripe.model.PaymentIntent;
import com.stripe.model.checkout.Session;

import static org.killbill.billing.plugin.stripe.dao.gen.tables.StripeHppRequests.STRIPE_HPP_REQUESTS;
import static org.killbill.billing.plugin.stripe.dao.gen.tables.StripePaymentMethods.STRIPE_PAYMENT_METHODS;
import static org.killbill.billing.plugin.stripe.dao.gen.tables.StripeResponses.STRIPE_RESPONSES;

public class StripeDao extends PluginPaymentDao {

    public StripeDao(final DataSource dataSource) throws SQLException {
        super(STRIPE_RESPONSES, STRIPE_PAYMENT_METHODS, dataSource);
        // Save space in the database
        objectMapper.setSerializationInclusion(Include.NON_EMPTY);
    }

    // Payment methods

    public void addPaymentMethod(final UUID kbAccountId,
                                 final UUID kbPaymentMethodId,
                                 final Map additionalDataMap,
                                 final String stripeId,
                                 final DateTime utcNow,
                                 final UUID kbTenantId) throws SQLException {
        execute(dataSource.getConnection(),
                new WithConnectionCallback() {
                    @Override
                    public StripeResponsesRecord withConnection(final Connection conn) throws SQLException {
                        DSL.using(conn, dialect, settings)
                           .insertInto(STRIPE_PAYMENT_METHODS,
                                       STRIPE_PAYMENT_METHODS.KB_ACCOUNT_ID,
                                       STRIPE_PAYMENT_METHODS.KB_PAYMENT_METHOD_ID,
                                       STRIPE_PAYMENT_METHODS.STRIPE_ID,
                                       STRIPE_PAYMENT_METHODS.IS_DELETED,
                                       STRIPE_PAYMENT_METHODS.ADDITIONAL_DATA,
                                       STRIPE_PAYMENT_METHODS.CREATED_DATE,
                                       STRIPE_PAYMENT_METHODS.UPDATED_DATE,
                                       STRIPE_PAYMENT_METHODS.KB_TENANT_ID)
                           .values(kbAccountId.toString(),
                                   kbPaymentMethodId.toString(),
                                   stripeId,
                                   (short) FALSE,
                                   asString(additionalDataMap),
                                   toLocalDateTime(utcNow),
                                   toLocalDateTime(utcNow),
                                   kbTenantId.toString()
                                   )
                           .execute();

                        return null;
                    }
                });
    }

    public void updatePaymentMethod(final UUID kbPaymentMethodId,
                                    final Map additionalDataMap,
                                    final String stripeId,
                                    final DateTime utcNow,
                                    final UUID kbTenantId) throws SQLException {
        execute(dataSource.getConnection(),
                new WithConnectionCallback() {
                    @Override
                    public StripeResponsesRecord withConnection(final Connection conn) throws SQLException {
                        DSL.using(conn, dialect, settings)
                           .update(STRIPE_PAYMENT_METHODS)
                           .set(STRIPE_PAYMENT_METHODS.ADDITIONAL_DATA, asString(additionalDataMap))
                           .set(STRIPE_PAYMENT_METHODS.UPDATED_DATE, toLocalDateTime(utcNow))
                           .where(STRIPE_PAYMENT_METHODS.KB_PAYMENT_METHOD_ID.equal(kbPaymentMethodId.toString()))
                           .and(STRIPE_PAYMENT_METHODS.STRIPE_ID.equal(stripeId))
                           .and(STRIPE_PAYMENT_METHODS.KB_TENANT_ID.equal(kbTenantId.toString()))
                           .execute();
                        return null;
                    }
                });
    }

    // HPP requests

    public void addHppRequest(final UUID kbAccountId,
                              final UUID kbPaymentId,
                              final UUID kbPaymentTransactionId,
                              final Session stripeSession,
                              final DateTime utcNow,
                              final UUID kbTenantId) throws SQLException {
        final Map additionalDataMap = StripePluginProperties.toAdditionalDataMap(stripeSession, null);

        execute(dataSource.getConnection(),
                new WithConnectionCallback() {
                    @Override
                    public Void withConnection(final Connection conn) throws SQLException {
                        DSL.using(conn, dialect, settings)
                           .insertInto(STRIPE_HPP_REQUESTS,
                                       STRIPE_HPP_REQUESTS.KB_ACCOUNT_ID,
                                       STRIPE_HPP_REQUESTS.KB_PAYMENT_ID,
                                       STRIPE_HPP_REQUESTS.KB_PAYMENT_TRANSACTION_ID,
                                       STRIPE_HPP_REQUESTS.SESSION_ID,
                                       STRIPE_HPP_REQUESTS.ADDITIONAL_DATA,
                                       STRIPE_HPP_REQUESTS.CREATED_DATE,
                                       STRIPE_HPP_REQUESTS.KB_TENANT_ID)
                           .values(kbAccountId.toString(),
                                   kbPaymentId == null ? null : kbPaymentId.toString(),
                                   kbPaymentTransactionId == null ? null : kbPaymentTransactionId.toString(),
                                   stripeSession.getId(),
                                   asString(additionalDataMap),
                                   toLocalDateTime(utcNow),
                                   kbTenantId.toString())
                           .execute();
                        return null;
                    }
                });
    }

    public StripeHppRequestsRecord getHppRequest(final String sessionId,
                                                 final String kbTenantId) throws SQLException {
        return execute(dataSource.getConnection(),
                       new WithConnectionCallback() {
                           @Override
                           public StripeHppRequestsRecord withConnection(final Connection conn) throws SQLException {
                               return DSL.using(conn, dialect, settings)
                                         .selectFrom(STRIPE_HPP_REQUESTS)
                                         .where(STRIPE_HPP_REQUESTS.SESSION_ID.equal(sessionId))
                                         .and(STRIPE_HPP_REQUESTS.KB_TENANT_ID.equal(kbTenantId))
                                         .orderBy(STRIPE_HPP_REQUESTS.RECORD_ID.desc())
                                         .limit(1)
                                         .fetchOne();
                           }
                       });
    }

    // Responses

    public StripeResponsesRecord addResponse(final UUID kbAccountId,
                                             final UUID kbPaymentId,
                                             final UUID kbPaymentTransactionId,
                                             final TransactionType transactionType,
                                             final BigDecimal amount,
                                             final Currency currency,
                                             @Nullable final PaymentIntent stripePaymentIntent,
                                             @Nullable final Charge lastCharge,
                                             @Nullable final StripeException stripeException,
                                             final DateTime utcNow,
                                             final UUID kbTenantId) throws SQLException {
        final Map additionalDataMap;
        if (stripePaymentIntent != null) {
            additionalDataMap = StripePluginProperties.toAdditionalDataMap(stripePaymentIntent, lastCharge);
        } else if (stripeException != null) {
            additionalDataMap = StripePluginProperties.toAdditionalDataMap(stripeException);
        } else {
            additionalDataMap = Collections.emptyMap();
        }

        return execute(dataSource.getConnection(),
                       conn -> DSL.using(conn, dialect, settings).transactionResult(configuration -> {
                           final DSLContext dslContext = DSL.using(configuration);
                           dslContext.insertInto(STRIPE_RESPONSES,
                                                 STRIPE_RESPONSES.KB_ACCOUNT_ID,
                                                 STRIPE_RESPONSES.KB_PAYMENT_ID,
                                                 STRIPE_RESPONSES.KB_PAYMENT_TRANSACTION_ID,
                                                 STRIPE_RESPONSES.TRANSACTION_TYPE,
                                                 STRIPE_RESPONSES.AMOUNT,
                                                 STRIPE_RESPONSES.CURRENCY,
                                                 STRIPE_RESPONSES.STRIPE_ID,
                                                 STRIPE_RESPONSES.ADDITIONAL_DATA,
                                                 STRIPE_RESPONSES.CREATED_DATE,
                                                 STRIPE_RESPONSES.KB_TENANT_ID)
                              .values(kbAccountId.toString(),
                                      kbPaymentId.toString(),
                                      kbPaymentTransactionId.toString(),
                                      transactionType.toString(),
                                      amount,
                                      currency == null ? null : currency.name(),
                                      stripePaymentIntent == null ? null : stripePaymentIntent.getId(),
                                      asString(additionalDataMap),
                                      toLocalDateTime(utcNow),
                                      kbTenantId.toString())
                              .execute();
                           return dslContext.fetchOne(
                                   STRIPE_RESPONSES,
                                   STRIPE_RESPONSES.RECORD_ID.eq(STRIPE_RESPONSES.RECORD_ID.getDataType().convert(dslContext.lastID())));
                       }));
    }

    public StripeResponsesRecord updateResponse(final UUID kbPaymentTransactionId,
                                                final PaymentIntent stripePaymentIntent,
                                                @Nullable final Charge lastCharge,
                                                final UUID kbTenantId) throws SQLException {
        final Map additionalDataMap = StripePluginProperties.toAdditionalDataMap(stripePaymentIntent, lastCharge);
        return updateResponse(kbPaymentTransactionId, additionalDataMap, kbTenantId);
    }

    public StripeResponsesRecord updateResponse(final UUID kbPaymentTransactionId,
                                                final Iterable additionalPluginProperties,
                                                final UUID kbTenantId) throws SQLException {
        final Map additionalProperties = PluginProperties.toMap(additionalPluginProperties);
        return updateResponse(kbPaymentTransactionId, additionalProperties, kbTenantId);
    }

    public StripeResponsesRecord updateResponse(final UUID kbPaymentTransactionId,
                                                final Map additionalProperties,
                                                final UUID kbTenantId) throws SQLException {
        return execute(dataSource.getConnection(),
                       new WithConnectionCallback() {
                           @Override
                           public StripeResponsesRecord withConnection(final Connection conn) throws SQLException {
                               final StripeResponsesRecord response = DSL.using(conn, dialect, settings)
                                                                         .selectFrom(STRIPE_RESPONSES)
                                                                         .where(STRIPE_RESPONSES.KB_PAYMENT_TRANSACTION_ID.equal(kbPaymentTransactionId.toString()))
                                                                         .and(STRIPE_RESPONSES.KB_TENANT_ID.equal(kbTenantId.toString()))
                                                                         .orderBy(STRIPE_RESPONSES.RECORD_ID.desc())
                                                                         .limit(1)
                                                                         .fetchOne();

                               if (response == null) {
                                   return null;
                               }

                               final Map originalData = new HashMap(fromAdditionalData(response.getAdditionalData()));
                               originalData.putAll(additionalProperties);

                               DSL.using(conn, dialect, settings)
                                  .update(STRIPE_RESPONSES)
                                  .set(STRIPE_RESPONSES.ADDITIONAL_DATA, asString(originalData))
                                  .where(STRIPE_RESPONSES.RECORD_ID.equal(response.getRecordId()))
                                  .execute();
                               return response;
                           }
                       });
    }

    public void updateResponse(final StripeResponsesRecord stripeResponsesRecord,
                               final Map additionalMetadata) throws SQLException {
        final Map additionalDataMap = fromAdditionalData(stripeResponsesRecord.getAdditionalData());
        additionalDataMap.putAll(additionalMetadata);

        execute(dataSource.getConnection(),
                new WithConnectionCallback() {
                    @Override
                    public Void withConnection(final Connection conn) throws SQLException {
                        DSL.using(conn, dialect, settings)
                           .update(STRIPE_RESPONSES)
                           .set(STRIPE_RESPONSES.ADDITIONAL_DATA, asString(additionalDataMap))
                           .where(STRIPE_RESPONSES.RECORD_ID.equal(stripeResponsesRecord.getRecordId()))
                           .execute();
                        return null;
                    }
                });
    }

    @Override
    public StripeResponsesRecord getSuccessfulAuthorizationResponse(final UUID kbPaymentId, final UUID kbTenantId) throws SQLException {
        return execute(dataSource.getConnection(),
                       new WithConnectionCallback() {
                           @Override
                           public StripeResponsesRecord withConnection(final Connection conn) throws SQLException {
                               return DSL.using(conn, dialect, settings)
                                         .selectFrom(responsesTable)
                                         .where(DSL.field(responsesTable.getName() + "." + KB_PAYMENT_ID).equal(kbPaymentId.toString()))
                                         .and(
                                                 DSL.field(responsesTable.getName() + "." + TRANSACTION_TYPE).equal(TransactionType.AUTHORIZE.toString())
                                                    .or(DSL.field(responsesTable.getName() + "." + TRANSACTION_TYPE).equal(TransactionType.PURCHASE.toString()))
                                             )
                                         .and(DSL.field(responsesTable.getName() + "." + KB_TENANT_ID).equal(kbTenantId.toString()))
                                         .orderBy(DSL.field(responsesTable.getName() + "." + RECORD_ID).desc())
                                         .limit(1)
                                         .fetchOne();
                           }
                       });
    }

    public static Map fromAdditionalData(@Nullable final String additionalData) {
        if (additionalData == null) {
            return Collections.emptyMap();
        }

        try {
            return objectMapper.readValue(additionalData, Map.class);
        } catch (final IOException e) {
            throw new RuntimeException(e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy