killbill-uncached
Changes
beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueBase.java 2(+1 -1)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java 8(+5 -3)
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 50(+39 -11)
payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentAutomatonDAOHelper.java 51(+33 -18)
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/DirectPaymentEnteringStateCallback.java 13(+6 -7)
payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentLeavingStateCallback.java 9(+7 -2)
payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentStateContext.java 13(+13 -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)
payment/src/main/java/org/killbill/billing/payment/core/sm/RetryAuthorizeOperationCallback.java 13(+12 -1)
payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCaptureOperationCallback.java 15(+10 -5)
payment/src/main/java/org/killbill/billing/payment/core/sm/RetryChargebackOperationCallback.java 47(+47 -0)
payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCreditOperationCallback.java 13(+12 -1)
payment/src/main/java/org/killbill/billing/payment/core/sm/RetryPurchaseOperationCallback.java 15(+12 -3)
payment/src/main/java/org/killbill/billing/payment/core/sm/RetryRefundOperationCallback.java 11(+10 -1)
payment/src/test/java/org/killbill/billing/payment/core/sm/TestDirectPaymentEnteringStateCallback.java 9(+1 -8)
Details
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueBase.java
index e3eb49c..e76b309 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueBase.java
@@ -64,7 +64,7 @@ public abstract class TestOverdueBase extends TestIntegrationBase {
account = createAccountWithNonOsgiPaymentMethod(getAccountData(0));
assertNotNull(account);
- paymentApi.addPaymentMethod(UUID.randomUUID().toString(), account, BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME, true, paymentMethodPlugin, PLUGIN_PROPERTIES, callContext);
+ paymentApi.addPaymentMethod(account, UUID.randomUUID().toString(), BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME, true, paymentMethodPlugin, PLUGIN_PROPERTIES, callContext);
productName = "Shotgun";
term = BillingPeriod.MONTHLY;
paymentPlugin.clear();
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index 4315ad9..cf3a7ad 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -47,6 +47,7 @@ import org.killbill.billing.invoice.api.InvoicePayment;
import org.killbill.billing.invoice.model.ExternalChargeInvoiceItem;
import org.killbill.billing.junction.DefaultBlockingState;
import org.killbill.billing.payment.api.DirectPayment;
+import org.killbill.billing.payment.api.PluginProperty;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@@ -637,7 +638,7 @@ public class TestOverdueIntegration extends TestOverdueBase {
checkChangePlanWithOverdueState(baseEntitlement, true, true);
// Add a payment method and set it as default
- paymentApi.addPaymentMethod(UUID.randomUUID().toString(), account, BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME, true, paymentMethodPlugin, PLUGIN_PROPERTIES, callContext);
+ paymentApi.addPaymentMethod(account, UUID.randomUUID().toString(), BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME, true, paymentMethodPlugin, PLUGIN_PROPERTIES, callContext);
allowPaymentsAndResetOverdueToClearByPayingAllUnpaidInvoices(false);
@@ -790,8 +791,9 @@ public class TestOverdueIntegration extends TestOverdueBase {
checkODState(DefaultBlockingState.CLEAR_STATE_NAME);
// Now, create a chargeback for the second (first non-zero dollar) invoice
- final InvoicePayment payment = invoicePaymentApi.getInvoicePayments(invoiceUserApi.getInvoicesByAccount(account.getId(), callContext).get(1).getPayments().get(0).getPaymentId(), callContext).get(0);
- createChargeBackAndCheckForCompletion(payment, NextEvent.BLOCK, NextEvent.INVOICE_ADJUSTMENT);
+ final InvoicePayment invoicePayment = invoicePaymentApi.getInvoicePayments(invoiceUserApi.getInvoicesByAccount(account.getId(), callContext).get(1).getPayments().get(0).getPaymentId(), callContext).get(0);
+ final DirectPayment payment = paymentApi.getPayment(invoicePayment.getPaymentId(), false, ImmutableList.<PluginProperty>of(), callContext);
+ createChargeBackAndCheckForCompletion(account, payment, NextEvent.BLOCK, NextEvent.INVOICE_ADJUSTMENT);
// We should now be in OD1
checkODState("OD1");
checkChangePlanWithOverdueState(baseEntitlement, true, true);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index 8089022..ceb3cb0 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -333,7 +333,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
final PaymentMethodPlugin info = createPaymentMethodPlugin();
- paymentApi.addPaymentMethod(UUID.randomUUID().toString(), account, paymentPluginName, true, info, PLUGIN_PROPERTIES, callContext);
+ paymentApi.addPaymentMethod(account, UUID.randomUUID().toString(), paymentPluginName, true, info, PLUGIN_PROPERTIES, callContext);
return accountUserApi.getAccountById(account.getId(), callContext);
}
@@ -517,18 +517,17 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
}, events);
}
- protected void createChargeBackAndCheckForCompletion(final InvoicePayment payment, final NextEvent... events) {
+ protected void createChargeBackAndCheckForCompletion(final Account account, final DirectPayment payment, final NextEvent... events) {
doCallAndCheckForCompletion(new Function<Void, Void>() {
@Override
public Void apply(@Nullable final Void input) {
- /*
try {
- // STEPH to be fixed with chargeback code
- //invoicePaymentApi.createChargeback(payment.getId(), payment.getAmount(), callContext);
- } catch (final InvoiceApiException e) {
+ paymentApi.createChargebackWithPaymentControl(account, payment.getId(), payment.getPurchasedAmount(), payment.getCurrency(), UUID.randomUUID().toString(),
+ PAYMENT_OPTIONS, callContext);
+ } catch (PaymentApiException e) {
fail(e.toString());
+ return null;
}
- */
return null;
}
}, events);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index 5fbcf5c..bb0b051 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -64,7 +64,6 @@ import org.killbill.billing.jaxrs.json.AccountEmailJson;
import org.killbill.billing.jaxrs.json.AccountJson;
import org.killbill.billing.jaxrs.json.AccountTimelineJson;
import org.killbill.billing.jaxrs.json.BundleJson;
-import org.killbill.billing.jaxrs.json.ChargebackJson;
import org.killbill.billing.jaxrs.json.CustomFieldJson;
import org.killbill.billing.jaxrs.json.DirectPaymentJson;
import org.killbill.billing.jaxrs.json.DirectTransactionJson;
@@ -330,20 +329,6 @@ public class AccountResource extends JaxRsResourceBase {
// Get the payments
final List<DirectPayment> payments = paymentApi.getAccountPayments(accountId, false, ImmutableList.<PluginProperty>of(), tenantContext);
- // Get the refunds
- final Iterable<DirectPaymentTransaction> refunds = getDirectPaymentTransactions(payments, TransactionType.REFUND);
- final Multimap<UUID, DirectPaymentTransaction> refundsByPayment = ArrayListMultimap.<UUID, DirectPaymentTransaction>create();
- for (final DirectPaymentTransaction refund : refunds) {
- refundsByPayment.put(refund.getDirectPaymentId(), refund);
- }
-
- // Get the chargebacks
- final Iterable<DirectPaymentTransaction> chargebacks = getDirectPaymentTransactions(payments, TransactionType.CHARGEBACK);
- final Multimap<UUID, DirectPaymentTransaction> chargebacksByPayment = ArrayListMultimap.<UUID, DirectPaymentTransaction>create();
- for (final DirectPaymentTransaction chargeback : chargebacks) {
- chargebacksByPayment.put(chargeback.getDirectPaymentId(), chargeback);
- }
-
// Get the bundles
final List<SubscriptionBundle> bundles = subscriptionApi.getSubscriptionBundlesForAccountId(account.getId(), tenantContext);
@@ -457,10 +442,11 @@ public class AccountResource extends JaxRsResourceBase {
public Response getInvoicePayments(@PathParam("accountId") final String accountIdStr,
@QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
- @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
- final TenantContext tenantContext = context.createContext(request);
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
final UUID accountId = UUID.fromString(accountIdStr);
- final List<DirectPayment> payments = paymentApi.getAccountPayments(accountId, withPluginInfo, ImmutableList.<PluginProperty>of(), tenantContext);
+ final TenantContext tenantContext = context.createContext(request);
+ final Account account = accountUserApi.getAccountById(accountId, tenantContext);
+ final List<DirectPayment> payments = paymentApi.getAccountPayments(account.getId(), withPluginInfo, ImmutableList.<PluginProperty>of(), tenantContext);
final List<InvoicePayment> invoicePayments = invoicePaymentApi.getInvoicePaymentsByAccount(accountId, tenantContext);
final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(accountId, auditMode.getLevel(), tenantContext);
final List<InvoicePaymentJson> result = new ArrayList<InvoicePaymentJson>(payments.size());
@@ -545,7 +531,7 @@ public class AccountResource extends JaxRsResourceBase {
return Response.status(Status.BAD_REQUEST).build();
}
- final UUID paymentMethodId = paymentApi.addPaymentMethod(data.getExternalKey(), account, data.getPluginName(), isDefault, data.getPluginDetail(), pluginProperties, callContext);
+ final UUID paymentMethodId = paymentApi.addPaymentMethod(account, data.getExternalKey(), data.getPluginName(), isDefault, data.getPluginDetail(), pluginProperties, callContext);
if (payAllUnpaidInvoices && unpaidInvoices.size() > 0) {
for (final Invoice invoice : unpaidInvoices) {
createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), false, callContext);
@@ -674,27 +660,6 @@ public class AccountResource extends JaxRsResourceBase {
}
/*
- * ************************** CHARGEBACKS ********************************
- */
- @GET
- @Path("/{accountId:" + UUID_PATTERN + "}/" + CHARGEBACKS)
- @Produces(APPLICATION_JSON)
- public Response getChargebacksForAccount(@PathParam("accountId") final String accountIdStr,
- @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
-
- final UUID accountId = UUID.fromString(accountIdStr);
- final TenantContext tenantContext = context.createContext(request);
-
- final List<DirectPayment> payments = paymentApi.getAccountPayments(accountId, false, ImmutableList.<PluginProperty>of(), tenantContext);
- final Iterable<DirectPaymentTransaction> transactions = getDirectPaymentTransactions(payments, TransactionType.CHARGEBACK);
- final List<ChargebackJson> chargebacksJson = new ArrayList<ChargebackJson>();
- for (final DirectPaymentTransaction chargeback : transactions) {
- chargebacksJson.add(new ChargebackJson(accountId, chargeback));
- }
- return Response.status(Response.Status.OK).entity(chargebacksJson).build();
- }
-
- /*
* ************************** OVERDUE ********************************
*/
@GET
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/DirectPaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/DirectPaymentResource.java
index cbae67b..a538348 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/DirectPaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/DirectPaymentResource.java
@@ -63,6 +63,7 @@ import org.killbill.clock.Clock;
import com.google.common.base.Function;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
@@ -83,9 +84,9 @@ public class DirectPaymentResource extends JaxRsResourceBase {
}
@GET
- @Path("/{directPaymentId:" + UUID_PATTERN + "}/")
+ @Path("/{paymentId:" + UUID_PATTERN + "}/")
@Produces(APPLICATION_JSON)
- public Response getDirectPayment(@PathParam("directPaymentId") final String directPaymentIdStr,
+ public Response getDirectPayment(@PathParam("paymentId") final String directPaymentIdStr,
@QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
@QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
@@ -184,11 +185,11 @@ public class DirectPaymentResource extends JaxRsResourceBase {
}
@POST
- @Path("/{directPaymentId:" + UUID_PATTERN + "}/")
+ @Path("/{paymentId:" + UUID_PATTERN + "}/")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response captureAuthorization(final DirectTransactionJson json,
- @PathParam("directPaymentId") final String directPaymentIdStr,
+ @PathParam("paymentId") final String directPaymentIdStr,
@QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@@ -209,11 +210,11 @@ public class DirectPaymentResource extends JaxRsResourceBase {
}
@POST
- @Path("/{directPaymentId:" + UUID_PATTERN + "}/" + REFUNDS)
+ @Path("/{paymentId:" + UUID_PATTERN + "}/" + REFUNDS)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response refundPayment(final DirectTransactionJson json,
- @PathParam("directPaymentId") final String directPaymentIdStr,
+ @PathParam("paymentId") final String directPaymentIdStr,
@QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@@ -234,11 +235,11 @@ public class DirectPaymentResource extends JaxRsResourceBase {
}
@DELETE
- @Path("/{directPaymentId:" + UUID_PATTERN + "}/")
+ @Path("/{paymentId:" + UUID_PATTERN + "}/")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response voidPayment(final DirectTransactionJson json,
- @PathParam("directPaymentId") final String directPaymentIdStr,
+ @PathParam("paymentId") final String directPaymentIdStr,
@QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@@ -256,6 +257,30 @@ public class DirectPaymentResource extends JaxRsResourceBase {
return uriBuilder.buildResponse(uriInfo, DirectPaymentResource.class, "getDirectPayment", payment.getId());
}
+ @POST
+ @Path("/{paymentId:" + UUID_PATTERN + "}/" + CHARGEBACKS)
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response chargebackPayment(final DirectTransactionJson json,
+ @PathParam("paymentId") final String directPaymentIdStr,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment,
+ @javax.ws.rs.core.Context final UriInfo uriInfo,
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+ final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+ final UUID directPaymentId = UUID.fromString(directPaymentIdStr);
+ final DirectPayment initialPayment = paymentApi.getPayment(directPaymentId, false, ImmutableList.<PluginProperty>of(), callContext);
+
+ final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
+ final Currency currency = json.getCurrency() == null ? account.getCurrency() : Currency.valueOf(json.getCurrency());
+
+ final DirectPayment payment = paymentApi.createChargeback(account, directPaymentId, json.getAmount(), currency,
+ json.getTransactionExternalKey(), callContext);
+ return uriBuilder.buildResponse(uriInfo, DirectPaymentResource.class, "getDirectPayment", payment.getId());
+ }
+
+
@Override
protected ObjectType getObjectType() {
return ObjectType.PAYMENT;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
index e256dbc..95cfe9c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
@@ -141,7 +141,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContext);
final Iterable<PluginProperty> pluginProperties;
- final String transactionExternalKey = UUID.randomUUID().toString();
+ final String transactionExternalKey = json.getTransactionExternalKey() != null ? json.getTransactionExternalKey() : UUID.randomUUID().toString();
if (json.isAdjusted() != null && json.isAdjusted()) {
if (json.getAdjustments() != null && json.getAdjustments().size() > 0) {
final Map<UUID, BigDecimal> adjustments = new HashMap<UUID, BigDecimal>();
@@ -164,6 +164,29 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
return uriBuilder.buildResponse(InvoicePaymentResource.class, "getInvoicePayment", result.getId(), uriInfo.getBaseUri().toString());
}
+ @POST
+ @Path("/{paymentId:" + UUID_PATTERN + "}/" + CHARGEBACKS)
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createChargeback(final InvoicePaymentTransactionJson json,
+ @PathParam("paymentId") final String paymentId,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment,
+ @javax.ws.rs.core.Context final UriInfo uriInfo,
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+
+ final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+ final UUID paymentUuid = UUID.fromString(paymentId);
+ final DirectPayment payment = paymentApi.getPayment(paymentUuid, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContext);
+ final String transactionExternalKey = json.getTransactionExternalKey() != null ? json.getTransactionExternalKey() : UUID.randomUUID().toString();
+
+ final DirectPayment result = paymentApi.createChargebackWithPaymentControl(account, payment.getId(), json.getAmount(), account.getCurrency(),
+ transactionExternalKey, createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
+ return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId());
+ }
+
@GET
@Path("/{paymentId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
@Produces(APPLICATION_JSON)
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPayment.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPayment.java
index 73a0d4e..cf46cae 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPayment.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPayment.java
@@ -40,7 +40,7 @@ public class DefaultDirectPayment extends EntityBase implements DirectPayment {
private final BigDecimal purchasedAmount;
private final BigDecimal creditAmount;
private final BigDecimal refundAmount;
- private final boolean isVoided;
+ private final Boolean isVoided;
private final Currency currency;
private final List<DirectPaymentTransaction> transactions;
@@ -135,8 +135,8 @@ public class DefaultDirectPayment extends EntityBase implements DirectPayment {
}
@Override
- public boolean isAuthVoided() {
- return false;
+ public Boolean isAuthVoided() {
+ return isVoided;
}
@Override
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..a79efe9 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,11 +37,10 @@ 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;
+ private static final boolean IS_API_PAYMENT = true;
private final DirectPaymentProcessor directPaymentProcessor;
private final PaymentMethodProcessor paymentMethodProcessor;
@@ -56,57 +55,50 @@ 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,
+ public DirectPayment createAuthorization(final Account account, final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency, @Nullable final String directPaymentExternalKey, @Nullable 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(properties, "plugin properties");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
- return directPaymentProcessor.createAuthorization(account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey,
+ return directPaymentProcessor.createAuthorization(IS_API_PAYMENT, account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey,
SHOULD_LOCK_ACCOUNT, properties, callContext, internalCallContext);
}
@Override
- public DirectPayment createCapture(final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency, final String directPaymentTransactionExternalKey,
+ public DirectPayment createCapture(final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency, @Nullable 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(properties, "plugin properties");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
- return directPaymentProcessor.createCapture(account, directPaymentId, amount, currency, directPaymentTransactionExternalKey,
+ return directPaymentProcessor.createCapture(IS_API_PAYMENT, account, directPaymentId, amount, currency, directPaymentTransactionExternalKey,
SHOULD_LOCK_ACCOUNT, properties, callContext, internalCallContext);
}
@Override
- 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,
+ public DirectPayment createPurchase(final Account account, final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency, @Nullable 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(properties, "plugin properties");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
- return directPaymentProcessor.createPurchase(account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey,
+ return directPaymentProcessor.createPurchase(IS_API_PAYMENT, account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey,
SHOULD_LOCK_ACCOUNT, properties, callContext, internalCallContext);
}
@@ -114,13 +106,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, "directPaymentTransactionExternalKey");
+ checkNotNullParameter(properties, "plugin properties");
checkPositiveAmount(amount);
if (paymentMethodId == null && !paymentOptions.isExternalPayment()) {
@@ -133,40 +124,38 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
final UUID nonNulPaymentMethodId = (paymentMethodId != null) ?
paymentMethodId :
paymentMethodProcessor.createOrGetExternalPaymentMethod(UUID.randomUUID().toString(), account, properties, callContext, internalCallContext);
- return pluginControlledPaymentProcessor.createPurchase(true, account, nonNulPaymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey,
+ return pluginControlledPaymentProcessor.createPurchase(IS_API_PAYMENT, account, nonNulPaymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey,
properties, paymentOptions.getPaymentControlPluginName(), callContext, internalCallContext);
}
@Override
- public DirectPayment createVoid(final Account account, final UUID directPaymentId, final String directPaymentTransactionExternalKey, final Iterable<PluginProperty> properties,
+ public DirectPayment createVoid(final Account account, final UUID directPaymentId, @Nullable 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(properties, "plugin properties");
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
- return directPaymentProcessor.createVoid(account, directPaymentId, directPaymentTransactionExternalKey,
+ return directPaymentProcessor.createVoid(IS_API_PAYMENT, account, directPaymentId, directPaymentTransactionExternalKey,
SHOULD_LOCK_ACCOUNT, properties, callContext, internalCallContext);
}
@Override
- public DirectPayment createRefund(final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency, final String directPaymentTransactionExternalKey, final Iterable<PluginProperty> properties,
+ public DirectPayment createRefund(final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency, @Nullable 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(properties, "plugin properties");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
- return directPaymentProcessor.createRefund(account, directPaymentId, amount, currency, directPaymentTransactionExternalKey,
+ return directPaymentProcessor.createRefund(IS_API_PAYMENT, account, directPaymentId, amount, currency, directPaymentTransactionExternalKey,
SHOULD_LOCK_ACCOUNT, properties, callContext, internalCallContext);
}
@@ -174,41 +163,36 @@ 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,
+ return pluginControlledPaymentProcessor.createRefund(IS_API_PAYMENT, account, directPaymentId, amount, currency, directPaymentTransactionExternalKey,
properties, paymentOptions.getPaymentControlPluginName(), callContext, internalCallContext);
}
@Override
public DirectPayment createCredit(final Account account, final UUID paymentMethodId, final UUID directPaymentId, final BigDecimal amount, final Currency currency,
- final String directPaymentExternalKey, final String directPaymentTransactionExternalKey,
+ @Nullable final String directPaymentExternalKey, @Nullable 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(properties, "plugin properties");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
- return directPaymentProcessor.createCredit(account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey,
+ return directPaymentProcessor.createCredit(IS_API_PAYMENT, account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey,
SHOULD_LOCK_ACCOUNT, properties, callContext, internalCallContext);
}
@@ -216,29 +200,49 @@ 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(final Account account, final UUID directPaymentTransactionId, final boolean isSuccess, final PaymentOptions paymentOptions, final CallContext context) throws PaymentApiException {
+
+ }
- checkNullParameter(account, "account");
- checkNullParameter(amount, "amount");
- checkNullParameter(currency, "currency");
- checkNullParameter(directPaymentTransactionId, "paymentTransactionId");
- checkNullParameter(chargebackTransactionExternalKey, "transactionExternalKey");
+
+ @Override
+ public DirectPayment createChargeback(final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency, final String directPaymentTransactionExternalKey, final CallContext callContext) throws PaymentApiException {
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentId, "paymentId");
checkPositiveAmount(amount);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
- return directPaymentProcessor.notifyPaymentPaymentOfChargeback(account, directPaymentTransactionId, chargebackTransactionExternalKey, amount, currency, callContext, internalCallContext);
+ return directPaymentProcessor.createChargeback(IS_API_PAYMENT, account, directPaymentId, directPaymentTransactionExternalKey, amount, currency, true,
+ callContext, internalCallContext);
+
}
+
@Override
- public List<DirectPayment> getAccountPayments(final UUID accountId, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext tenantContext) throws PaymentApiException {
+ public DirectPayment createChargebackWithPaymentControl(final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency, final String directPaymentTransactionExternalKey, final PaymentOptions paymentOptions, final CallContext callContext) throws PaymentApiException {
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(directPaymentId, "paymentId");
+ checkPositiveAmount(amount);
+
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ return pluginControlledPaymentProcessor.createChargeback(account, directPaymentId, directPaymentTransactionExternalKey, 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 {
return directPaymentProcessor.getAccountPayments(accountId, internalCallContextFactory.createInternalTenantContext(accountId, tenantContext));
}
@@ -264,7 +268,11 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
@Override
public DirectPayment getPaymentByExternalKey(final String paymentExternalKey, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext tenantContext)
throws PaymentApiException {
- return directPaymentProcessor.getPaymentByExternalKey(paymentExternalKey, withPluginInfo, properties, tenantContext, internalCallContextFactory.createInternalTenantContext(tenantContext));
+ final DirectPayment payment = directPaymentProcessor.getPaymentByExternalKey(paymentExternalKey, withPluginInfo, properties, tenantContext, internalCallContextFactory.createInternalTenantContext(tenantContext));
+ if (payment == null) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT, paymentExternalKey);
+ }
+ return payment;
}
// STEPH TODO withPluginInfo needs to be honored...
@@ -278,10 +286,8 @@ 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,
+ public UUID addPaymentMethod(final Account account, final String paymentMethodExternalKey, final String pluginName,
final boolean setDefault, final PaymentMethodPlugin paymentMethodInfo,
final Iterable<PluginProperty> properties, final CallContext context)
throws PaymentApiException {
@@ -302,7 +308,7 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
}
@Override
- public PaymentMethod getPaymentMethodByExternalKey(String paymentMethodExternalKey, boolean includedInactive, boolean withPluginInfo, Iterable<PluginProperty> properties, TenantContext context)
+ public PaymentMethod getPaymentMethodByExternalKey(final String paymentMethodExternalKey, final boolean includedInactive, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext context)
throws PaymentApiException {
return paymentMethodProcessor.getPaymentMethodByExternalKey(paymentMethodExternalKey, includedInactive, withPluginInfo, properties, context, internalCallContextFactory.createInternalTenantContext(context));
}
@@ -358,7 +364,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..cc4fa4d 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;
@@ -109,40 +108,45 @@ public class DirectPaymentProcessor extends ProcessorBase {
this.directPaymentAutomatonRunner = directPaymentAutomatonRunner;
}
- public DirectPayment createAuthorization(final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency,
+ public DirectPayment createAuthorization(final boolean isApiPayment, final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency,
final String directPaymentExternalKey, final String directPaymentTransactionExternalKey, final boolean shouldLockAccountAndDispatch,
final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
- return performOperation(TransactionType.AUTHORIZE, account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
+ return performOperation(isApiPayment, TransactionType.AUTHORIZE, account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
}
- public DirectPayment createCapture(final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency,
+ public DirectPayment createCapture(final boolean isApiPayment, final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency,
final String directPaymentTransactionExternalKey, final boolean shouldLockAccountAndDispatch,
final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
- return performOperation(TransactionType.CAPTURE, account, null, directPaymentId, amount, currency, null, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
+ return performOperation(isApiPayment, TransactionType.CAPTURE, account, null, directPaymentId, amount, currency, null, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
}
- public DirectPayment createPurchase(final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency,
+ public DirectPayment createPurchase(final boolean isApiPayment, final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency,
final String directPaymentExternalKey, final String directPaymentTransactionExternalKey, final boolean shouldLockAccountAndDispatch,
final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
- return performOperation(TransactionType.PURCHASE, account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
+ return performOperation(isApiPayment, TransactionType.PURCHASE, account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
}
- public DirectPayment createVoid(final Account account, final UUID directPaymentId, final String directPaymentTransactionExternalKey, final boolean shouldLockAccountAndDispatch,
+ public DirectPayment createVoid(final boolean isApiPayment, final Account account, final UUID directPaymentId, final String directPaymentTransactionExternalKey, final boolean shouldLockAccountAndDispatch,
final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
- return performOperation(TransactionType.VOID, account, null, directPaymentId, null, null, null, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
+ return performOperation(isApiPayment, TransactionType.VOID, account, null, directPaymentId, null, null, null, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
}
- public DirectPayment createRefund(final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency,
+ public DirectPayment createRefund(final boolean isApiPayment, final Account account, final UUID directPaymentId, final BigDecimal amount, final Currency currency,
final String directPaymentTransactionExternalKey, final boolean shouldLockAccountAndDispatch,
final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
- return performOperation(TransactionType.REFUND, account, null, directPaymentId, amount, currency, null, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
+ return performOperation(isApiPayment, TransactionType.REFUND, account, null, directPaymentId, amount, currency, null, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
}
- public DirectPayment createCredit(final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency,
+ public DirectPayment createCredit(final boolean isApiPayment, final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID directPaymentId, final BigDecimal amount, final Currency currency,
final String directPaymentExternalKey, final String directPaymentTransactionExternalKey, final boolean shouldLockAccountAndDispatch,
final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
- return performOperation(TransactionType.CREDIT, account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
+ return performOperation(isApiPayment, TransactionType.CREDIT, account, paymentMethodId, directPaymentId, amount, currency, directPaymentExternalKey, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, properties, callContext, internalCallContext);
+ }
+
+ public DirectPayment createChargeback(final boolean isApiPayment, final Account account, final UUID paymentId, final String directPaymentTransactionExternalKey, final BigDecimal amount, final Currency currency, final boolean shouldLockAccountAndDispatch,
+ final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ return performOperation(isApiPayment, TransactionType.CHARGEBACK, account, null, paymentId, amount, currency, null, directPaymentTransactionExternalKey, shouldLockAccountAndDispatch, ImmutableList.<PluginProperty>of(), callContext, internalCallContext);
}
public List<DirectPayment> getAccountPayments(final UUID accountId, final InternalTenantContext tenantContext) throws PaymentApiException {
@@ -178,28 +182,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) {
@@ -330,7 +312,7 @@ public class DirectPaymentProcessor extends ProcessorBase {
return toDirectPayment(paymentModelDao, transactionsForAccount, pluginTransactions);
}
- private DirectPayment performOperation(final TransactionType transactionType, final Account account, final UUID paymentMethodId, final UUID directPaymentId, final BigDecimal amount, final Currency currency,
+ private DirectPayment performOperation(final boolean isApiPayment, final TransactionType transactionType, final Account account, final UUID paymentMethodId, final UUID directPaymentId, final BigDecimal amount, final Currency currency,
final String directPaymentExternalKey, final String directPaymentTransactionExternalKey,
final boolean shouldLockAccountAndDispatch, final Iterable<PluginProperty> properties, final CallContext callContext,
final InternalCallContext internalCallContext) throws PaymentApiException {
@@ -354,21 +336,8 @@ public class DirectPaymentProcessor extends ProcessorBase {
directPayment = getPayment(nonNullDirectPaymentId, true, properties, callContext, internalCallContext);
return directPayment;
} finally {
- postPaymentEvent(account, transactionType, directPayment, directPaymentTransactionExternalKey, internalCallContext);
-
- }
- }
+ postPaymentEvent(isApiPayment, account, transactionType, directPayment, directPaymentTransactionExternalKey, internalCallContext);
- 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);
}
}
@@ -432,23 +401,29 @@ public class DirectPaymentProcessor extends ProcessorBase {
curPaymentModelDao.getPaymentMethodId(), curPaymentModelDao.getPaymentNumber(), curPaymentModelDao.getExternalKey(), sortedTransactions);
}
- private void postPaymentEvent(final Account account, final TransactionType transactionType, @Nullable final DirectPayment directPayment, final String transactionExternalKey, final InternalCallContext context) {
- final BusInternalEvent event = buildPaymentEvent(account, transactionType, directPayment, transactionExternalKey, context);
- postPaymentEvent(event, account.getId(), context);
+ private void postPaymentEvent(final boolean isApiPayment, final Account account, final TransactionType transactionType, @Nullable final DirectPayment directPayment, final String transactionExternalKey, final InternalCallContext context) {
+ final BusInternalEvent event = buildPaymentEvent(isApiPayment, account, transactionType, directPayment, transactionExternalKey, context);
+ if (event != null) {
+ postPaymentEvent(event, account.getId(), context);
+ }
}
- private BusInternalEvent buildPaymentEvent(final Account account, final TransactionType transactionType, @Nullable final DirectPayment directPayment, final String transactionExternalKey, final InternalCallContext context) {
+ private BusInternalEvent buildPaymentEvent(final boolean isApiPayment, final Account account, final TransactionType transactionType, @Nullable final DirectPayment directPayment, final String transactionExternalKey, final InternalCallContext context) {
+ // If an exception was thrown we don't have the payment detail but we still want to send a partially formed event for calls originating outside of API calls (e.g bus, ..)
if (directPayment == null) {
- return new DefaultPaymentErrorEvent(account.getId(),
- null,
- null,
- transactionType,
- "No payment method",
- context.getAccountRecordId(),
- context.getTenantRecordId(),
- context.getUserToken());
-
+ if (isApiPayment) {
+ return null;
+ } else {
+ return new DefaultPaymentErrorEvent(account.getId(),
+ null,
+ null,
+ transactionType,
+ "Early abortion of payment transaction",
+ context.getAccountRecordId(),
+ context.getTenantRecordId(),
+ context.getUserToken());
+ }
}
final DirectPaymentTransaction directPaymentTransaction = directPayment.getTransactions().get(directPayment.getTransactions().size() - 1);
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
index 066c19e..ca7dca0 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
@@ -433,6 +433,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
for (final PaymentMethodInfoPlugin cur : pluginPms) {
// If the kbPaymentId is NULL, the plugin does not know about it, so we create a new UUID
final UUID paymentMethodId = cur.getPaymentMethodId() != null ? cur.getPaymentMethodId() : UUID.randomUUID();
+ // TODO paymentMethod externalKey seems broken here.
final PaymentMethod input = new DefaultPaymentMethod(paymentMethodId, paymentMethodId.toString(), account.getId(), pluginName);
final PaymentMethodModelDao pmModel = new PaymentMethodModelDao(input.getId(), input.getExternalKey(), input.getCreatedDate(), input.getUpdatedDate(),
input.getAccountId(), input.getPluginName(), input.isActive());
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..7c58873 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,36 @@ 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 createChargeback(final Account account, final UUID paymentId, final String transactionExternalKey, final BigDecimal amount, final Currency currency,
+ final String paymentControlPluginName, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ return pluginControlledDirectPaymentAutomatonRunner.run(true,
+ TransactionType.CHARGEBACK,
+ account,
+ null,
+ paymentId,
+ 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..47a8ba0 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 {
@@ -171,6 +175,20 @@ public abstract class ProcessorBase {
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..5955c18
--- /dev/null
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackOperation.java
@@ -0,0 +1,85 @@
+/*
+ * 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 java.math.BigDecimal;
+
+import javax.annotation.Nullable;
+
+import org.killbill.automaton.OperationResult;
+import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.api.TransactionType;
+import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
+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;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+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());
+
+ final PaymentPluginStatus status;
+ if (!directPaymentStateContext.getOnLeavingStateExistingTransactions().isEmpty()) {
+ final Iterable<PaymentTransactionModelDao> purchaseTransactions = getOnLeavingStateExistingTransactionsForType(TransactionType.PURCHASE);
+ final Iterable<PaymentTransactionModelDao> captureTransactions = getOnLeavingStateExistingTransactionsForType(TransactionType.CAPTURE);
+ final Iterable<PaymentTransactionModelDao> refundTransactions = getOnLeavingStateExistingTransactionsForType(TransactionType.REFUND);
+ final Iterable<PaymentTransactionModelDao> chargebackTransactions = getOnLeavingStateExistingTransactionsForType(TransactionType.CHARGEBACK);
+
+ final BigDecimal purchasedAmount = getSumAmount(purchaseTransactions);
+ final BigDecimal capturedAmount = getSumAmount(captureTransactions);
+ final BigDecimal refundedAmount = getSumAmount(refundTransactions);
+ final BigDecimal chargebackAmount = getSumAmount(chargebackTransactions);
+ final BigDecimal chargebackAvailableAmount = purchasedAmount.add(capturedAmount).subtract(refundedAmount.add(chargebackAmount));
+
+ if (directPaymentStateContext.getAmount().compareTo(chargebackAvailableAmount) > 0) {
+ status = PaymentPluginStatus.ERROR;
+ } else {
+ status = PaymentPluginStatus.PROCESSED;
+ }
+ } else {
+ status = PaymentPluginStatus.PROCESSED;
+ }
+ return new DefaultNoOpPaymentInfoPlugin(directPaymentStateContext.getDirectPaymentId(),
+ directPaymentStateContext.getTransactionPaymentId(),
+ TransactionType.CHARGEBACK,
+ directPaymentStateContext.getAmount(),
+ directPaymentStateContext.getCurrency(),
+ null,
+ null,
+ status,
+ null);
+ }
+}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentAutomatonDAOHelper.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentAutomatonDAOHelper.java
index 5a3c457..dc6e161 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentAutomatonDAOHelper.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentAutomatonDAOHelper.java
@@ -18,6 +18,7 @@
package org.killbill.billing.payment.core.sm;
import java.math.BigDecimal;
+import java.util.List;
import java.util.UUID;
import javax.annotation.Nullable;
@@ -29,13 +30,15 @@ import org.killbill.billing.catalog.api.Currency;
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.PaymentModelDao;
-import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.dao.PaymentDao;
import org.killbill.billing.payment.dao.PaymentMethodModelDao;
+import org.killbill.billing.payment.dao.PaymentModelDao;
+import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin;
+import com.google.common.collect.ImmutableList;
+
public class DirectPaymentAutomatonDAOHelper {
protected final DirectPaymentStateContext directPaymentStateContext;
@@ -58,21 +61,33 @@ public class DirectPaymentAutomatonDAOHelper {
this.internalCallContext = internalCallContext;
}
- public void createNewDirectPaymentTransaction() {
+ public void createNewDirectPaymentTransaction() throws PaymentApiException {
+
final PaymentTransactionModelDao paymentTransactionModelDao;
+ final List<PaymentTransactionModelDao> existingTransactions;
if (directPaymentStateContext.getDirectPaymentId() == null) {
final PaymentModelDao newPaymentModelDao = buildNewDirectPaymentModelDao();
final PaymentTransactionModelDao newPaymentTransactionModelDao = buildNewDirectPaymentTransactionModelDao(newPaymentModelDao.getId());
+ existingTransactions = ImmutableList.of();
final PaymentModelDao paymentModelDao = paymentDao.insertDirectPaymentWithFirstTransaction(newPaymentModelDao, newPaymentTransactionModelDao, internalCallContext);
paymentTransactionModelDao = paymentDao.getDirectTransactionsForDirectPayment(paymentModelDao.getId(), internalCallContext).get(0);
+
} else {
+ existingTransactions = paymentDao.getDirectTransactionsForDirectPayment(directPaymentStateContext.getDirectPaymentId(), internalCallContext);
+ if (existingTransactions.isEmpty()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_SUCCESS_PAYMENT, directPaymentStateContext.getDirectPaymentId());
+ }
+ if (directPaymentStateContext.getCurrency() != null && existingTransactions.get(0).getCurrency() != directPaymentStateContext.getCurrency()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_INVALID_PARAMETER, "currency", " should be " + existingTransactions.get(0).getCurrency() + " to match other existing transactions");
+ }
+
final PaymentTransactionModelDao newPaymentTransactionModelDao = buildNewDirectPaymentTransactionModelDao(directPaymentStateContext.getDirectPaymentId());
paymentTransactionModelDao = paymentDao.updateDirectPaymentWithNewTransaction(directPaymentStateContext.getDirectPaymentId(), newPaymentTransactionModelDao, internalCallContext);
}
-
// Update the context
directPaymentStateContext.setDirectPaymentTransactionModelDao(paymentTransactionModelDao);
+ directPaymentStateContext.setOnLeavingStateExistingTransactions(existingTransactions);
}
public void processPaymentInfoPlugin(final TransactionStatus paymentStatus, @Nullable final PaymentTransactionInfoPlugin paymentInfoPlugin,
@@ -128,10 +143,10 @@ public class DirectPaymentAutomatonDAOHelper {
final DateTime updatedDate = utcNow;
return new PaymentModelDao(createdDate,
- updatedDate,
- directPaymentStateContext.getAccount().getId(),
- directPaymentStateContext.getPaymentMethodId(),
- directPaymentStateContext.getDirectPaymentExternalKey());
+ updatedDate,
+ directPaymentStateContext.getAccount().getId(),
+ directPaymentStateContext.getPaymentMethodId(),
+ directPaymentStateContext.getDirectPaymentExternalKey());
}
private PaymentTransactionModelDao buildNewDirectPaymentTransactionModelDao(final UUID directPaymentId) {
@@ -142,16 +157,16 @@ public class DirectPaymentAutomatonDAOHelper {
final String gatewayErrorMsg = null;
return new PaymentTransactionModelDao(createdDate,
- updatedDate,
- directPaymentStateContext.getDirectPaymentTransactionExternalKey(),
- directPaymentId,
- directPaymentStateContext.getTransactionType(),
- effectiveDate,
- TransactionStatus.UNKNOWN,
- directPaymentStateContext.getAmount(),
- directPaymentStateContext.getCurrency(),
- gatewayErrorCode,
- gatewayErrorMsg);
+ updatedDate,
+ directPaymentStateContext.getDirectPaymentTransactionExternalKey(),
+ directPaymentId,
+ directPaymentStateContext.getTransactionType(),
+ effectiveDate,
+ TransactionStatus.UNKNOWN,
+ directPaymentStateContext.getAmount(),
+ directPaymentStateContext.getCurrency(),
+ gatewayErrorCode,
+ gatewayErrorMsg);
}
private PaymentPluginApi getPaymentPluginApi(final String pluginName) throws PaymentApiException {
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/DirectPaymentEnteringStateCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentEnteringStateCallback.java
index c63e8d8..633e089 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentEnteringStateCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentEnteringStateCallback.java
@@ -48,13 +48,12 @@ public abstract class DirectPaymentEnteringStateCallback implements EnteringStat
public void enteringState(final State newState, final Operation.OperationCallback operationCallback, final OperationResult operationResult, final LeavingStateCallback leavingStateCallback) {
logger.debug("Entering state {} with result {}", newState.getName(), operationResult);
- // Check for illegal state (should never happen)
- Preconditions.checkState(directPaymentStateContext.getDirectPaymentTransactionModelDao() != null && directPaymentStateContext.getDirectPaymentTransactionModelDao().getId() != null);
-
- final PaymentTransactionInfoPlugin paymentInfoPlugin = directPaymentStateContext.getPaymentInfoPlugin();
- final TransactionStatus paymentStatus = paymentPluginStatusToPaymentStatus(paymentInfoPlugin, operationResult);
-
- daoHelper.processPaymentInfoPlugin(paymentStatus, paymentInfoPlugin, newState.getName());
+ // If the transaction was not created -- for instance we had an exception in leavingState callback then we bail; if not, then update state:
+ if (directPaymentStateContext.getDirectPaymentTransactionModelDao() != null && directPaymentStateContext.getDirectPaymentTransactionModelDao().getId() != null) {
+ final PaymentTransactionInfoPlugin paymentInfoPlugin = directPaymentStateContext.getPaymentInfoPlugin();
+ final TransactionStatus paymentStatus = paymentPluginStatusToPaymentStatus(paymentInfoPlugin, operationResult);
+ daoHelper.processPaymentInfoPlugin(paymentStatus, paymentInfoPlugin, newState.getName());
+ }
}
private TransactionStatus paymentPluginStatusToPaymentStatus(@Nullable final PaymentTransactionInfoPlugin paymentInfoPlugin, final OperationResult operationResult) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentLeavingStateCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentLeavingStateCallback.java
index 223837f..8790cfa 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentLeavingStateCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentLeavingStateCallback.java
@@ -17,6 +17,7 @@
package org.killbill.billing.payment.core.sm;
+import org.killbill.automaton.OperationException;
import org.killbill.automaton.State;
import org.killbill.automaton.State.LeavingStateCallback;
import org.killbill.billing.payment.api.PaymentApiException;
@@ -34,10 +35,14 @@ public abstract class DirectPaymentLeavingStateCallback implements LeavingStateC
}
@Override
- public void leavingState(final State oldState) {
+ public void leavingState(final State oldState) throws OperationException {
logger.debug("Leaving state {}", oldState.getName());
// Create or update the direct payment and transaction
- daoHelper.createNewDirectPaymentTransaction();
+ try {
+ daoHelper.createNewDirectPaymentTransaction();
+ } catch (PaymentApiException e) {
+ throw new OperationException(e);
+ }
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentOperation.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentOperation.java
index c519331..cf6e6c5 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentOperation.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentOperation.java
@@ -17,6 +17,8 @@
package org.killbill.billing.payment.core.sm;
+import java.math.BigDecimal;
+import java.util.Iterator;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -25,7 +27,10 @@ import org.killbill.automaton.OperationException;
import org.killbill.automaton.OperationResult;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.api.TransactionStatus;
+import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.core.ProcessorBase.WithAccountLockCallback;
+import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.dispatcher.PluginDispatcher;
import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.payment.plugin.api.PaymentPluginApiException;
@@ -36,16 +41,21 @@ import org.killbill.commons.locker.LockFailedException;
import com.google.common.base.Objects;
import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
// Encapsulates the payment specific logic
public abstract class DirectPaymentOperation extends OperationCallbackBase implements OperationCallback {
protected final PaymentPluginApi plugin;
+ protected final DirectPaymentAutomatonDAOHelper daoHelper;
protected DirectPaymentOperation(final DirectPaymentAutomatonDAOHelper daoHelper, final GlobalLocker locker,
final PluginDispatcher<OperationResult> paymentPluginDispatcher,
final DirectPaymentStateContext directPaymentStateContext) throws PaymentApiException {
super(locker, paymentPluginDispatcher, directPaymentStateContext);
+ this.daoHelper = daoHelper;
this.plugin = daoHelper.getPaymentProviderPlugin();
}
@@ -92,6 +102,27 @@ public abstract class DirectPaymentOperation extends OperationCallbackBase imple
@Override
protected abstract PaymentTransactionInfoPlugin doCallSpecificOperationCallback() throws PaymentPluginApiException;
+ protected Iterable<PaymentTransactionModelDao> getOnLeavingStateExistingTransactionsForType(final TransactionType transactionType) {
+ if (directPaymentStateContext.getOnLeavingStateExistingTransactions() == null || directPaymentStateContext.getOnLeavingStateExistingTransactions().isEmpty()) {
+ return ImmutableList.of();
+ }
+ return Iterables.filter(directPaymentStateContext.getOnLeavingStateExistingTransactions(), new Predicate<PaymentTransactionModelDao>() {
+ @Override
+ public boolean apply(final PaymentTransactionModelDao input) {
+ return input.getTransactionStatus() == TransactionStatus.SUCCESS && input.getTransactionType() == transactionType;
+ }
+ });
+ }
+
+ protected BigDecimal getSumAmount(final Iterable<PaymentTransactionModelDao> transactions) {
+ BigDecimal result = BigDecimal.ZERO;
+ Iterator<PaymentTransactionModelDao> iterator = transactions.iterator();
+ while (iterator.hasNext()) {
+ result = result.add(iterator.next().getAmount());
+ }
+ return result;
+ }
+
private OperationResult doOperationCallbackWithDispatchAndAccountLock() throws OperationException {
return dispatchWithAccountLockAndTimeout(new WithAccountLockCallback<OperationResult, OperationException>() {
@Override
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentStateContext.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentStateContext.java
index d8019dc..dfeeaa6 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentStateContext.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentStateContext.java
@@ -18,6 +18,7 @@
package org.killbill.billing.payment.core.sm;
import java.math.BigDecimal;
+import java.util.List;
import java.util.UUID;
import javax.annotation.Nullable;
@@ -31,12 +32,15 @@ import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin;
import org.killbill.billing.util.callcontext.CallContext;
+import com.google.common.collect.ImmutableList;
+
public class DirectPaymentStateContext {
// HACK
protected UUID paymentMethodId;
// Stateful objects created by the callbacks and passed to the other following callbacks in the automaton
+ protected List<PaymentTransactionModelDao> onLeavingStateExistingTransactions;
protected PaymentTransactionModelDao directPaymentTransactionModelDao;
protected PaymentTransactionInfoPlugin paymentInfoPlugin;
protected BigDecimal amount;
@@ -81,6 +85,7 @@ public class DirectPaymentStateContext {
this.properties = properties;
this.internalCallContext = internalCallContext;
this.callContext = callContext;
+ this.onLeavingStateExistingTransactions = ImmutableList.of();
}
public void setPaymentMethodId(final UUID paymentMethodId) {
@@ -95,6 +100,14 @@ public class DirectPaymentStateContext {
this.directPaymentTransactionModelDao = directPaymentTransactionModelDao;
}
+ public List<PaymentTransactionModelDao> getOnLeavingStateExistingTransactions() {
+ return onLeavingStateExistingTransactions;
+ }
+
+ public void setOnLeavingStateExistingTransactions(final List<PaymentTransactionModelDao> onLeavingStateExistingTransactions) {
+ this.onLeavingStateExistingTransactions = onLeavingStateExistingTransactions;
+ }
+
public PaymentTransactionInfoPlugin getPaymentInfoPlugin() {
return paymentInfoPlugin;
}
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/RetryAuthorizeOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryAuthorizeOperationCallback.java
index 5993143..5159d46 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryAuthorizeOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryAuthorizeOperationCallback.java
@@ -33,6 +33,17 @@ public class RetryAuthorizeOperationCallback extends RetryOperationCallback {
@Override
protected DirectPayment doCallSpecificOperationCallback() throws PaymentApiException {
- return directPaymentProcessor.createAuthorization(directPaymentStateContext.account, directPaymentStateContext.paymentMethodId, directPaymentStateContext.directPaymentId, directPaymentStateContext.getAmount(), directPaymentStateContext.getCurrency(), directPaymentStateContext.directPaymentExternalKey, directPaymentStateContext.directPaymentTransactionExternalKey, false, directPaymentStateContext.getProperties(), directPaymentStateContext.callContext, directPaymentStateContext.internalCallContext);
+ return directPaymentProcessor.createAuthorization(retryableDirectPaymentStateContext.isApiPayment(),
+ retryableDirectPaymentStateContext.getAccount(),
+ retryableDirectPaymentStateContext.getPaymentMethodId(),
+ retryableDirectPaymentStateContext.getDirectPaymentId(),
+ retryableDirectPaymentStateContext.getAmount(),
+ retryableDirectPaymentStateContext.getCurrency(),
+ retryableDirectPaymentStateContext.getDirectPaymentExternalKey(),
+ retryableDirectPaymentStateContext.getDirectPaymentTransactionExternalKey(),
+ false,
+ retryableDirectPaymentStateContext.getProperties(),
+ retryableDirectPaymentStateContext.getCallContext(),
+ retryableDirectPaymentStateContext.getInternalCallContext());
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCaptureOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCaptureOperationCallback.java
index 508a83e..88cd362 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCaptureOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCaptureOperationCallback.java
@@ -33,10 +33,15 @@ public class RetryCaptureOperationCallback extends RetryOperationCallback {
@Override
protected DirectPayment doCallSpecificOperationCallback() throws PaymentApiException {
- return directPaymentProcessor.createCapture(directPaymentStateContext.account, directPaymentStateContext.directPaymentId,
- directPaymentStateContext.getAmount(), directPaymentStateContext.getCurrency(),
- directPaymentStateContext.directPaymentTransactionExternalKey,
- false, directPaymentStateContext.getProperties(),
- directPaymentStateContext.callContext, directPaymentStateContext.internalCallContext);
+ return directPaymentProcessor.createCapture(retryableDirectPaymentStateContext.isApiPayment(),
+ retryableDirectPaymentStateContext.getAccount(),
+ retryableDirectPaymentStateContext.getPaymentMethodId(),
+ retryableDirectPaymentStateContext.getAmount(),
+ retryableDirectPaymentStateContext.getCurrency(),
+ retryableDirectPaymentStateContext.getDirectPaymentTransactionExternalKey(),
+ false,
+ retryableDirectPaymentStateContext.getProperties(),
+ retryableDirectPaymentStateContext.getCallContext(),
+ retryableDirectPaymentStateContext.getInternalCallContext());
}
}
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..d442ceb
--- /dev/null
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryChargebackOperationCallback.java
@@ -0,0 +1,47 @@
+/*
+ * 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.createChargeback(retryableDirectPaymentStateContext.isApiPayment(),
+ retryableDirectPaymentStateContext.getAccount(),
+ retryableDirectPaymentStateContext.getDirectPaymentId(),
+ retryableDirectPaymentStateContext.getDirectPaymentTransactionExternalKey(),
+ retryableDirectPaymentStateContext.getAmount(),
+ retryableDirectPaymentStateContext.getCurrency(),
+ false,
+ retryableDirectPaymentStateContext.getCallContext(),
+ retryableDirectPaymentStateContext.getInternalCallContext());
+ }
+}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCreditOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCreditOperationCallback.java
index 6f25017..1b309d9 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCreditOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCreditOperationCallback.java
@@ -33,6 +33,17 @@ public class RetryCreditOperationCallback extends RetryOperationCallback {
@Override
protected DirectPayment doCallSpecificOperationCallback() throws PaymentApiException {
- return directPaymentProcessor.createCredit(directPaymentStateContext.account, directPaymentStateContext.paymentMethodId, directPaymentStateContext.directPaymentId, directPaymentStateContext.getAmount(), directPaymentStateContext.getCurrency(), directPaymentStateContext.directPaymentExternalKey, directPaymentStateContext.directPaymentTransactionExternalKey, false, directPaymentStateContext.getProperties(), directPaymentStateContext.callContext, directPaymentStateContext.internalCallContext);
+ return directPaymentProcessor.createCredit(retryableDirectPaymentStateContext.isApiPayment(),
+ retryableDirectPaymentStateContext.getAccount(),
+ retryableDirectPaymentStateContext.getPaymentMethodId(),
+ retryableDirectPaymentStateContext.getDirectPaymentId(),
+ retryableDirectPaymentStateContext.getAmount(),
+ retryableDirectPaymentStateContext.getCurrency(),
+ retryableDirectPaymentStateContext.getDirectPaymentExternalKey(),
+ retryableDirectPaymentStateContext.getDirectPaymentTransactionExternalKey(),
+ false,
+ retryableDirectPaymentStateContext.getProperties(),
+ retryableDirectPaymentStateContext.getCallContext(),
+ retryableDirectPaymentStateContext.getInternalCallContext());
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryLeavingStateCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryLeavingStateCallback.java
index 31a3674..2c1d56b 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryLeavingStateCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryLeavingStateCallback.java
@@ -57,7 +57,7 @@ public class RetryLeavingStateCallback implements LeavingStateCallback {
final DateTime utcNow = retryableDirectPaymentAutomatonRunner.clock.getUTCNow();
- Preconditions.checkState(stateContext.getDirectPaymentExternalKey() != null || /* AUTH, PURCHASE, CREDIT calls will provide the payment */
+ Preconditions.checkState(stateContext.getDirectPaymentExternalKey() != null || /* CAPTURE, PURCHASE, CREDIT calls will provide the paymentId */
stateContext.getDirectPaymentId() != null);
if (stateContext.getDirectPaymentExternalKey() == null) {
final PaymentModelDao payment = paymentDao.getDirectPayment(stateContext.getDirectPaymentId(), stateContext.internalCallContext);
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java
index 5f44768..7c7bd6e 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java
@@ -53,15 +53,19 @@ import org.slf4j.LoggerFactory;
public abstract class RetryOperationCallback extends OperationCallbackBase implements OperationCallback {
- protected final DirectPaymentProcessor directPaymentProcessor;
private final OSGIServiceRegistration<PaymentControlPluginApi> paymentControlPluginRegistry;
+ protected final DirectPaymentProcessor directPaymentProcessor;
+ protected final RetryableDirectPaymentStateContext retryableDirectPaymentStateContext;
+
+
private final Logger logger = LoggerFactory.getLogger(RetryOperationCallback.class);
protected RetryOperationCallback(final GlobalLocker locker, final PluginDispatcher<OperationResult> paymentPluginDispatcher, final RetryableDirectPaymentStateContext directPaymentStateContext, final DirectPaymentProcessor directPaymentProcessor, final OSGIServiceRegistration<PaymentControlPluginApi> retryPluginRegistry) {
super(locker, paymentPluginDispatcher, directPaymentStateContext);
this.directPaymentProcessor = directPaymentProcessor;
this.paymentControlPluginRegistry = retryPluginRegistry;
+ this.retryableDirectPaymentStateContext = directPaymentStateContext;
}
@@ -76,7 +80,6 @@ public abstract class RetryOperationCallback extends OperationCallbackBase imple
@Override
public OperationResult doOperation() throws OperationException {
- final RetryableDirectPaymentStateContext retryableDirectPaymentStateContext = (RetryableDirectPaymentStateContext) directPaymentStateContext;
final PaymentControlContext paymentControlContext = new DefaultPaymentControlContext(directPaymentStateContext.getAccount(),
directPaymentStateContext.getPaymentMethodId(),
retryableDirectPaymentStateContext.getAttemptId(),
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryPurchaseOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryPurchaseOperationCallback.java
index 7876e9e..1e5636a 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryPurchaseOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryPurchaseOperationCallback.java
@@ -33,8 +33,17 @@ public class RetryPurchaseOperationCallback extends RetryOperationCallback {
@Override
protected DirectPayment doCallSpecificOperationCallback() throws PaymentApiException {
- return directPaymentProcessor.createPurchase(directPaymentStateContext.account, directPaymentStateContext.paymentMethodId, directPaymentStateContext.directPaymentId, directPaymentStateContext.getAmount(),
- directPaymentStateContext.getCurrency(), directPaymentStateContext.directPaymentExternalKey, directPaymentStateContext.directPaymentTransactionExternalKey, false,
- directPaymentStateContext.getProperties(), directPaymentStateContext.callContext, directPaymentStateContext.internalCallContext);
+ return directPaymentProcessor.createPurchase(retryableDirectPaymentStateContext.isApiPayment(),
+ retryableDirectPaymentStateContext.getAccount(),
+ retryableDirectPaymentStateContext.getPaymentMethodId(),
+ retryableDirectPaymentStateContext.getDirectPaymentId(),
+ retryableDirectPaymentStateContext.getAmount(),
+ retryableDirectPaymentStateContext.getCurrency(),
+ retryableDirectPaymentStateContext.getDirectPaymentExternalKey(),
+ retryableDirectPaymentStateContext.getDirectPaymentTransactionExternalKey(),
+ false,
+ retryableDirectPaymentStateContext.getProperties(),
+ retryableDirectPaymentStateContext.getCallContext(),
+ retryableDirectPaymentStateContext.getInternalCallContext());
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryRefundOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryRefundOperationCallback.java
index 414f2f8..2fc77fb 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryRefundOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryRefundOperationCallback.java
@@ -33,6 +33,15 @@ public class RetryRefundOperationCallback extends RetryOperationCallback {
@Override
protected DirectPayment doCallSpecificOperationCallback() throws PaymentApiException {
- return directPaymentProcessor.createRefund(directPaymentStateContext.account, directPaymentStateContext.directPaymentId, directPaymentStateContext.getAmount(), directPaymentStateContext.getCurrency(), directPaymentStateContext.directPaymentTransactionExternalKey, false, directPaymentStateContext.getProperties(), directPaymentStateContext.callContext, directPaymentStateContext.internalCallContext);
+ return directPaymentProcessor.createRefund(retryableDirectPaymentStateContext.isApiPayment(),
+ retryableDirectPaymentStateContext.getAccount(),
+ retryableDirectPaymentStateContext.getDirectPaymentId(),
+ retryableDirectPaymentStateContext.getAmount(),
+ retryableDirectPaymentStateContext.getCurrency(),
+ retryableDirectPaymentStateContext.getDirectPaymentTransactionExternalKey(),
+ false,
+ retryableDirectPaymentStateContext.getProperties(),
+ retryableDirectPaymentStateContext.getCallContext(),
+ retryableDirectPaymentStateContext.getInternalCallContext());
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryVoidOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryVoidOperationCallback.java
index 45ea703..a2f2382 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryVoidOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryVoidOperationCallback.java
@@ -33,6 +33,13 @@ public class RetryVoidOperationCallback extends RetryOperationCallback {
@Override
protected DirectPayment doCallSpecificOperationCallback() throws PaymentApiException {
- return directPaymentProcessor.createVoid(directPaymentStateContext.account, directPaymentStateContext.directPaymentId, directPaymentStateContext.directPaymentTransactionExternalKey, false, directPaymentStateContext.getProperties(), directPaymentStateContext.callContext, directPaymentStateContext.internalCallContext);
+ return directPaymentProcessor.createVoid(retryableDirectPaymentStateContext.isApiPayment(),
+ retryableDirectPaymentStateContext.getAccount(),
+ retryableDirectPaymentStateContext.getDirectPaymentId(),
+ retryableDirectPaymentStateContext.getDirectPaymentTransactionExternalKey(),
+ false,
+ retryableDirectPaymentStateContext.getProperties(),
+ retryableDirectPaymentStateContext.getCallContext(),
+ retryableDirectPaymentStateContext.getInternalCallContext());
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentMethodModelDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentMethodModelDao.java
index 5475e17..38b9adb 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentMethodModelDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentMethodModelDao.java
@@ -27,6 +27,8 @@ import org.killbill.billing.util.dao.TableName;
import org.killbill.billing.entity.EntityBase;
import org.killbill.billing.util.entity.dao.EntityModelDao;
+import com.google.common.base.Objects;
+
public class PaymentMethodModelDao extends EntityBase implements EntityModelDao<PaymentMethod> {
private String externalKey;
@@ -36,11 +38,11 @@ public class PaymentMethodModelDao extends EntityBase implements EntityModelDao<
public PaymentMethodModelDao() { /* For the DAO mapper */ }
- public PaymentMethodModelDao(final UUID id, final String externalKey, @Nullable final DateTime createdDate, @Nullable final DateTime updatedDate,
+ public PaymentMethodModelDao(final UUID id, @Nullable final String externalKey, @Nullable final DateTime createdDate, @Nullable final DateTime updatedDate,
final UUID accountId, final String pluginName,
final Boolean isActive) {
super(id, createdDate, updatedDate);
- this.externalKey = externalKey;
+ this.externalKey = Objects.firstNonNull(externalKey, id.toString());
this.accountId = accountId;
this.pluginName = pluginName;
this.isActive = isActive;
@@ -120,9 +122,12 @@ public class PaymentMethodModelDao extends EntityBase implements EntityModelDao<
if (id != null ? !id.equals(that.id) : that.id != null) {
return false;
}
+ /*
+ TODO unclear
if (externalKey != null ? !externalKey.equals(that.externalKey) : that.externalKey != null) {
return false;
}
+ */
if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) {
return false;
}
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..b487b9c 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
+++ b/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
@@ -235,21 +235,32 @@
<operation name="OP_VOID"/>
</operations>
</stateMachine>
- <!-- The transition to the state CHARGEBACK_SUCCESS occurs outside of the state machine engine (at least for now).
- It needs to exist but there is no need for a linkStateMachine Transition to reach that state.
- -->
<stateMachine name="CHARGEBACK">
<states>
<state name="CHARGEBACK_INIT"/>
<state name="CHARGEBACK_SUCCESS"/>
+ <state name="CHARGEBACK_FAILED"/>
+ <state name="CHARGEBACK_ERRORED"/>
</states>
<transitions>
- <transition>
- <initialState>CHARGEBACK_INIT</initialState>
- <operation>OP_CHARGEBACK</operation>
- <operationResult>SUCCESS</operationResult>
- <finalState>CHARGEBACK_SUCCESS</finalState>
- </transition>
+ <transition>
+ <initialState>CHARGEBACK_INIT</initialState>
+ <operation>OP_CHARGEBACK</operation>
+ <operationResult>SUCCESS</operationResult>
+ <finalState>CHARGEBACK_SUCCESS</finalState>
+ </transition>
+ <transition>
+ <initialState>CHARGEBACK_INIT</initialState>
+ <operation>OP_CHARGEBACK</operation>
+ <operationResult>FAILURE</operationResult>
+ <finalState>CHARGEBACK_FAILED</finalState>
+ </transition>
+ <transition>
+ <initialState>CHARGEBACK_INIT</initialState>
+ <operation>OP_CHARGEBACK</operation>
+ <operationResult>EXCEPTION</operationResult>
+ <finalState>CHARGEBACK_ERRORED</finalState>
+ </transition>
</transitions>
<operations>
<operation name="OP_CHARGEBACK"/>
@@ -290,6 +301,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>
@@ -302,22 +319,57 @@
</linkStateMachine>
<linkStateMachine>
<initialStateMachine>REFUND</initialStateMachine>
- <initialState>REFUND_FAILED</initialState>
+ <initialState>REFUND_SUCCESS</initialState>
<finalStateMachine>REFUND</finalStateMachine>
<finalState>REFUND_INIT</finalState>
</linkStateMachine>
<linkStateMachine>
<initialStateMachine>REFUND</initialStateMachine>
- <initialState>REFUND_SUCCESS</initialState>
+ <initialState>REFUND_FAILED</initialState>
<finalStateMachine>REFUND</finalStateMachine>
<finalState>REFUND_INIT</finalState>
</linkStateMachine>
<linkStateMachine>
+ <initialStateMachine>REFUND</initialStateMachine>
+ <initialState>REFUND_SUCCESS</initialState>
+ <finalStateMachine>CHARGEBACK</finalStateMachine>
+ <finalState>CHARGEBACK_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
+ <initialStateMachine>REFUND</initialStateMachine>
+ <initialState>REFUND_FAILED</initialState>
+ <finalStateMachine>CHARGEBACK</finalStateMachine>
+ <finalState>CHARGEBACK_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
<initialStateMachine>PURCHASE</initialStateMachine>
<initialState>PURCHASE_SUCCESS</initialState>
<finalStateMachine>REFUND</finalStateMachine>
<finalState>REFUND_INIT</finalState>
</linkStateMachine>
+ <linkStateMachine>
+ <initialStateMachine>PURCHASE</initialStateMachine>
+ <initialState>PURCHASE_SUCCESS</initialState>
+ <finalStateMachine>CHARGEBACK</finalStateMachine>
+ <finalState>CHARGEBACK_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
+ <initialStateMachine>CHARGEBACK</initialStateMachine>
+ <initialState>CHARGEBACK_SUCCESS</initialState>
+ <finalStateMachine>CHARGEBACK</finalStateMachine>
+ <finalState>CHARGEBACK_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
+ <initialStateMachine>CHARGEBACK</initialStateMachine>
+ <initialState>CHARGEBACK_FAILED</initialState>
+ <finalStateMachine>CHARGEBACK</finalStateMachine>
+ <finalState>CHARGEBACK_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
+ <initialStateMachine>CHARGEBACK</initialStateMachine>
+ <initialState>CHARGEBACK_ERRORED</initialState>
+ <finalStateMachine>CHARGEBACK</finalStateMachine>
+ <finalState>CHARGEBACK_INIT</finalState>
+ </linkStateMachine>
</linkStateMachines>
-
</stateMachineConfig>
diff --git a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
index a1557e5..f47842b 100644
--- a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
@@ -440,7 +440,7 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
final DirectPayment payment = paymentApi.createPurchase(account, account.getPaymentMethodId(), null, requestedAmount, Currency.AED, paymentExternalKey, transactionExternalKey,
ImmutableList.<PluginProperty>of(), callContext);
- paymentApi.notifyChargeback(account, payment.getTransactions().get(0).getId(), transactionExternalKey2, requestedAmount, Currency.AED, callContext);
+ paymentApi.createChargeback(account, payment.getId(), requestedAmount, Currency.AED, transactionExternalKey2, callContext);
final DirectPayment payment2 = paymentApi.getPayment(payment.getId(), false, ImmutableList.<PluginProperty>of(), callContext);
assertEquals(payment2.getExternalKey(), paymentExternalKey);
@@ -506,6 +506,47 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
}
}
+ @Test(groups = "fast")
+ public void testSimpleAuthCaptureWithInvalidPaymentId() throws Exception {
+ final BigDecimal requestedAmount = new BigDecimal("80.0091");
+
+ final DirectPayment initialPayment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), null, requestedAmount, account.getCurrency(),
+ UUID.randomUUID().toString(), UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), callContext);
+
+
+ try {
+ paymentApi.createCapture(account, UUID.randomUUID(), requestedAmount, account.getCurrency(), UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), callContext);
+ Assert.fail("Expected capture to fail...");
+ } catch (PaymentApiException e) {
+ Assert.assertEquals(e.getCode(), ErrorCode.PAYMENT_NO_SUCH_PAYMENT.getCode());
+
+ final DirectPayment latestPayment = paymentApi.getPayment(initialPayment.getId(), false, ImmutableList.<PluginProperty>of(), callContext);
+ assertEquals(latestPayment, initialPayment);
+ }
+ }
+
+
+ @Test(groups = "fast")
+ public void testSimpleAuthCaptureWithInvalidCurrency() throws Exception {
+ final BigDecimal requestedAmount = new BigDecimal("80.0091");
+
+ final DirectPayment initialPayment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), null, requestedAmount, account.getCurrency(),
+ UUID.randomUUID().toString(), UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), callContext);
+
+
+ try {
+ paymentApi.createCapture(account, initialPayment.getId(), requestedAmount, Currency.AMD, UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), callContext);
+ Assert.fail("Expected capture to fail...");
+ } catch (PaymentApiException e) {
+ Assert.assertEquals(e.getCode(), ErrorCode.PAYMENT_INVALID_PARAMETER.getCode());
+
+ final DirectPayment latestPayment = paymentApi.getPayment(initialPayment.getId(), false, ImmutableList.<PluginProperty>of(), callContext);
+ assertEquals(latestPayment, initialPayment);
+ }
+ }
+
+
+
private List<PluginProperty> createPropertiesForInvoice(final Invoice invoice) {
final List<PluginProperty> result = new ArrayList<PluginProperty>();
result.add(new PluginProperty(InvoicePaymentControlPluginApi.PROP_IPCD_INVOICE_ID, invoice.getId().toString(), false));
diff --git a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiNoDB.java b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiNoDB.java
index e5fda6b..38f777e 100644
--- a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiNoDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiNoDB.java
@@ -78,7 +78,7 @@ public class TestPaymentApiNoDB extends PaymentTestSuiteNoDB {
}
@Test(groups = "fast")
- public void testSimplePaymentWithNoAmount() throws Exception {
+ public void testSimpleInvoicePaymentWithNoAmount() throws Exception {
final BigDecimal invoiceAmount = new BigDecimal("10.0011");
final BigDecimal requestedAmount = null;
final BigDecimal expectedAmount = null;
@@ -87,7 +87,7 @@ public class TestPaymentApiNoDB extends PaymentTestSuiteNoDB {
}
@Test(groups = "fast")
- public void testSimplePaymentWithInvoiceAmount() throws Exception {
+ public void testSimpleInvoicePaymentWithInvoiceAmount() throws Exception {
final BigDecimal invoiceAmount = new BigDecimal("10.0011");
final BigDecimal requestedAmount = invoiceAmount;
final BigDecimal expectedAmount = invoiceAmount;
@@ -96,7 +96,7 @@ public class TestPaymentApiNoDB extends PaymentTestSuiteNoDB {
}
@Test(groups = "fast")
- public void testSimplePaymentWithLowerAmount() throws Exception {
+ public void testSimpleInvoicePaymentWithLowerAmount() throws Exception {
final BigDecimal invoiceAmount = new BigDecimal("10.0011");
final BigDecimal requestedAmount = new BigDecimal("8.0091");
final BigDecimal expectedAmount = requestedAmount;
@@ -105,7 +105,7 @@ public class TestPaymentApiNoDB extends PaymentTestSuiteNoDB {
}
@Test(groups = "fast")
- public void testSimplePaymentWithInvalidAmount() throws Exception {
+ public void testSimpleInvoicePaymentWithInvalidAmount() throws Exception {
final BigDecimal invoiceAmount = new BigDecimal("10.0011");
final BigDecimal requestedAmount = new BigDecimal("80.0091");
final BigDecimal expectedAmount = null;
@@ -170,7 +170,7 @@ public class TestPaymentApiNoDB extends PaymentTestSuiteNoDB {
assertEquals(initDefaultMethod.getId(), account.getPaymentMethodId());
final PaymentMethodPlugin newPaymenrMethod = new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), true, null);
- final UUID newPaymentMethodId = paymentApi.addPaymentMethod(UUID.randomUUID().toString(), account, MockPaymentProviderPlugin.PLUGIN_NAME, true, newPaymenrMethod, PLUGIN_PROPERTIES, callContext);
+ final UUID newPaymentMethodId = paymentApi.addPaymentMethod(account, UUID.randomUUID().toString(), MockPaymentProviderPlugin.PLUGIN_NAME, true, newPaymenrMethod, PLUGIN_PROPERTIES, callContext);
Mockito.when(account.getPaymentMethodId()).thenReturn(newPaymentMethodId);
methods = paymentApi.getAccountPaymentMethods(account.getId(), false, PLUGIN_PROPERTIES, callContext);
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestDirectPaymentEnteringStateCallback.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestDirectPaymentEnteringStateCallback.java
index c665585..b976bc7 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestDirectPaymentEnteringStateCallback.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestDirectPaymentEnteringStateCallback.java
@@ -21,6 +21,7 @@ import java.math.BigDecimal;
import java.util.UUID;
import org.killbill.automaton.Operation.OperationCallback;
+import org.killbill.automaton.OperationException;
import org.killbill.automaton.OperationResult;
import org.killbill.automaton.State;
import org.killbill.automaton.State.LeavingStateCallback;
@@ -115,14 +116,6 @@ public class TestDirectPaymentEnteringStateCallback extends PaymentTestSuiteWith
Assert.assertEquals(paymentDao.getDirectPaymentTransaction(directPaymentStateContext.getDirectPaymentTransactionModelDao().getId(), internalCallContext).getTransactionStatus(), TransactionStatus.PLUGIN_FAILURE);
}
- @Test(groups = "slow", expectedExceptions = IllegalStateException.class)
- public void testEnterStateWithNoDirectPaymentTransactionId() throws Exception {
- directPaymentStateContext.setDirectPaymentTransactionModelDao(null);
- directPaymentStateContext.setPaymentInfoPlugin(Mockito.mock(PaymentTransactionInfoPlugin.class));
-
- callback.enteringState(state, operationCallback, operationResult, leavingStateCallback);
- }
-
private static final class DirectPaymentEnteringStateTestCallback extends DirectPaymentEnteringStateCallback {
private DirectPaymentEnteringStateTestCallback(final DirectPaymentAutomatonDAOHelper daoHelper, final DirectPaymentStateContext directPaymentStateContext) throws PaymentApiException {
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/TestDirectPaymentProcessor.java b/payment/src/test/java/org/killbill/billing/payment/core/TestDirectPaymentProcessor.java
index 7e2de1d..cfa5141 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/TestDirectPaymentProcessor.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/TestDirectPaymentProcessor.java
@@ -75,7 +75,7 @@ public class TestDirectPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
// AUTH pre-3DS
final String authorizationKey = UUID.randomUUID().toString();
- final DirectPayment authorization = directPaymentProcessor.createAuthorization(account, null, null, TEN, CURRENCY, directPaymentExternalKey, authorizationKey,
+ final DirectPayment authorization = directPaymentProcessor.createAuthorization(true, account, null, null, TEN, CURRENCY, directPaymentExternalKey, authorizationKey,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
verifyDirectPayment(authorization, directPaymentExternalKey, TEN, ZERO, ZERO, 1);
final UUID directPaymentId = authorization.getId();
@@ -84,7 +84,7 @@ public class TestDirectPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
// AUTH post-3DS
final String authorizationPost3DSKey = UUID.randomUUID().toString();
- final DirectPayment authorizationPost3DS = directPaymentProcessor.createAuthorization(account, null, directPaymentId, TEN, CURRENCY, directPaymentExternalKey, authorizationPost3DSKey,
+ final DirectPayment authorizationPost3DS = directPaymentProcessor.createAuthorization(true, account, null, directPaymentId, TEN, CURRENCY, directPaymentExternalKey, authorizationPost3DSKey,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
verifyDirectPayment(authorizationPost3DS, directPaymentExternalKey, TEN, ZERO, ZERO, 2);
verifyDirectPaymentTransaction(authorizationPost3DS.getTransactions().get(1), authorizationPost3DSKey, TransactionType.AUTHORIZE, TEN, directPaymentId);
@@ -92,7 +92,7 @@ public class TestDirectPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
// CAPTURE
final String capture1Key = UUID.randomUUID().toString();
- final DirectPayment partialCapture1 = directPaymentProcessor.createCapture(account, directPaymentId, FIVE, CURRENCY, capture1Key,
+ final DirectPayment partialCapture1 = directPaymentProcessor.createCapture(true, account, directPaymentId, FIVE, CURRENCY, capture1Key,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
verifyDirectPayment(partialCapture1, directPaymentExternalKey, TEN, FIVE, ZERO, 3);
verifyDirectPaymentTransaction(partialCapture1.getTransactions().get(2), capture1Key, TransactionType.CAPTURE, FIVE, directPaymentId);
@@ -100,7 +100,7 @@ public class TestDirectPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
// CAPTURE
final String capture2Key = UUID.randomUUID().toString();
- final DirectPayment partialCapture2 = directPaymentProcessor.createCapture(account, directPaymentId, FIVE, CURRENCY, capture2Key,
+ final DirectPayment partialCapture2 = directPaymentProcessor.createCapture(true, account, directPaymentId, FIVE, CURRENCY, capture2Key,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
verifyDirectPayment(partialCapture2, directPaymentExternalKey, TEN, TEN, ZERO, 4);
verifyDirectPaymentTransaction(partialCapture2.getTransactions().get(3), capture2Key, TransactionType.CAPTURE, FIVE, directPaymentId);
@@ -108,7 +108,7 @@ public class TestDirectPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
// REFUND
final String refund1Key = UUID.randomUUID().toString();
- final DirectPayment partialRefund1 = directPaymentProcessor.createRefund(account, directPaymentId, FIVE, CURRENCY, refund1Key,
+ final DirectPayment partialRefund1 = directPaymentProcessor.createRefund(true, account, directPaymentId, FIVE, CURRENCY, refund1Key,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
verifyDirectPayment(partialRefund1, directPaymentExternalKey, TEN, TEN, FIVE, 5);
verifyDirectPaymentTransaction(partialRefund1.getTransactions().get(4), refund1Key, TransactionType.REFUND, FIVE, directPaymentId);
@@ -116,7 +116,7 @@ public class TestDirectPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
// REFUND
final String refund2Key = UUID.randomUUID().toString();
- final DirectPayment partialRefund2 = directPaymentProcessor.createRefund(account, directPaymentId, FIVE, CURRENCY, refund2Key,
+ final DirectPayment partialRefund2 = directPaymentProcessor.createRefund(true, account, directPaymentId, FIVE, CURRENCY, refund2Key,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
verifyDirectPayment(partialRefund2, directPaymentExternalKey, TEN, TEN, TEN, 6);
verifyDirectPaymentTransaction(partialRefund2.getTransactions().get(5), refund2Key, TransactionType.REFUND, FIVE, directPaymentId);
@@ -129,7 +129,7 @@ public class TestDirectPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
// AUTH
final String authorizationKey = UUID.randomUUID().toString();
- final DirectPayment authorization = directPaymentProcessor.createAuthorization(account, null, null, TEN, CURRENCY, directPaymentExternalKey, authorizationKey,
+ final DirectPayment authorization = directPaymentProcessor.createAuthorization(true, account, null, null, TEN, CURRENCY, directPaymentExternalKey, authorizationKey,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
verifyDirectPayment(authorization, directPaymentExternalKey, TEN, ZERO, ZERO, 1);
final UUID directPaymentId = authorization.getId();
@@ -138,7 +138,7 @@ public class TestDirectPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
// VOID
final String voidKey = UUID.randomUUID().toString();
- final DirectPayment voidTransaction = directPaymentProcessor.createVoid(account, directPaymentId, voidKey,
+ final DirectPayment voidTransaction = directPaymentProcessor.createVoid(true, account, directPaymentId, voidKey,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
verifyDirectPayment(voidTransaction, directPaymentExternalKey, TEN, ZERO, ZERO, 2);
verifyDirectPaymentTransaction(voidTransaction.getTransactions().get(1), voidKey, TransactionType.VOID, null, directPaymentId);
@@ -151,7 +151,7 @@ public class TestDirectPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
// PURCHASE
final String purchaseKey = UUID.randomUUID().toString();
- final DirectPayment purchase = directPaymentProcessor.createPurchase(account, null, null, TEN, CURRENCY, directPaymentExternalKey, purchaseKey,
+ final DirectPayment purchase = directPaymentProcessor.createPurchase(true, account, null, null, TEN, CURRENCY, directPaymentExternalKey, purchaseKey,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
verifyDirectPayment(purchase, directPaymentExternalKey, ZERO, ZERO, ZERO, 1);
final UUID directPaymentId = purchase.getId();
@@ -165,7 +165,7 @@ public class TestDirectPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
// CREDIT
final String creditKey = UUID.randomUUID().toString();
- final DirectPayment purchase = directPaymentProcessor.createCredit(account, null, null, TEN, CURRENCY, directPaymentExternalKey, creditKey,
+ final DirectPayment purchase = directPaymentProcessor.createCredit(true, account, null, null, TEN, CURRENCY, directPaymentExternalKey, creditKey,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
verifyDirectPayment(purchase, directPaymentExternalKey, ZERO, ZERO, ZERO, 1);
final UUID directPaymentId = purchase.getId();
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorRefreshWithDB.java b/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorRefreshWithDB.java
index 52a5434..8a61a5e 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorRefreshWithDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorRefreshWithDB.java
@@ -68,7 +68,8 @@ public class TestPaymentMethodProcessorRefreshWithDB extends PaymentTestSuiteWit
Assert.assertEquals(getPluginApi().getPaymentMethods(account.getId(), true, PLUGIN_PROPERTIES, callContext).size(), 1);
final UUID firstPmId = account.getPaymentMethodId();
- final UUID secondPmId = paymentApi.addPaymentMethod(UUID.randomUUID().toString(), account, MockPaymentProviderPlugin.PLUGIN_NAME, true, new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), false, null), PLUGIN_PROPERTIES, callContext);
+ String secondPaymentMethodExternalKey = UUID.randomUUID().toString();
+ final UUID secondPmId = paymentApi.addPaymentMethod(account, secondPaymentMethodExternalKey, MockPaymentProviderPlugin.PLUGIN_NAME, true, new DefaultNoOpPaymentMethodPlugin(secondPaymentMethodExternalKey, false, null), PLUGIN_PROPERTIES, callContext);
Assert.assertEquals(getPluginApi().getPaymentMethods(account.getId(), true, PLUGIN_PROPERTIES, callContext).size(), 2);
Assert.assertEquals(paymentApi.getAccountPaymentMethods(account.getId(), false, PLUGIN_PROPERTIES, callContext).size(), 2);
diff --git a/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentProviderPlugin.java b/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentProviderPlugin.java
index 4779159..57ccdce 100644
--- a/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentProviderPlugin.java
+++ b/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentProviderPlugin.java
@@ -345,14 +345,11 @@ public class MockPaymentProviderPlugin implements NoOpPaymentPluginApi {
private PaymentTransactionInfoPlugin getPaymentTransactionInfoPluginResult(final UUID kbPaymentId, final UUID kbTransactionId, final TransactionType type, final BigDecimal amount, final Currency currency) throws PaymentPluginApiException {
if (makeNextInvoiceFailWithException.getAndSet(false)) {
- System.out.println("################## (STEPH) MockPaymentProviderPlugin getPaymentTransactionInfoPluginResult makeNextInvoiceFailWithException => THROW");
throw new PaymentPluginApiException("", "test error");
}
final PaymentPluginStatus status = (makeAllInvoicesFailWithError.get() || makeNextInvoiceFailWithError.getAndSet(false)) ? PaymentPluginStatus.ERROR : PaymentPluginStatus.PROCESSED;
- System.out.println("################## (STEPH) MockPaymentProviderPlugin getPaymentTransactionInfoPluginResult makeNextInvoiceFailWithError => status = " + status);
-
InternalPaymentInfo info = payments.get(kbPaymentId.toString());
if (info == null) {
info = new InternalPaymentInfo();
diff --git a/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java b/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
index aee2f2d..cd6bd40 100644
--- a/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
+++ b/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
@@ -130,7 +130,7 @@ public class TestPaymentHelper {
}
public void addTestPaymentMethod(final Account account, final PaymentMethodPlugin paymentMethodInfo) throws Exception {
- final UUID paymentMethodId = paymentApi.addPaymentMethod(UUID.randomUUID().toString(), account, MockPaymentProviderPlugin.PLUGIN_NAME, true, paymentMethodInfo, ImmutableList.<PluginProperty>of(), context);
+ final UUID paymentMethodId = paymentApi.addPaymentMethod(account, paymentMethodInfo.getExternalPaymentMethodId(), MockPaymentProviderPlugin.PLUGIN_NAME, true, paymentMethodInfo, ImmutableList.<PluginProperty>of(), context);
Mockito.when(account.getPaymentMethodId()).thenReturn(paymentMethodId);
}
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
index 9f604ed..bfcd862 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
@@ -40,9 +40,7 @@ import static org.testng.Assert.assertNotNull;
public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedDB {
- //private final int DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC = 5;
- // STEPH fix timeout value after debug
- private final int DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC = 5000;
+ private final int DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC = 5;
protected static final String PLUGIN_NAME = "noop";
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
index 3b507a5..35d2e89 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
@@ -29,7 +29,6 @@ import org.joda.time.LocalDate;
import org.killbill.billing.client.model.Account;
import org.killbill.billing.client.model.AccountTimeline;
import org.killbill.billing.client.model.AuditLog;
-import org.killbill.billing.client.model.Chargeback;
import org.killbill.billing.client.model.Credit;
import org.killbill.billing.client.model.EventSubscription;
import org.killbill.billing.client.model.Invoice;
@@ -43,6 +42,10 @@ import org.killbill.billing.util.audit.ChangeType;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableList;
+
+import static org.testng.Assert.assertEquals;
+
public class TestAccountTimeline extends TestJaxrsBase {
private static final String PAYMENT_REQUEST_PROCESSOR = "PaymentRequestProcessor";
@@ -93,15 +96,11 @@ public class TestAccountTimeline extends TestJaxrsBase {
killBillClient.createInvoicePaymentRefund(refund, createdBy, reason, comment);
// Add chargeback
- /*
- // STEPH disable until chargeback has been fixed
final BigDecimal chargebackAmount = BigDecimal.ONE;
- final Chargeback chargeback = new Chargeback();
+ final InvoicePaymentTransaction chargeback = new InvoicePaymentTransaction();
chargeback.setPaymentId(postedPayment.getPaymentId());
chargeback.setAmount(chargebackAmount);
- killBillClient.createChargeBack(chargeback, createdBy, reason, comment);
- */
- final BigDecimal chargebackAmount = BigDecimal.ZERO;
+ killBillClient.createInvoicePaymentChargeback(chargeback, createdBy, reason, comment);
// Verify payments
verifyPayments(accountJson.getAccountId(), startTime, endTime, refundAmount, chargebackAmount);
@@ -136,19 +135,16 @@ public class TestAccountTimeline extends TestJaxrsBase {
Assert.assertEquals(refundTransaction.getPaymentId(), payment.getPaymentId());
Assert.assertEquals(refundTransaction.getAmount().compareTo(refundAmount), 0);
- // Verify chargebacks
- /*
-STEPH
final List<PaymentTransaction> chargebackTransactions = getDirectPaymentTransactions(timeline.getPayments(), TransactionType.CHARGEBACK.toString());
Assert.assertEquals(chargebackTransactions.size(), 1);
final PaymentTransaction chargebackTransaction = chargebackTransactions.get(0);
Assert.assertEquals(chargebackTransaction.getPaymentId(), payment.getPaymentId());
Assert.assertEquals(chargebackTransaction.getAmount().compareTo(chargebackAmount), 0);
-*/
+
// Verify audits
final List<AuditLog> paymentAuditLogs = purchaseTransaction.getAuditLogs();
final List<AuditLog> refundAuditLogs = refundTransaction.getAuditLogs();
- //final List<AuditLog> chargebackAuditLogs = chargebackTransaction.getAuditLogs(); STEPH
+ final List<AuditLog> chargebackAuditLogs = chargebackTransaction.getAuditLogs();
if (AuditLevel.NONE.equals(auditLevel)) {
// Audits for payments
@@ -158,7 +154,7 @@ STEPH
Assert.assertEquals(refundAuditLogs.size(), 0);
// Audits for chargebacks
- //Assert.assertEquals(chargebackAuditLogs.size(), 0); STEPH
+ Assert.assertEquals(chargebackAuditLogs.size(), 0);
} else if (AuditLevel.MINIMAL.equals(auditLevel)) {
// Audits for payments
Assert.assertEquals(paymentAuditLogs.size(), 1);
@@ -169,8 +165,8 @@ STEPH
verifyAuditLog(refundAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
// Audits for chargebacks
- //Assert.assertEquals(chargebackAuditLogs.size(), 1); STEPH
- //verifyAuditLog(chargebackAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime); STEPH
+ Assert.assertEquals(chargebackAuditLogs.size(), 1);
+ verifyAuditLog(chargebackAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
} else {
// Audits for payments
Assert.assertEquals(paymentAuditLogs.size(), 2);
@@ -183,8 +179,9 @@ STEPH
verifyAuditLog(refundAuditLogs.get(1), ChangeType.UPDATE, reason, comment, createdBy, startTime, endTime);
// Audits for chargebacks
- //Assert.assertEquals(chargebackAuditLogs.size(), 1); STEPH
- // verifyAuditLog(chargebackAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime); STEPH
+ Assert.assertEquals(chargebackAuditLogs.size(), 2);
+ verifyAuditLog(chargebackAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+ verifyAuditLog(chargebackAuditLogs.get(1), ChangeType.UPDATE, reason, comment, createdBy, startTime, endTime);
}
}
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java
index f8b3196..d5929de 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java
@@ -26,13 +26,19 @@ import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.client.KillBillClientException;
import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Chargeback;
import org.killbill.billing.client.model.Invoice;
+import org.killbill.billing.client.model.InvoicePayment;
+import org.killbill.billing.client.model.InvoicePaymentTransaction;
+import org.killbill.billing.client.model.InvoicePayments;
import org.killbill.billing.client.model.Payment;
+import org.killbill.billing.client.model.PaymentTransaction;
import org.killbill.billing.client.model.Subscription;
+import org.killbill.billing.payment.api.TransactionType;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableList;
+
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
@@ -41,48 +47,50 @@ import static org.testng.Assert.fail;
public class TestChargeback extends TestJaxrsBase {
- // STEPH disable all chargeback tests until chargeback gets correctly implemented in payment (part of TODO list)
- @Test(groups = "slow", description = "Can create a chargeback", enabled=false)
+ @Test(groups = "slow", description = "Can create a chargeback")
public void testAddChargeback() throws Exception {
final Payment payment = createAccountWithInvoiceAndPayment();
createAndVerifyChargeback(payment);
}
- @Test(groups = "slow", description = "Can create multiple chargebacks", enabled=false)
+ @Test(groups = "slow", description = "Can create multiple chargebacks")
public void testMultipleChargeback() throws Exception {
final Payment payment = createAccountWithInvoiceAndPayment();
// We get a 249.95 payment so we do 4 chargeback and then the fifth should fail
- final Chargeback input = new Chargeback();
- input.setAmount(new BigDecimal("50.00"));
+ final InvoicePaymentTransaction input = new InvoicePaymentTransaction();
input.setPaymentId(payment.getPaymentId());
-
+ input.setAmount(new BigDecimal("50.00"));
int count = 4;
while (count-- > 0) {
- assertNotNull(killBillClient.createChargeBack(input, createdBy, reason, comment));
+ assertNotNull(killBillClient.createInvoicePaymentChargeback(input, createdBy, reason, comment));
}
// Last attempt should fail because this is more than the Payment
try {
- killBillClient.createChargeBack(input, createdBy, reason, comment);
+ killBillClient.createInvoicePaymentChargeback(input, createdBy, reason, comment);
fail();
} catch (final KillBillClientException e) {
}
- // Find the chargeback by account
- List<Chargeback> chargebacks = killBillClient.getChargebacksForAccount(payment.getAccountId());
- assertEquals(chargebacks.size(), 4);
- for (final Chargeback chargeBack : chargebacks) {
- assertTrue(chargeBack.getAmount().compareTo(input.getAmount()) == 0);
- assertEquals(chargeBack.getPaymentId(), input.getPaymentId());
+ final List<InvoicePayment> payments = killBillClient.getInvoicePaymentsForAccount(payment.getAccountId());
+ final List<PaymentTransaction> transactions = getDirectPaymentTransactions(payments, TransactionType.CHARGEBACK.toString());
+ Assert.assertEquals(transactions.size(), 5);
+ int found = 0;
+ for (final PaymentTransaction transaction : transactions) {
+ if (transaction.getStatus().equals("SUCCESS")) {
+ assertTrue(transaction.getAmount().compareTo(input.getAmount()) == 0);
+ assertEquals(transaction.getPaymentId(), input.getPaymentId());
+ found++;
+ } else {
+ assertEquals(transaction.getStatus(), "PAYMENT_FAILURE");
+ found++;
+ }
}
-
- // Find the chargeback by payment
- chargebacks = killBillClient.getChargebacksForPayment(payment.getPaymentId());
- assertEquals(chargebacks.size(), 4);
+ assertEquals(found, 5);
}
- @Test(groups = "slow", description = "Can add a chargeback for deleted payment methods", enabled=false)
+ @Test(groups = "slow", description = "Can add a chargeback for deleted payment methods")
public void testAddChargebackForDeletedPaymentMethod() throws Exception {
final Payment payment = createAccountWithInvoiceAndPayment();
@@ -99,59 +107,62 @@ public class TestChargeback extends TestJaxrsBase {
createAndVerifyChargeback(payment);
}
- @Test(groups = "slow", description = "Cannot add a chargeback for non existent payment", enabled=false)
- public void testInvoicePaymentDoesNotExist() throws Exception {
- final Chargeback input = new Chargeback();
+ @Test(groups = "slow", description = "Cannot add a chargeback for non existent payment")
+ public void testInvoicePaymentDoesNotExist() {
+
+ final InvoicePaymentTransaction input = new InvoicePaymentTransaction();
+ input.setPaymentId(input.getPaymentId());
input.setAmount(BigDecimal.TEN);
- input.setPaymentId(UUID.randomUUID());
- assertNull(killBillClient.createChargeBack(input, createdBy, reason, comment));
+ try {
+ killBillClient.createInvoicePaymentChargeback(input, createdBy, reason, comment);
+ fail();
+ } catch (NullPointerException e) {
+ } catch (KillBillClientException e) {
+ fail();
+ }
}
- @Test(groups = "slow", description = "Cannot add a badly formatted chargeback", enabled=false)
+ @Test(groups = "slow", description = "Cannot add a badly formatted chargeback")
public void testBadRequest() throws Exception {
final Payment payment = createAccountWithInvoiceAndPayment();
- final Chargeback input = new Chargeback();
- input.setAmount(BigDecimal.TEN.negate());
+ final InvoicePaymentTransaction input = new InvoicePaymentTransaction();
input.setPaymentId(payment.getPaymentId());
+ input.setAmount(BigDecimal.TEN.negate());
try {
- killBillClient.createChargeBack(input, createdBy, reason, comment);
+ killBillClient.createInvoicePaymentChargeback(input, createdBy, reason, comment);
fail();
} catch (final KillBillClientException e) {
}
}
- @Test(groups = "slow", description = "Accounts can have zero chargeback", enabled=false)
+ @Test(groups = "slow", description = "Accounts can have zero chargeback")
public void testNoChargebackForAccount() throws Exception {
- Assert.assertEquals(killBillClient.getChargebacksForAccount(UUID.randomUUID()).size(), 0);
- }
-
- @Test(groups = "slow", description = "Payments can have zero chargeback", enabled=false)
- public void testNoChargebackForPayment() throws Exception {
- Assert.assertEquals(killBillClient.getChargebacksForPayment(UUID.randomUUID()).size(), 0);
+ final List<InvoicePayment> payments = killBillClient.getInvoicePaymentsForAccount(UUID.randomUUID());
+ final List<PaymentTransaction> transactions = getDirectPaymentTransactions(payments, TransactionType.CHARGEBACK.toString());
+ Assert.assertEquals(transactions.size(), 0);
}
private void createAndVerifyChargeback(final Payment payment) throws KillBillClientException {
// Create the chargeback
- final Chargeback chargeback = new Chargeback();
+ final InvoicePaymentTransaction chargeback = new InvoicePaymentTransaction();
chargeback.setPaymentId(payment.getPaymentId());
chargeback.setAmount(BigDecimal.TEN);
- final Chargeback chargebackJson = killBillClient.createChargeBack(chargeback, createdBy, reason, comment);
- assertEquals(chargebackJson.getAmount().compareTo(chargeback.getAmount()), 0);
- assertEquals(chargebackJson.getPaymentId(), chargeback.getPaymentId());
+
+ final InvoicePayment chargebackJson = killBillClient.createInvoicePaymentChargeback(chargeback, createdBy, reason, comment);
+ final List<PaymentTransaction> chargebackTransactions = getDirectPaymentTransactions(ImmutableList.of(chargebackJson), TransactionType.CHARGEBACK.toString());
+ assertEquals(chargebackTransactions.size(), 1);
+
+ assertEquals(chargebackTransactions.get(0).getAmount().compareTo(chargeback.getAmount()), 0);
+ assertEquals(chargebackTransactions.get(0).getPaymentId(), chargeback.getPaymentId());
// Find the chargeback by account
- List<Chargeback> chargebacks = killBillClient.getChargebacksForAccount(payment.getAccountId());
- assertEquals(chargebacks.size(), 1);
- assertEquals(chargebacks.get(0).getAmount().compareTo(chargeback.getAmount()), 0);
- assertEquals(chargebacks.get(0).getPaymentId(), chargeback.getPaymentId());
-
- // Find the chargeback by payment
- chargebacks = killBillClient.getChargebacksForPayment(payment.getPaymentId());
- assertEquals(chargebacks.size(), 1);
- assertEquals(chargebacks.get(0).getAmount().compareTo(chargeback.getAmount()), 0);
- assertEquals(chargebacks.get(0).getPaymentId(), chargeback.getPaymentId());
+ final List<InvoicePayment> payments = killBillClient.getInvoicePaymentsForAccount(payment.getAccountId());
+ final List<PaymentTransaction> transactions = getDirectPaymentTransactions(payments, TransactionType.CHARGEBACK.toString());
+ Assert.assertEquals(transactions.size(), 1);
+ assertEquals(transactions.get(0).getAmount().compareTo(chargeback.getAmount()), 0);
+ assertEquals(transactions.get(0).getPaymentId(), chargeback.getPaymentId());
}
private Payment createAccountWithInvoiceAndPayment() throws Exception {
@@ -182,7 +193,7 @@ public class TestChargeback extends TestJaxrsBase {
}
private Payment getPayment(final Invoice invoice) throws KillBillClientException {
- final List<Payment> payments = null; //killBillClient.getPaymentsForInvoice(invoice.getInvoiceId());
+ final InvoicePayments payments = killBillClient.getInvoicePayment(invoice.getInvoiceId());
assertNotNull(payments);
assertEquals(payments.size(), 1);
return payments.get(0);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExceptions.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExceptions.java
index 8e68e97..fa7c31f 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExceptions.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExceptions.java
@@ -21,32 +21,29 @@ package org.killbill.billing.jaxrs;
import java.math.BigDecimal;
import java.util.List;
-import org.killbill.billing.client.model.InvoicePayment;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
import org.killbill.billing.ErrorCode;
import org.killbill.billing.client.KillBillClientException;
import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.Chargeback;
-import org.killbill.billing.client.model.Payment;
+import org.killbill.billing.client.model.InvoicePayment;
+import org.killbill.billing.client.model.InvoicePaymentTransaction;
import org.killbill.billing.invoice.api.InvoiceApiException;
+import org.testng.Assert;
+import org.testng.annotations.Test;
import static org.testng.Assert.fail;
public class TestExceptions extends TestJaxrsBase {
- // STEPH disable all chargeback tests until chargeback gets correctly implemented in payment (part of TODO list)
- @Test(groups = "slow", enabled=false)
+ @Test(groups = "slow", enabled = false)
public void testExceptionMapping() throws Exception {
final Account account = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
final List<InvoicePayment> payments = killBillClient.getInvoicePaymentsForAccount(account.getAccountId());
- final Chargeback input = new Chargeback();
- input.setAmount(BigDecimal.TEN.negate());
- input.setPaymentId(payments.get(0).getPaymentId());
+ final InvoicePaymentTransaction input = new InvoicePaymentTransaction();
+ input.setPaymentId(payments.get(0).getPaymentId());
+ input.setAmount(BigDecimal.TEN.negate());
try {
- killBillClient.createChargeBack(input, createdBy, reason, comment);
+ killBillClient.createInvoicePaymentChargeback(input, createdBy, reason, comment);
fail();
} catch (final KillBillClientException e) {
Assert.assertEquals(e.getBillingException().getClassName(), InvoiceApiException.class.getName());