private Payment toPayment( final PaymentModelDao paymentModelDao, @Nullable final Iterable<PaymentTransactionInfoPlugin> pluginTransactions, final InternalTenantContext tenantContext) { final InternalTenantContext tenantContextWithAccountRecordId = getInternalTenantContextWithAccountRecordId(paymentModelDao.getAccountId(), tenantContext); final List<PaymentTransactionModelDao> transactionsForPayment = paymentDao.getTransactionsForPayment( paymentModelDao.getId(), tenantContextWithAccountRecordId); return toPayment(paymentModelDao, transactionsForPayment, pluginTransactions, tenantContext); }
private List<PaymentTransactionInfoPlugin> getPaymentTransactionInfoPlugins( final PaymentPluginApi plugin, final PaymentModelDao paymentModelDao, final Iterable<PluginProperty> properties, final TenantContext context) throws PaymentApiException { try { return plugin.getPaymentInfo( paymentModelDao.getAccountId(), paymentModelDao.getId(), properties, context); } catch (final PaymentPluginApiException e) { throw new PaymentApiException( ErrorCode.PAYMENT_PLUGIN_GET_PAYMENT_INFO, paymentModelDao.getId(), e.toString()); } }
// Used in single get APIs (getPayment / getPaymentByExternalKey) private Payment toPayment( final PaymentModelDao paymentModelDao, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext context, final InternalTenantContext tenantContext) throws PaymentApiException { final PaymentPluginApi plugin = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), tenantContext); final List<PaymentTransactionInfoPlugin> pluginTransactions = withPluginInfo ? getPaymentTransactionInfoPlugins(plugin, paymentModelDao, properties, context) : null; return toPayment(paymentModelDao, pluginTransactions, tenantContext); }
// Used in bulk get API (getAccountPayments / getPayments) private List<PaymentTransactionInfoPlugin> getPaymentTransactionInfoPluginsIfNeeded( @Nullable final PaymentPluginApi pluginApi, final PaymentModelDao paymentModelDao, final TenantContext context) { if (pluginApi == null) { return null; } try { return getPaymentTransactionInfoPlugins( pluginApi, paymentModelDao, PLUGIN_PROPERTIES, context); } catch (final PaymentApiException e) { log.warn("Unable to retrieve plugin info for payment " + paymentModelDao.getId()); return null; } }
// Used in bulk get API (getAccountPayments) private Payment toPayment( final PaymentModelDao curPaymentModelDao, final Iterable<PaymentTransactionModelDao> curTransactionsModelDao, @Nullable final Iterable<PaymentTransactionInfoPlugin> pluginTransactions, final InternalTenantContext internalTenantContext) { final Ordering<PaymentTransaction> perPaymentTransactionOrdering = Ordering.<PaymentTransaction>from( new Comparator<PaymentTransaction>() { @Override public int compare(final PaymentTransaction o1, final PaymentTransaction o2) { return o1.getEffectiveDate().compareTo(o2.getEffectiveDate()); } }); // Need to filter for optimized codepaths looking up by account_record_id final Iterable<PaymentTransactionModelDao> filteredTransactions = Iterables.filter( curTransactionsModelDao, new Predicate<PaymentTransactionModelDao>() { @Override public boolean apply(final PaymentTransactionModelDao curPaymentTransactionModelDao) { return curPaymentTransactionModelDao .getPaymentId() .equals(curPaymentModelDao.getId()); } }); PaymentModelDao newPaymentModelDao = curPaymentModelDao; final Collection<PaymentTransaction> transactions = new LinkedList<PaymentTransaction>(); for (final PaymentTransactionModelDao curPaymentTransactionModelDao : filteredTransactions) { PaymentTransactionModelDao newPaymentTransactionModelDao = curPaymentTransactionModelDao; final PaymentTransactionInfoPlugin paymentTransactionInfoPlugin = findPaymentTransactionInfoPlugin(newPaymentTransactionModelDao, pluginTransactions); if (paymentTransactionInfoPlugin != null) { // Make sure to invoke the Janitor task in case the plugin fixes its state on the fly // See https://github.com/killbill/killbill/issues/341 final boolean hasChanged = incompletePaymentTransactionTask.updatePaymentAndTransactionIfNeededWithAccountLock( newPaymentModelDao, newPaymentTransactionModelDao, paymentTransactionInfoPlugin, internalTenantContext); if (hasChanged) { newPaymentModelDao = paymentDao.getPayment(newPaymentModelDao.getId(), internalTenantContext); newPaymentTransactionModelDao = paymentDao.getPaymentTransaction( newPaymentTransactionModelDao.getId(), internalTenantContext); } } final PaymentTransaction transaction = new DefaultPaymentTransaction( newPaymentTransactionModelDao.getId(), newPaymentTransactionModelDao.getAttemptId(), newPaymentTransactionModelDao.getTransactionExternalKey(), newPaymentTransactionModelDao.getCreatedDate(), newPaymentTransactionModelDao.getUpdatedDate(), newPaymentTransactionModelDao.getPaymentId(), newPaymentTransactionModelDao.getTransactionType(), newPaymentTransactionModelDao.getEffectiveDate(), newPaymentTransactionModelDao.getTransactionStatus(), newPaymentTransactionModelDao.getAmount(), newPaymentTransactionModelDao.getCurrency(), newPaymentTransactionModelDao.getProcessedAmount(), newPaymentTransactionModelDao.getProcessedCurrency(), newPaymentTransactionModelDao.getGatewayErrorCode(), newPaymentTransactionModelDao.getGatewayErrorMsg(), paymentTransactionInfoPlugin); transactions.add(transaction); } final List<PaymentTransaction> sortedTransactions = perPaymentTransactionOrdering.immutableSortedCopy(transactions); return new DefaultPayment( curPaymentModelDao.getId(), curPaymentModelDao.getCreatedDate(), curPaymentModelDao.getUpdatedDate(), curPaymentModelDao.getAccountId(), curPaymentModelDao.getPaymentMethodId(), curPaymentModelDao.getPaymentNumber(), curPaymentModelDao.getExternalKey(), sortedTransactions); }
public DefaultPayment( final PaymentModelDao src, @Nullable final PaymentInfoPlugin paymentPluginInfo, final List<PaymentAttemptModelDao> attempts, final List<RefundModelDao> refunds) { this( src.getId(), src.getCreatedDate(), src.getUpdatedDate(), src.getAccountId(), src.getInvoiceId(), src.getPaymentMethodId(), src.getAmount(), toPaidAmount(src.getPaymentStatus(), src.getAmount(), refunds), src.getCurrency(), src.getEffectiveDate(), src.getPaymentNumber(), src.getPaymentStatus(), paymentPluginInfo, toPaymentAttempts(attempts)); }
@Override public void leavingState(final State state) throws OperationException { final DateTime utcNow = pluginControlPaymentAutomatonRunner.getClock().getUTCNow(); // Retrieve the associated payment transaction, if any PaymentTransactionModelDao paymentTransactionModelDaoCandidate = null; if (stateContext.getTransactionId() != null) { paymentTransactionModelDaoCandidate = paymentDao.getPaymentTransaction( stateContext.getTransactionId(), stateContext.getInternalCallContext()); Preconditions.checkNotNull( paymentTransactionModelDaoCandidate, "paymentTransaction cannot be null for id " + stateContext.getTransactionId()); } else if (stateContext.getPaymentTransactionExternalKey() != null) { final List<PaymentTransactionModelDao> paymentTransactionModelDaos = paymentDao.getPaymentTransactionsByExternalKey( stateContext.getPaymentTransactionExternalKey(), stateContext.getInternalCallContext()); if (!paymentTransactionModelDaos.isEmpty()) { paymentTransactionModelDaoCandidate = paymentTransactionModelDaos.get(paymentTransactionModelDaos.size() - 1); } } final PaymentTransactionModelDao paymentTransactionModelDao = paymentTransactionModelDaoCandidate != null && TRANSIENT_TRANSACTION_STATUSES.contains( paymentTransactionModelDaoCandidate.getTransactionStatus()) ? paymentTransactionModelDaoCandidate : null; if (stateContext.getPaymentId() != null && stateContext.getPaymentExternalKey() == null) { final PaymentModelDao payment = paymentDao.getPayment(stateContext.getPaymentId(), stateContext.getInternalCallContext()); Preconditions.checkNotNull( payment, "payment cannot be null for id " + stateContext.getPaymentId()); stateContext.setPaymentExternalKey(payment.getExternalKey()); stateContext.setPaymentMethodId(payment.getPaymentMethodId()); } else if (stateContext.getPaymentExternalKey() == null) { stateContext.setPaymentExternalKey(UUIDs.randomUUID().toString()); } if (paymentTransactionModelDao != null) { stateContext.setPaymentTransactionExternalKey( paymentTransactionModelDao.getTransactionExternalKey()); } else if (stateContext.getPaymentTransactionExternalKey() == null) { stateContext.setPaymentTransactionExternalKey(UUIDs.randomUUID().toString()); } if (stateContext.getPaymentMethodId() == null) { // Similar logic in PaymentAutomatonRunner stateContext.setPaymentMethodId(stateContext.getAccount().getPaymentMethodId()); } if (state.getName().equals(initialState.getName()) || state.getName().equals(retriedState.getName())) { try { final PaymentAttemptModelDao attempt; if (paymentTransactionModelDao != null && paymentTransactionModelDao.getAttemptId() != null) { attempt = pluginControlPaymentAutomatonRunner .getPaymentDao() .getPaymentAttempt( paymentTransactionModelDao.getAttemptId(), stateContext.getInternalCallContext()); Preconditions.checkNotNull( attempt, "attempt cannot be null for id " + paymentTransactionModelDao.getAttemptId()); } else { // // We don't serialize any properties at this stage to avoid serializing sensitive // information. // However, if after going through the control plugins, the attempt end up in RETRIED // state, // the properties will be serialized in the enteringState callback (any plugin that sets a // retried date is responsible to correctly remove sensitive information such as CVV, ...) // final byte[] serializedProperties = PluginPropertySerializer.serialize(ImmutableList.<PluginProperty>of()); attempt = new PaymentAttemptModelDao( stateContext.getAccount().getId(), stateContext.getPaymentMethodId(), utcNow, utcNow, stateContext.getPaymentExternalKey(), stateContext.getTransactionId(), stateContext.getPaymentTransactionExternalKey(), transactionType, initialState.getName(), stateContext.getAmount(), stateContext.getCurrency(), stateContext.getPaymentControlPluginNames(), serializedProperties); pluginControlPaymentAutomatonRunner .getPaymentDao() .insertPaymentAttemptWithProperties(attempt, stateContext.getInternalCallContext()); } stateContext.setAttemptId(attempt.getId()); } catch (final PluginPropertySerializerException e) { throw new OperationException(e); } } }