killbill-aplcache
Changes
payment/src/main/java/org/killbill/billing/payment/control/InvoicePaymentControlPluginApi.java 78(+50 -28)
payment/src/main/java/org/killbill/billing/payment/core/PluginControlledPaymentProcessor.java 52(+41 -11)
payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentAutomatonRunner.java 7(+7 -0)
payment/src/main/java/org/killbill/billing/payment/core/sm/PluginControlledDirectPaymentAutomatonRunner.java 24(+5 -19)
payment/src/main/java/org/killbill/billing/payment/core/sm/RetryableDirectPaymentStateContext.java 12(+2 -10)
Details
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ChargebackResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ChargebackResource.java
index 55615cb..0546cff 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ChargebackResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ChargebackResource.java
@@ -73,6 +73,7 @@ public class ChargebackResource extends JaxRsResourceBase {
super(uriBuilder, tagUserApi, customFieldUserApi, auditUserApi, accountUserApi, paymentApi, clock, context);
}
+ // STEPH API needs to be discussed
@POST
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@@ -86,8 +87,8 @@ public class ChargebackResource extends JaxRsResourceBase {
final CallContext callContext = context.createContext(createdBy, reason, comment, request);
final Account account = accountUserApi.getAccountById(UUID.fromString(json.getAccountId()), callContext);
- final DirectPayment payment = paymentApi.notifyChargeback(account, UUID.fromString(json.getChargedBackTransactionId()), json.getChargedBackTransactionId(), json.getAmount(),
- Currency.valueOf(json.getCurrency()), callContext);
+ final DirectPayment payment = paymentApi.notifyChargebackWithPaymentControl(account, UUID.fromString(json.getChargedBackTransactionId()), json.getChargedBackTransactionId(), json.getAmount(),
+ Currency.valueOf(json.getCurrency()), createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
return uriBuilder.buildResponse(uriInfo, DirectPaymentResource.class, "getDirectPayment", payment.getId());
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPaymentApi.java
index 4f79e19..8edb561 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPaymentApi.java
@@ -37,8 +37,6 @@ import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.callcontext.TenantContext;
import org.killbill.billing.util.entity.Pagination;
-import com.google.common.base.Preconditions;
-
public class DefaultDirectPaymentApi implements DirectPaymentApi {
private static final boolean SHOULD_LOCK_ACCOUNT = true;
@@ -56,18 +54,17 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
this.internalCallContextFactory = internalCallContextFactory;
}
-
@Override
public DirectPayment createAuthorization(final Account account, final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency, final String directPaymentExternalKey, final String directPaymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
- checkNullParameter(account, "account");
- checkNullParameter(paymentMethodId, "paymentMethodId");
- checkNullParameter(amount, "amount");
- checkNullParameter(currency, "currency");
- checkNullParameter(directPaymentExternalKey, "paymentExternalKey");
- checkNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
- checkNullParameter(properties, "plugin properties");
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(paymentMethodId, "paymentMethodId");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentExternalKey, "paymentExternalKey");
+ checkNotNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
+ checkNotNullParameter(properties, "plugin properties");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
@@ -79,12 +76,11 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
public DirectPayment createCapture(final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency, final String directPaymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
-
- checkNullParameter(account, "account");
- checkNullParameter(directPaymentId, "paymentId");
- checkNullParameter(currency, "currency");
- checkNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
- checkNullParameter(properties, "plugin properties");
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(directPaymentId, "paymentId");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
+ checkNotNullParameter(properties, "plugin properties");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
@@ -96,13 +92,13 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
public DirectPayment createPurchase(final Account account, final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency, final String directPaymentExternalKey, final String directPaymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
- checkNullParameter(account, "account");
- checkNullParameter(paymentMethodId, "paymentMethodId");
- checkNullParameter(amount, "amount");
- checkNullParameter(currency, "currency");
- checkNullParameter(directPaymentExternalKey, "paymentExternalKey");
- checkNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
- checkNullParameter(properties, "plugin properties");
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(paymentMethodId, "paymentMethodId");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentExternalKey, "paymentExternalKey");
+ checkNotNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
+ checkNotNullParameter(properties, "plugin properties");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
@@ -114,13 +110,12 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
public DirectPayment createPurchaseWithPaymentControl(final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency, final String directPaymentExternalKey, final String directPaymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final PaymentOptions paymentOptions, final CallContext callContext) throws PaymentApiException {
-
- checkNullParameter(account, "account");
- checkNullParameter(amount, "amount");
- checkNullParameter(currency, "currency");
- checkNullParameter(directPaymentExternalKey, "paymentExternalKey");
- checkNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
- checkNullParameter(properties, "plugin properties");
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentExternalKey, "paymentExternalKey");
+ checkNotNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
+ checkNotNullParameter(properties, "plugin properties");
checkPositiveAmount(amount);
if (paymentMethodId == null && !paymentOptions.isExternalPayment()) {
@@ -142,10 +137,10 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
public DirectPayment createVoid(final Account account, final UUID directPaymentId, final String directPaymentTransactionExternalKey, final Iterable<PluginProperty> properties,
final CallContext callContext) throws PaymentApiException {
- checkNullParameter(account, "account");
- checkNullParameter(directPaymentId, "paymentId");
- checkNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
- checkNullParameter(properties, "plugin properties");
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(directPaymentId, "paymentId");
+ checkNotNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
+ checkNotNullParameter(properties, "plugin properties");
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
return directPaymentProcessor.createVoid(account, directPaymentId, directPaymentTransactionExternalKey,
@@ -157,12 +152,12 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
public DirectPayment createRefund(final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency, final String directPaymentTransactionExternalKey, final Iterable<PluginProperty> properties,
final CallContext callContext) throws PaymentApiException {
- checkNullParameter(account, "account");
- checkNullParameter(amount, "amount");
- checkNullParameter(currency, "currency");
- checkNullParameter(directPaymentId, "paymentId");
- checkNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
- checkNullParameter(properties, "plugin properties");
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentId, "paymentId");
+ checkNotNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
+ checkNotNullParameter(properties, "plugin properties");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
@@ -174,17 +169,15 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
public DirectPayment createRefundWithPaymentControl(final Account account, final UUID directPaymentId, @Nullable final BigDecimal amount, final Currency currency, final String directPaymentTransactionExternalKey, final Iterable<PluginProperty> properties,
final PaymentOptions paymentOptions, final CallContext callContext) throws PaymentApiException {
-
- checkNullParameter(account, "account");
- checkNullParameter(currency, "currency");
- checkNullParameter(directPaymentId, "paymentId");
- checkNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
- checkNullParameter(properties, "plugin properties");
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentId, "paymentId");
+ checkNotNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
+ checkNotNullParameter(properties, "plugin properties");
if (amount != null) {
checkPositiveAmount(amount);
}
-
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
return pluginControlledPaymentProcessor.createRefund(true, account, directPaymentId, amount, currency, directPaymentTransactionExternalKey,
properties, paymentOptions.getPaymentControlPluginName(), callContext, internalCallContext);
@@ -196,15 +189,14 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
final String directPaymentExternalKey, final String directPaymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
-
- checkNullParameter(account, "account");
- checkNullParameter(paymentMethodId, "paymentMethodId");
- checkNullParameter(amount, "amount");
- checkNullParameter(currency, "currency");
- checkNullParameter(directPaymentId, "paymentId");
- checkNullParameter(directPaymentExternalKey, "paymentExternalKey");
- checkNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
- checkNullParameter(properties, "plugin properties");
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(paymentMethodId, "paymentMethodId");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentId, "paymentId");
+ checkNotNullParameter(directPaymentExternalKey, "paymentExternalKey");
+ checkNotNullParameter(directPaymentTransactionExternalKey, "paymentTransactionExternalKey");
+ checkNotNullParameter(properties, "plugin properties");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
@@ -216,29 +208,51 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
@Override
public void notifyPendingTransactionOfStateChanged(final Account account, final UUID directPaymentTransactionId, final boolean isSuccess, final CallContext callContext) throws PaymentApiException {
- checkNullParameter(account, "account");
- checkNullParameter(directPaymentTransactionId, "paymentTransactionId");
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(directPaymentTransactionId, "paymentTransactionId");
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
directPaymentProcessor.notifyPendingPaymentOfStateChanged(account, directPaymentTransactionId, isSuccess, callContext, internalCallContext);
}
@Override
- public DirectPayment notifyChargeback(final Account account, final UUID directPaymentTransactionId, final String chargebackTransactionExternalKey, final BigDecimal amount, final Currency currency, final CallContext callContext) throws PaymentApiException {
+ public void notifyPendingTransactionOfStateChangedWithPaymentControl(Account account, UUID directPaymentTransactionId, boolean isSuccess, PaymentOptions paymentOptions, CallContext context) throws PaymentApiException {
+
+ }
+
+
+ @Override
+ public DirectPayment notifyChargeback(final Account account, final UUID directPaymentTransactionId, final String chargebackTransactionExternalKey, final BigDecimal amount, final Currency currency,
+ final CallContext callContext) throws PaymentApiException {
+
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentTransactionId, "paymentTransactionId");
+ checkNotNullParameter(chargebackTransactionExternalKey, "transactionExternalKey");
+ checkPositiveAmount(amount);
- checkNullParameter(account, "account");
- checkNullParameter(amount, "amount");
- checkNullParameter(currency, "currency");
- checkNullParameter(directPaymentTransactionId, "paymentTransactionId");
- checkNullParameter(chargebackTransactionExternalKey, "transactionExternalKey");
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ return directPaymentProcessor.notifyChargeback(account, null, directPaymentTransactionId, chargebackTransactionExternalKey, amount, currency, true,
+ callContext, internalCallContext);
+ }
+
+ @Override
+ public DirectPayment notifyChargebackWithPaymentControl(Account account, UUID directPaymentTransactionId, String chargebackTransactionExternalKey, BigDecimal amount, Currency currency, final PaymentOptions paymentOptions, CallContext callContext) throws PaymentApiException {
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentTransactionId, "paymentTransactionId");
+ checkNotNullParameter(chargebackTransactionExternalKey, "transactionExternalKey");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
- return directPaymentProcessor.notifyPaymentPaymentOfChargeback(account, directPaymentTransactionId, chargebackTransactionExternalKey, amount, currency, callContext, internalCallContext);
+ return pluginControlledPaymentProcessor.notifyPaymentPaymentOfChargeback(account, directPaymentTransactionId, chargebackTransactionExternalKey, amount, currency,
+ paymentOptions.getPaymentControlPluginName(), callContext, internalCallContext);
}
@Override
- public List<DirectPayment> getAccountPayments(final UUID accountId, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext tenantContext) throws PaymentApiException {
+ public List<DirectPayment> getAccountPayments(final UUID accountId, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext tenantContext) throws PaymentApiException {
return directPaymentProcessor.getAccountPayments(accountId, internalCallContextFactory.createInternalTenantContext(accountId, tenantContext));
}
@@ -278,7 +292,6 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
return directPaymentProcessor.searchPayments(searchKey, offset, limit, pluginName, properties, context, internalCallContextFactory.createInternalTenantContext(context));
}
-
@Override
public UUID addPaymentMethod(String paymentMethodExternalKey,
final Account account, final String pluginName,
@@ -358,7 +371,7 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
return paymentMethods;
}
- private void checkNullParameter(final Object parameter, final String parameterName) throws PaymentApiException {
+ private void checkNotNullParameter(final Object parameter, final String parameterName) throws PaymentApiException {
if (parameter == null) {
throw new PaymentApiException(ErrorCode.PAYMENT_INVALID_PARAMETER, parameterName, "should not be null");
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/control/InvoicePaymentControlPluginApi.java b/payment/src/main/java/org/killbill/billing/payment/control/InvoicePaymentControlPluginApi.java
index 73357a6..8874dcc 100644
--- a/payment/src/main/java/org/killbill/billing/payment/control/InvoicePaymentControlPluginApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/control/InvoicePaymentControlPluginApi.java
@@ -113,13 +113,19 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
final TransactionType transactionType = paymentControlContext.getTransactionType();
Preconditions.checkArgument(transactionType == TransactionType.PURCHASE ||
- transactionType == TransactionType.REFUND);
+ transactionType == TransactionType.REFUND ||
+ transactionType == TransactionType.CHARGEBACK);
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(paymentControlContext.getAccountId(), paymentControlContext);
- if (transactionType == TransactionType.PURCHASE) {
- return getPluginPurchaseResult(paymentControlContext, internalContext);
- } else /* TransactionType.REFUND */ {
- return getPluginRefundResult(paymentControlContext, internalContext);
+ switch (transactionType) {
+ case PURCHASE:
+ return getPluginPurchaseResult(paymentControlContext, internalContext);
+ case REFUND:
+ return getPluginRefundResult(paymentControlContext, internalContext);
+ case CHARGEBACK:
+ return new DefaultPriorPaymentControlResult(false, paymentControlContext.getAmount());
+ default:
+ throw new IllegalStateException("Unexpected transactionType " + transactionType);
}
}
@@ -128,43 +134,60 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
final TransactionType transactionType = paymentControlContext.getTransactionType();
Preconditions.checkArgument(transactionType == TransactionType.PURCHASE ||
- transactionType == TransactionType.REFUND);
+ transactionType == TransactionType.REFUND ||
+ transactionType == TransactionType.CHARGEBACK);
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(paymentControlContext.getAccountId(), paymentControlContext);
try {
- if (transactionType == TransactionType.PURCHASE) {
- final UUID invoiceId = getInvoiceId(paymentControlContext);
- invoiceApi.notifyOfPayment(invoiceId,
- paymentControlContext.getAmount(),
- paymentControlContext.getCurrency(),
- paymentControlContext.getProcessedCurrency(),
- paymentControlContext.getPaymentId(),
- paymentControlContext.getCreatedDate(),
- internalContext);
- } else /* TransactionType.REFUND */ {
- final Map<UUID, BigDecimal> idWithAmount = extractIdsWithAmountFromProperties(paymentControlContext.getPluginProperties());
- final PluginProperty prop = getPluginProperty(paymentControlContext.getPluginProperties(), PROP_IPCD_REFUND_WITH_ADJUSTMENTS);
- final boolean isAdjusted = prop != null ? Boolean.valueOf((String) prop.getValue()) : false;
- invoiceApi.createRefund(paymentControlContext.getPaymentId(), paymentControlContext.getAmount(), isAdjusted , idWithAmount, paymentControlContext.getTransactionExternalKey(), internalContext);
+ switch (transactionType) {
+ case PURCHASE:
+ final UUID invoiceId = getInvoiceId(paymentControlContext);
+ invoiceApi.notifyOfPayment(invoiceId,
+ paymentControlContext.getAmount(),
+ paymentControlContext.getCurrency(),
+ paymentControlContext.getProcessedCurrency(),
+ paymentControlContext.getPaymentId(),
+ paymentControlContext.getCreatedDate(),
+ internalContext);
+ break;
+
+ case REFUND:
+ final Map<UUID, BigDecimal> idWithAmount = extractIdsWithAmountFromProperties(paymentControlContext.getPluginProperties());
+ final PluginProperty prop = getPluginProperty(paymentControlContext.getPluginProperties(), PROP_IPCD_REFUND_WITH_ADJUSTMENTS);
+ final boolean isAdjusted = prop != null ? Boolean.valueOf((String) prop.getValue()) : false;
+ invoiceApi.createRefund(paymentControlContext.getPaymentId(), paymentControlContext.getAmount(), isAdjusted, idWithAmount, paymentControlContext.getTransactionExternalKey(), internalContext);
+ break;
+
+ case CHARGEBACK:
+ invoiceApi.createChargeback(paymentControlContext.getPaymentId(), paymentControlContext.getProcessedAmount(), paymentControlContext.getProcessedCurrency(), internalContext);
+ break;
+
+ default:
+ throw new IllegalStateException("Unexpected transactionType " + transactionType);
}
-
} catch (InvoiceApiException e) {
+ // STEPH need to add some state machine logic in the plugin itself to handle those cases
logger.error("Failed to complete call: ", e);
//throw new PaymentControlApiException(e);
}
}
@Override
- public FailureCallResult onFailureCall(final PaymentControlContext paymentControlContext) throws PaymentControlApiException {
+ public FailureCallResult onFailureCall(final PaymentControlContext paymentControlContext) throws
+ PaymentControlApiException {
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(paymentControlContext.getAccountId(), paymentControlContext);
- switch (paymentControlContext.getTransactionType()) {
+ final TransactionType transactionType = paymentControlContext.getTransactionType();
+ switch (transactionType) {
case PURCHASE:
final DateTime nextRetryDate = computeNextRetryDate(paymentControlContext.getPaymentExternalKey(), paymentControlContext.isApiPayment(), internalContext);
return new DefaultFailureCallResult(nextRetryDate);
- default:
- // We don't retry REFUND
+ case REFUND:
+ case CHARGEBACK:
+ // We don't retry REFUND, CHARGEBACK
return new DefaultFailureCallResult(null);
+ default:
+ throw new IllegalStateException("Unexpected transactionType " + transactionType);
}
}
@@ -176,16 +199,15 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
controlDao.removeAutoPayOffEntry(account.getId());
}
- private UUID getInvoiceId(final PaymentControlContext paymentControlContext) throws PaymentControlApiException {
+ private UUID getInvoiceId(final PaymentControlContext paymentControlContext) throws PaymentControlApiException {
final PluginProperty invoiceProp = getPluginProperty(paymentControlContext.getPluginProperties(), PROP_IPCD_INVOICE_ID);
if (invoiceProp == null ||
- ! (invoiceProp.getValue() instanceof String)) {
+ !(invoiceProp.getValue() instanceof String)) {
throw new PaymentControlApiException("Need to specify a valid invoiceId in property " + PROP_IPCD_INVOICE_ID);
}
return UUID.fromString((String) invoiceProp.getValue());
}
-
private PriorPaymentControlResult getPluginPurchaseResult(final PaymentControlContext paymentControlPluginContext, final InternalCallContext internalContext) throws PaymentControlApiException {
try {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/DirectPaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/DirectPaymentProcessor.java
index 26e7a00..e11a89c 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/DirectPaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/DirectPaymentProcessor.java
@@ -28,7 +28,6 @@ import java.util.concurrent.ExecutorService;
import javax.annotation.Nullable;
import javax.inject.Inject;
-import org.joda.time.DateTime;
import org.killbill.automaton.State;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.account.api.Account;
@@ -145,6 +144,15 @@ public class DirectPaymentProcessor extends ProcessorBase {
return performOperation(TransactionType.CREDIT, account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
}
+ public DirectPayment notifyChargeback(final Account account, @Nullable final UUID paymentId, @Nullable final UUID transactionId, final String directPaymentTransactionExternalKey, final BigDecimal amount, final Currency currency, final boolean shouldLockAccountAndDispatch,
+ final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+
+ // We need to have something...
+ Preconditions.checkState(paymentId != null || transactionId != null);
+ final UUID nonNullPaymentId = retrieveNonNullPaymentIdFromArguments(paymentId, transactionId, internalCallContext);
+ return performOperation(TransactionType.CHARGEBACK, account, null, nonNullPaymentId, amount, currency, null, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, ImmutableList.<PluginProperty>of(), callContext, internalCallContext);
+ }
+
public List<DirectPayment> getAccountPayments(final UUID accountId, final InternalTenantContext tenantContext) throws PaymentApiException {
final List<PaymentModelDao> paymentsModelDao = paymentDao.getDirectPaymentsForAccount(accountId, tenantContext);
final List<PaymentTransactionModelDao> transactionsModelDao = paymentDao.getDirectTransactionsForAccount(accountId, tenantContext);
@@ -178,28 +186,6 @@ public class DirectPaymentProcessor extends ProcessorBase {
transactionModelDao.getGatewayErrorCode(), transactionModelDao.getGatewayErrorMsg(), internalCallContext);
}
- public DirectPayment notifyPaymentPaymentOfChargeback(final Account account, final UUID transactionId, final String chargebackTransactionExternalKey, final BigDecimal amount, final Currency currency, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
-
- validateUniqueTransactionExternalKey(chargebackTransactionExternalKey, internalCallContext);
-
- final PaymentTransactionModelDao transactionModelDao = paymentDao.getDirectPaymentTransaction(transactionId, internalCallContext);
- Preconditions.checkState(transactionModelDao != null);
-
- final DateTime utcNow = clock.getUTCNow();
- final PaymentTransactionModelDao chargebackTransaction = new PaymentTransactionModelDao(utcNow, utcNow, chargebackTransactionExternalKey, transactionModelDao.getPaymentId(),
-
- TransactionType.CHARGEBACK, utcNow, TransactionStatus.SUCCESS, amount, currency, null, null);
- final State currentPaymentState = directPaymentAutomatonRunner.fetchNextState("CHARGEBACK_INIT", true);
-
- // TODO STEPH we could create a DAO operation to do both steps at once
- paymentDao.updateDirectPaymentWithNewTransaction(transactionModelDao.getPaymentId(), chargebackTransaction, internalCallContext);
- paymentDao.updateDirectPaymentAndTransactionOnCompletion(transactionModelDao.getPaymentId(), currentPaymentState.getName(), chargebackTransaction.getId(), TransactionStatus.SUCCESS,
- chargebackTransaction.getAmount(), chargebackTransaction.getCurrency(),
- chargebackTransaction.getGatewayErrorCode(), chargebackTransaction.getGatewayErrorMsg(), internalCallContext);
-
- return getPayment(transactionModelDao.getPaymentId(), false, ImmutableList.<PluginProperty>of(), callContext, internalCallContext);
- }
-
public DirectPayment getPayment(final UUID directPaymentId, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext tenantContext, final InternalTenantContext internalTenantContext) throws PaymentApiException {
final PaymentModelDao paymentModelDao = paymentDao.getDirectPayment(directPaymentId, internalTenantContext);
if (paymentModelDao == null) {
@@ -359,19 +345,6 @@ public class DirectPaymentProcessor extends ProcessorBase {
}
}
- private void validateUniqueTransactionExternalKey(final String transactionExternalKey, final InternalTenantContext tenantContext) throws PaymentApiException {
- final List<PaymentTransactionModelDao> transactions = paymentDao.getDirectPaymentTransactionsByExternalKey(transactionExternalKey, tenantContext);
- final PaymentTransactionModelDao transactionAlreadyExists = Iterables.tryFind(transactions, new Predicate<PaymentTransactionModelDao>() {
- @Override
- public boolean apply(final PaymentTransactionModelDao input) {
- return input.getTransactionStatus() == TransactionStatus.SUCCESS;
- }
- }).orNull();
- if (transactionAlreadyExists != null) {
- throw new PaymentApiException(ErrorCode.PAYMENT_ACTIVE_TRANSACTION_KEY_EXISTS, transactionExternalKey);
- }
- }
-
private DirectPayment getDirectPayment(final PaymentModelDao paymentModelDao, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext context, final InternalTenantContext tenantContext) throws PaymentApiException {
final InternalTenantContext tenantContextWithAccountRecordId;
if (tenantContext.getAccountRecordId() == null) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PluginControlledPaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PluginControlledPaymentProcessor.java
index 8f53346..230dd4a 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PluginControlledPaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PluginControlledPaymentProcessor.java
@@ -24,6 +24,7 @@ import java.util.concurrent.ExecutorService;
import javax.annotation.Nullable;
import javax.inject.Inject;
+import org.joda.time.DateTime;
import org.killbill.automaton.State;
import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
@@ -36,6 +37,7 @@ import org.killbill.billing.osgi.api.OSGIServiceRegistration;
import org.killbill.billing.payment.api.DirectPayment;
import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.core.sm.PluginControlledDirectPaymentAutomatonRunner;
import org.killbill.billing.payment.dao.PaymentModelDao;
@@ -52,6 +54,7 @@ import org.killbill.clock.Clock;
import org.killbill.commons.locker.GlobalLocker;
import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.inject.name.Named;
@@ -102,7 +105,9 @@ public class PluginControlledPaymentProcessor extends ProcessorBase {
return pluginControlledDirectPaymentAutomatonRunner.run(isApiPayment,
TransactionType.CAPTURE,
account,
+ null,
directPaymentId,
+ null,
transactionExternalKey,
amount,
currency,
@@ -133,8 +138,12 @@ public class PluginControlledPaymentProcessor extends ProcessorBase {
return pluginControlledDirectPaymentAutomatonRunner.run(isApiPayment,
TransactionType.VOID,
account,
+ null,
directPaymentId,
+ null,
transactionExternalKey,
+ null,
+ null,
properties,
null,
callContext, internalCallContext);
@@ -145,7 +154,9 @@ public class PluginControlledPaymentProcessor extends ProcessorBase {
return pluginControlledDirectPaymentAutomatonRunner.run(isApiPayment,
TransactionType.REFUND,
account,
+ null,
directPaymentId,
+ null,
transactionExternalKey,
amount,
currency,
@@ -158,19 +169,38 @@ public class PluginControlledPaymentProcessor extends ProcessorBase {
final String transactionExternalKey, final Iterable<PluginProperty> properties, final String paymentControlPluginName, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return pluginControlledDirectPaymentAutomatonRunner.run(isApiPayment,
- TransactionType.CREDIT,
- account,
- paymentMethodId,
- directPaymentId,
- paymentExternalKey,
- transactionExternalKey,
- amount,
- currency,
- properties,
- paymentControlPluginName,
- callContext, internalCallContext);
+ TransactionType.CREDIT,
+ account,
+ paymentMethodId,
+ directPaymentId,
+ paymentExternalKey,
+ transactionExternalKey,
+ amount,
+ currency,
+ properties,
+ paymentControlPluginName,
+ callContext, internalCallContext);
}
+ public DirectPayment notifyPaymentPaymentOfChargeback(final Account account, final UUID transactionId, final String transactionExternalKey, final BigDecimal amount, final Currency currency,
+ final String paymentControlPluginName, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ // We need to have something...
+ final UUID nonNullPaymentId = retrieveNonNullPaymentIdFromArguments(null, transactionId, internalCallContext);
+ return pluginControlledDirectPaymentAutomatonRunner.run(true,
+ TransactionType.CHARGEBACK,
+ account,
+ null,
+ nonNullPaymentId,
+ null,
+ transactionExternalKey,
+ amount,
+ currency,
+ ImmutableList.<PluginProperty>of(),
+ paymentControlPluginName,
+ callContext, internalCallContext);
+ }
+
+
public void retryPaymentTransaction(final UUID attemptId, final String pluginName, final InternalCallContext internalCallContext) {
try {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java b/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
index eb0f9f3..f0689da 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
@@ -39,8 +39,10 @@ import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.invoice.api.InvoiceInternalApi;
import org.killbill.billing.osgi.api.OSGIServiceRegistration;
import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.dao.PaymentDao;
import org.killbill.billing.payment.dao.PaymentMethodModelDao;
+import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.tag.TagInternalApi;
import org.killbill.billing.util.api.TagApiException;
@@ -60,7 +62,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
+import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
public abstract class ProcessorBase {
@@ -167,10 +171,38 @@ public abstract class ProcessorBase {
}
}
+ protected UUID retrieveNonNullPaymentIdFromArguments(@Nullable final UUID paymentId, @Nullable final UUID transactionId, final InternalCallContext internalCallContext) throws PaymentApiException {
+ final UUID nonNullPaymentId;
+ if (paymentId == null) {
+ final PaymentTransactionModelDao transactionModelDao = paymentDao.getDirectPaymentTransaction(transactionId, internalCallContext);
+ if (transactionModelDao == null) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_INVALID_PARAMETER, transactionId, "need to specify a valid transactionId");
+ }
+ nonNullPaymentId = transactionModelDao.getPaymentId();
+ } else {
+ nonNullPaymentId = paymentId;
+ }
+ return nonNullPaymentId;
+ }
+
protected TenantContext buildTenantContext(final InternalTenantContext context) {
return context.toTenantContext(nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT));
}
+ protected void validateUniqueTransactionExternalKey(final String transactionExternalKey, final InternalTenantContext tenantContext) throws PaymentApiException {
+ final List<PaymentTransactionModelDao> transactions = paymentDao.getDirectPaymentTransactionsByExternalKey(transactionExternalKey, tenantContext);
+ final PaymentTransactionModelDao transactionAlreadyExists = Iterables.tryFind(transactions, new Predicate<PaymentTransactionModelDao>() {
+ @Override
+ public boolean apply(final PaymentTransactionModelDao input) {
+ return input.getTransactionStatus() == TransactionStatus.SUCCESS;
+ }
+ }).orNull();
+ if (transactionAlreadyExists != null) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_ACTIVE_TRANSACTION_KEY_EXISTS, transactionExternalKey);
+ }
+ }
+
+
// TODO Rename - there is no lock!
public interface WithAccountLockCallback<ReturnType, ExceptionType extends Exception> {
public ReturnType doOperation() throws ExceptionType;
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackCompleted.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackCompleted.java
new file mode 100644
index 0000000..3ef5c93
--- /dev/null
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackCompleted.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 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.payment.core.sm;
+
+import org.killbill.billing.payment.api.PaymentApiException;
+
+public class ChargebackCompleted extends DirectPaymentEnteringStateCallback {
+
+ public ChargebackCompleted(final DirectPaymentAutomatonDAOHelper daoHelper, final DirectPaymentStateContext directPaymentStateContext) throws PaymentApiException {
+ super(daoHelper, directPaymentStateContext);
+ }
+}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackInitiated.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackInitiated.java
new file mode 100644
index 0000000..9b2c36a
--- /dev/null
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackInitiated.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 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.payment.core.sm;
+
+import org.killbill.billing.payment.api.PaymentApiException;
+
+public class ChargebackInitiated extends DirectPaymentLeavingStateCallback {
+
+ public ChargebackInitiated(final DirectPaymentAutomatonDAOHelper daoHelper, final DirectPaymentStateContext directPaymentStateContext) throws PaymentApiException {
+ super(daoHelper);
+ }
+}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackOperation.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackOperation.java
new file mode 100644
index 0000000..c3d0235
--- /dev/null
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackOperation.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 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.payment.core.sm;
+
+import org.killbill.automaton.OperationResult;
+import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.api.TransactionType;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher;
+import org.killbill.billing.payment.plugin.api.PaymentPluginApiException;
+import org.killbill.billing.payment.plugin.api.PaymentPluginStatus;
+import org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin;
+import org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin;
+import org.killbill.commons.locker.GlobalLocker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChargebackOperation extends DirectPaymentOperation {
+
+ private final Logger logger = LoggerFactory.getLogger(ChargebackOperation.class);
+
+ public ChargebackOperation(final DirectPaymentAutomatonDAOHelper daoHelper,
+ final GlobalLocker locker, final PluginDispatcher<OperationResult> paymentPluginDispatcher,
+ final DirectPaymentStateContext directPaymentStateContext) throws PaymentApiException {
+ super(daoHelper, locker, paymentPluginDispatcher, directPaymentStateContext);
+ }
+
+ @Override
+ protected PaymentTransactionInfoPlugin doCallSpecificOperationCallback() throws PaymentPluginApiException {
+ logger.debug("Starting CHARGEBACK for payment {} ({} {})", directPaymentStateContext.getDirectPaymentId(), directPaymentStateContext.getAmount(), directPaymentStateContext.getCurrency());
+ return new DefaultNoOpPaymentInfoPlugin( directPaymentStateContext.getDirectPaymentId(),
+ directPaymentStateContext.getTransactionPaymentId(),
+ TransactionType.CHARGEBACK,
+ directPaymentStateContext.getAmount(),
+ directPaymentStateContext.getCurrency(),
+ null,
+ null,
+ PaymentPluginStatus.PROCESSED,
+ null);
+ }
+}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentAutomatonRunner.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentAutomatonRunner.java
index 0e4b6a5..6d99e34 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentAutomatonRunner.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentAutomatonRunner.java
@@ -189,6 +189,13 @@ public class DirectPaymentAutomatonRunner {
leavingStateCallback = new CreditInitiated(daoHelper, directPaymentStateContext);
enteringStateCallback = new CreditCompleted(daoHelper, directPaymentStateContext);
break;
+ case CHARGEBACK:
+ operationStateMachineName = "CHARGEBACK";
+ operationName = "OP_CHARGEBACK";
+ operationCallback = new ChargebackOperation(daoHelper, locker, paymentPluginDispatcher, directPaymentStateContext);
+ leavingStateCallback = new ChargebackInitiated(daoHelper, directPaymentStateContext);
+ enteringStateCallback = new ChargebackCompleted(daoHelper, directPaymentStateContext);
+ break;
default:
throw new IllegalStateException("Unsupported transaction type " + transactionType);
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginControlledDirectPaymentAutomatonRunner.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginControlledDirectPaymentAutomatonRunner.java
index f3af2a9..c48a3ca 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginControlledDirectPaymentAutomatonRunner.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginControlledDirectPaymentAutomatonRunner.java
@@ -89,29 +89,12 @@ public class PluginControlledDirectPaymentAutomatonRunner extends DirectPaymentA
public DirectPayment run(final boolean isApiPayment, final TransactionType transactionType, final Account account, @Nullable final UUID paymentMethodId,
@Nullable final UUID directPaymentId, @Nullable final String directPaymentExternalKey, final String directPaymentTransactionExternalKey,
@Nullable final BigDecimal amount, @Nullable final Currency currency,
- final Iterable<PluginProperty> properties,
- @Nullable final String pluginName, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ final Iterable<PluginProperty> properties, @Nullable final String pluginName,
+ final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return run(initialState, isApiPayment, transactionType, account, paymentMethodId, directPaymentId, directPaymentExternalKey, directPaymentTransactionExternalKey,
amount, currency, properties, pluginName, callContext, internalCallContext);
}
- public DirectPayment run(final boolean isApiPayment, final TransactionType transactionType, final Account account,
- @Nullable final UUID directPaymentId, final String directPaymentTransactionExternalKey,
- @Nullable final BigDecimal amount, @Nullable final Currency currency,
- final Iterable<PluginProperty> properties,
- @Nullable final String pluginName, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
- return run(initialState, isApiPayment, transactionType, account, null, directPaymentId, null, directPaymentTransactionExternalKey,
- amount, currency, properties, pluginName, callContext, internalCallContext);
- }
-
- public DirectPayment run(final boolean isApiPayment, final TransactionType transactionType, final Account account,
- @Nullable final UUID directPaymentId, final String directPaymentTransactionExternalKey,
- final Iterable<PluginProperty> properties,
- @Nullable final String pluginName, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
- return run(initialState, isApiPayment, transactionType, account, null, directPaymentId, null, directPaymentTransactionExternalKey,
- null, null, properties, pluginName, callContext, internalCallContext);
- }
-
public DirectPayment run(final State state, final boolean isApiPayment, final TransactionType transactionType, final Account account, @Nullable final UUID paymentMethodId,
@Nullable final UUID directPaymentId, @Nullable final String directPaymentExternalKey, final String directPaymentTransactionExternalKey,
@Nullable final BigDecimal amount, @Nullable final Currency currency,
@@ -193,6 +176,9 @@ public class PluginControlledDirectPaymentAutomatonRunner extends DirectPaymentA
case REFUND:
callback = new RetryRefundOperationCallback(locker, paymentPluginDispatcher, directPaymentStateContext, directPaymentProcessor, paymentControlPluginRegistry);
break;
+ case CHARGEBACK:
+ callback = new RetryChargebackOperationCallback(locker, paymentPluginDispatcher, directPaymentStateContext, directPaymentProcessor, paymentControlPluginRegistry);
+ break;
default:
throw new IllegalStateException("Unsupported transaction type " + transactionType);
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryableDirectPaymentStateContext.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryableDirectPaymentStateContext.java
index 2b70ba6..e085666 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryableDirectPaymentStateContext.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryableDirectPaymentStateContext.java
@@ -43,7 +43,8 @@ public class RetryableDirectPaymentStateContext extends DirectPaymentStateContex
private String pluginName;
private DirectPayment result;
- public RetryableDirectPaymentStateContext(@Nullable final String pluginName, final boolean isApiPayment, @Nullable final UUID directPaymentId, final String directPaymentExternalKey, @Nullable final String directPaymentTransactionExternalKey, final TransactionType transactionType,
+ public RetryableDirectPaymentStateContext(@Nullable final String pluginName, final boolean isApiPayment, @Nullable final UUID directPaymentId, final String directPaymentExternalKey,
+ @Nullable final String directPaymentTransactionExternalKey, final TransactionType transactionType,
final Account account, @Nullable final UUID paymentMethodId, final BigDecimal amount, final Currency currency,
final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext, final CallContext callContext) {
super(directPaymentId, directPaymentExternalKey, directPaymentTransactionExternalKey, transactionType, account, paymentMethodId, amount, currency, true, properties, internalCallContext, callContext);
@@ -97,14 +98,5 @@ public class RetryableDirectPaymentStateContext extends DirectPaymentStateContex
return null;
}
return result.getTransactions().get(result.getTransactions().size() -1);
-/*
-STEPH
- Iterables.filter(result.getTransactions(), new Predicate<DirectPaymentTransaction>() {
- @Override
- public boolean apply(final DirectPaymentTransaction input) {
- return input.getExternalKey().equals(directPaymentTransactionExternalKey);
- }
- })
- */
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryChargebackOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryChargebackOperationCallback.java
new file mode 100644
index 0000000..1b3bd88
--- /dev/null
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryChargebackOperationCallback.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 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.payment.core.sm;
+
+import org.killbill.automaton.OperationResult;
+import org.killbill.billing.osgi.api.OSGIServiceRegistration;
+import org.killbill.billing.payment.api.DirectPayment;
+import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.core.DirectPaymentProcessor;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher;
+import org.killbill.billing.retry.plugin.api.PaymentControlPluginApi;
+import org.killbill.commons.locker.GlobalLocker;
+
+public class RetryChargebackOperationCallback extends RetryOperationCallback {
+
+ public RetryChargebackOperationCallback(final GlobalLocker locker, final PluginDispatcher<OperationResult> paymentPluginDispatcher, final RetryableDirectPaymentStateContext directPaymentStateContext, final DirectPaymentProcessor directPaymentProcessor, final OSGIServiceRegistration<PaymentControlPluginApi> paymentControlPluginRegistry) {
+ super(locker, paymentPluginDispatcher, directPaymentStateContext, directPaymentProcessor, paymentControlPluginRegistry);
+ }
+
+ @Override
+ protected DirectPayment doCallSpecificOperationCallback() throws PaymentApiException {
+ return directPaymentProcessor.notifyChargeback(directPaymentStateContext.account, directPaymentStateContext.getDirectPaymentId(), null, directPaymentStateContext.directPaymentTransactionExternalKey, directPaymentStateContext.getAmount(),
+ directPaymentStateContext.getCurrency(), false,
+ directPaymentStateContext.callContext, directPaymentStateContext.internalCallContext);
+
+ }
+}
diff --git a/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml b/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
index 26eee32..990920d 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
+++ b/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
@@ -290,6 +290,12 @@
</linkStateMachine>
<linkStateMachine>
<initialStateMachine>CAPTURE</initialStateMachine>
+ <initialState>CAPTURE_SUCCESS</initialState>
+ <finalStateMachine>CHARGEBACK</finalStateMachine>
+ <finalState>CHARGEBACK_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
+ <initialStateMachine>CAPTURE</initialStateMachine>
<initialState>CAPTURE_FAILED</initialState>
<finalStateMachine>CAPTURE</finalStateMachine>
<finalState>CAPTURE_INIT</finalState>
@@ -318,6 +324,11 @@
<finalStateMachine>REFUND</finalStateMachine>
<finalState>REFUND_INIT</finalState>
</linkStateMachine>
+ <linkStateMachine>
+ <initialStateMachine>PURCHASE</initialStateMachine>
+ <initialState>PURCHASE_SUCCESS</initialState>
+ <finalStateMachine>CHARGEBACK</finalStateMachine>
+ <finalState>CHARGEBACK_INIT</finalState>
+ </linkStateMachine>
</linkStateMachines>
-
</stateMachineConfig>