Details
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
index 15c4a94..8d107ef 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
@@ -35,6 +35,7 @@ import com.ning.billing.analytics.dao.BusinessAccountDao;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceUserApi;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.util.tag.Tag;
@@ -59,14 +60,14 @@ public class BusinessAccountRecorder {
Account account;
try {
account = accountApi.getAccountByKey(data.getExternalKey());
- final BusinessAccount bac = createBusinessAccountFromAccount(account);
+ final BusinessAccount bac = createBusinessAccountFromAccount(account);
- log.info("ACCOUNT CREATION " + bac);
- dao.createAccount(bac);
+ log.info("ACCOUNT CREATION " + bac);
+ dao.createAccount(bac);
} catch (AccountApiException e) {
- log.warn("Error encountered creating BusinessAccount",e);
+ log.warn("Error encountered creating BusinessAccount",e);
}
- }
+ }
/**
* Notification handler for Account changes
@@ -85,17 +86,19 @@ public class BusinessAccountRecorder {
* @param paymentInfo payment object (from the payment plugin)
*/
public void accountUpdated(final PaymentInfoEvent paymentInfo) {
- final PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
- if (paymentAttempt == null) {
- return;
- }
try {
+ final PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
+ if (paymentAttempt == null) {
+ return;
+ }
+
final Account account = accountApi.getAccountById(paymentAttempt.getAccountId());
accountUpdated(account.getId());
} catch (AccountApiException e) {
log.warn("Error encountered creating BusinessAccount",e);
+ } catch (PaymentApiException e) {
+ log.warn("Error encountered creating BusinessAccount",e);
}
-
}
/**
@@ -152,51 +155,56 @@ public class BusinessAccountRecorder {
}
private void updateBusinessAccountFromAccount(final Account account, final BusinessAccount bac) {
- DateTime lastInvoiceDate = null;
- BigDecimal totalInvoiceBalance = BigDecimal.ZERO;
- String lastPaymentStatus = null;
- String paymentMethod = null;
- String creditCardType = null;
- String billingAddressCountry = null;
-
- // Retrieve invoices information
- final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId());
- if (invoices != null && invoices.size() > 0) {
- final List<String> invoiceIds = new ArrayList<String>();
- for (final Invoice invoice : invoices) {
- invoiceIds.add(invoice.getId().toString());
- totalInvoiceBalance = totalInvoiceBalance.add(invoice.getBalance());
-
- if (lastInvoiceDate == null || invoice.getInvoiceDate().isAfter(lastInvoiceDate)) {
- lastInvoiceDate = invoice.getInvoiceDate();
+
+ try {
+ DateTime lastInvoiceDate = null;
+ BigDecimal totalInvoiceBalance = BigDecimal.ZERO;
+ String lastPaymentStatus = null;
+ String paymentMethod = null;
+ String creditCardType = null;
+ String billingAddressCountry = null;
+
+ // Retrieve invoices information
+ final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId());
+ if (invoices != null && invoices.size() > 0) {
+ final List<String> invoiceIds = new ArrayList<String>();
+ for (final Invoice invoice : invoices) {
+ invoiceIds.add(invoice.getId().toString());
+ totalInvoiceBalance = totalInvoiceBalance.add(invoice.getBalance());
+
+ if (lastInvoiceDate == null || invoice.getInvoiceDate().isAfter(lastInvoiceDate)) {
+ lastInvoiceDate = invoice.getInvoiceDate();
+ }
}
- }
- // Retrieve payments information for these invoices
- DateTime lastPaymentDate = null;
- final List<PaymentInfoEvent> payments = paymentApi.getPaymentInfo(invoiceIds);
- if (payments != null) {
- for (final PaymentInfoEvent payment : payments) {
- // Use the last payment method/type/country as the default one for the account
- if (lastPaymentDate == null || payment.getCreatedDate().isAfter(lastPaymentDate)) {
- lastPaymentDate = payment.getCreatedDate();
-
- lastPaymentStatus = payment.getStatus();
- paymentMethod = payment.getPaymentMethod();
- creditCardType = payment.getCardType();
- billingAddressCountry = payment.getCardCountry();
+ // Retrieve payments information for these invoices
+ DateTime lastPaymentDate = null;
+ final List<PaymentInfoEvent> payments = paymentApi.getPaymentInfo(invoiceIds);
+ if (payments != null) {
+ for (final PaymentInfoEvent payment : payments) {
+ // Use the last payment method/type/country as the default one for the account
+ if (lastPaymentDate == null || payment.getCreatedDate().isAfter(lastPaymentDate)) {
+ lastPaymentDate = payment.getCreatedDate();
+
+ lastPaymentStatus = payment.getStatus();
+ paymentMethod = payment.getPaymentMethod();
+ creditCardType = payment.getCardType();
+ billingAddressCountry = payment.getCardCountry();
+ }
}
}
}
- }
- bac.setLastPaymentStatus(lastPaymentStatus);
- bac.setPaymentMethod(paymentMethod);
- bac.setCreditCardType(creditCardType);
- bac.setBillingAddressCountry(billingAddressCountry);
- bac.setLastInvoiceDate(lastInvoiceDate);
- bac.setTotalInvoiceBalance(totalInvoiceBalance);
+ bac.setLastPaymentStatus(lastPaymentStatus);
+ bac.setPaymentMethod(paymentMethod);
+ bac.setCreditCardType(creditCardType);
+ bac.setBillingAddressCountry(billingAddressCountry);
+ bac.setLastInvoiceDate(lastInvoiceDate);
+ bac.setTotalInvoiceBalance(totalInvoiceBalance);
- bac.setBalance(invoiceUserApi.getAccountBalance(account.getId()));
+ bac.setBalance(invoiceUserApi.getAccountBalance(account.getId()));
+ } catch (PaymentApiException e) {
+ log.error("Failed to update Business account", e);
+ }
}
}
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index c317465..3aa190b 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -201,7 +201,25 @@ public enum ErrorCode {
BLOCK_BLOCKED_ACTION(6000, "The action %s is block on this %s with id=%s"),
BLOCK_TYPE_NOT_SUPPORTED(6001, "The Blockable type '%s' is not supported"),
- /*
+
+ /*
+ * Range 7000 : Payment
+ */
+ PAYMENT_NO_SUCH_PAYMENT_METHOD(7001, "Payment method for account %s, and paymentId %s does not exist"),
+ PAYMENT_NO_PAYMENT_METHODS(7002, "Payment methods for account %s don't exist"),
+ PAYMENT_UPD_GATEWAY_FAILED(7003, "Failed to update payment gateway for account %s : %s"),
+ PAYMENT_GET_PAYMENT_PROVIDER(7004, "Failed to retrieve payment provider for account %s : %s"),
+ PAYMENT_ADD_PAYMENT_METHOD(7005, "Failed to add payment method for account %s : %s"),
+ PAYMENT_DEL_PAYMENT_METHOD(7006, "Failed to delete payment method for account %s : %s"),
+ PAYMENT_UPD_PAYMENT_METHOD(7007, "Failed to update payment method for account %s : %s"),
+ PAYMENT_CREATE_PAYMENT(7008, "Failed to create payment for account %s : %s"),
+ PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT(7009, "Failed to create payment for account %s and attempt %s : %s"),
+ PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_WITH_NON_POSITIVE_INV(70010, "Got payment attempt with negative or null invoice for account %s"),
+ PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_BAD(7011, "Failed to create payment for attempts %s "),
+ PAYMENT_CREATE_PAYMENT_PROVIDER_ACCOUNT(7012, "Failed to create payment provider account for account %s : %s"),
+ PAYMENT_UPD_PAYMENT_PROVIDER_ACCOUNT(7013, "Failed to update payment provider account for account %s : %s"),
+ PAYMENT_CREATE_REFUND(7014, "Failed to create refund for account %s : %s"),
+ /*
*
* Range 9000: Miscellaneous
*
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
index 1679f50..c7b5965 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
@@ -26,36 +26,54 @@ import com.ning.billing.util.callcontext.CallContext;
public interface PaymentApi {
- Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey, CallContext context);
+ public void updatePaymentGateway(final String accountKey, final CallContext context)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId);
+ public PaymentMethodInfo getPaymentMethod(final String accountKey, final String paymentMethodId)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(String accountKey);
+ public List<PaymentMethodInfo> getPaymentMethods(final String accountKey)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context);
+ public String addPaymentMethod(final String accountKey, final PaymentMethodInfo paymentMethod, final CallContext context)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context);
+ public PaymentMethodInfo updatePaymentMethod(final String accountKey, final PaymentMethodInfo paymentMethodInfo, final CallContext context)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context);
+ public void deletePaymentMethod(final String accountKey, final String paymentMethodId, final CallContext context)
+ throws PaymentApiException;
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(String accountKey, List<String> invoiceIds, CallContext context);
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(Account account, List<String> invoiceIds, CallContext context);
- Either<PaymentErrorEvent, PaymentInfoEvent> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context);
+ public List<PaymentInfoEvent> createPayment(final String accountKey, final List<String> invoiceIds, final CallContext context)
+ throws PaymentApiException;
+
+ public List<PaymentInfoEvent> createPayment(final Account account, final List<String> invoiceIds, final CallContext context)
+ throws PaymentApiException;
+
+ public PaymentInfoEvent createPaymentForPaymentAttempt(final UUID paymentAttemptId, final CallContext context)
+ throws PaymentApiException;
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> createRefund(Account account, List<String> invoiceIds, CallContext context); //TODO
+ public List<PaymentInfoEvent> createRefund(final Account account, final List<String> invoiceIds, final CallContext context)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey);
+ public PaymentProviderAccount getPaymentProviderAccount(final String accountKey)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account, CallContext context);
+ public String createPaymentProviderAccount(final Account account, final CallContext context)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, Void> updatePaymentProviderAccountContact(String accountKey, CallContext context);
+ public void updatePaymentProviderAccountContact(String accountKey, CallContext context)
+ throws PaymentApiException;
- PaymentAttempt getPaymentAttemptForPaymentId(String id);
+ public PaymentAttempt getPaymentAttemptForPaymentId(final String id)
+ throws PaymentApiException;
- List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds);
+ public List<PaymentInfoEvent> getPaymentInfo(final List<String> invoiceIds)
+ throws PaymentApiException;
- List<PaymentAttempt> getPaymentAttemptsForInvoiceId(String invoiceId);
-
- PaymentInfoEvent getPaymentInfoForPaymentAttemptId(String paymentAttemptId);
+ public List<PaymentAttempt> getPaymentAttemptsForInvoiceId(final String invoiceId)
+ throws PaymentApiException;
+ public PaymentInfoEvent getPaymentInfoForPaymentAttemptId(final String paymentAttemptId)
+ throws PaymentApiException;
}
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java
new file mode 100644
index 0000000..ff81b16
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.payment.api;
+
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.catalog.api.CatalogApiException;
+
+public class PaymentApiException extends BillingExceptionBase {
+
+ private static final long serialVersionUID = 39445033L;
+
+
+ public PaymentApiException(AccountApiException e) {
+ super(e, e.getCode(), e.getMessage());
+ }
+
+ /*
+ public PaymentApiException(CatalogApiException e) {
+ super(e, e.getCode(), e.getMessage());
+ }
+ */
+
+ public PaymentApiException(Throwable e, ErrorCode code, Object...args) {
+ super(e, code, args);
+ }
+
+ public PaymentApiException(Throwable e, int code, String message) {
+ super(e, code, message);
+ }
+
+ public PaymentApiException(ErrorCode code, Object...args) {
+ super(code, args);
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
index 9061eac..07502cc 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -67,6 +67,7 @@ import com.ning.billing.jaxrs.util.Context;
import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
import com.ning.billing.jaxrs.util.TagHelper;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.util.api.TagDefinitionApiException;
@@ -268,6 +269,9 @@ public class AccountResource implements BaseJaxrsResource {
return Response.status(Status.OK).entity(json).build();
} catch (AccountApiException e) {
return Response.status(Status.NO_CONTENT).build();
+ } catch (PaymentApiException e) {
+ log.error(e.getMessage());
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
} catch (EntitlementRepairException e) {
log.error(e.getMessage());
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
index 2ed490c..2ac89d2 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
@@ -18,6 +18,7 @@ package com.ning.billing.payment.api;
import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@@ -29,6 +30,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountUserApi;
@@ -68,9 +70,14 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId) {
+ public PaymentMethodInfo getPaymentMethod(final String accountKey, final String paymentMethodId)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.getPaymentMethodInfo(paymentMethodId);
+ Either<PaymentErrorEvent, PaymentMethodInfo> result = plugin.getPaymentMethodInfo(paymentMethodId);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, accountKey, paymentMethodId);
+ }
+ return result.getRight();
}
private PaymentProviderPlugin getPaymentProviderPlugin(String accountKey) {
@@ -100,60 +107,86 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(String accountKey) {
+ public List<PaymentMethodInfo> getPaymentMethods(String accountKey)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.getPaymentMethods(accountKey);
+ Either<PaymentErrorEvent, List<PaymentMethodInfo>> result = plugin.getPaymentMethods(accountKey);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_PAYMENT_METHODS, accountKey);
+ }
+ return result.getRight();
}
@Override
- public Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey, CallContext context) {
+ public void updatePaymentGateway(String accountKey, CallContext context)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.updatePaymentGateway(accountKey);
+ Either<PaymentErrorEvent, Void> result = plugin.updatePaymentGateway(accountKey);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_UPD_GATEWAY_FAILED, accountKey, result.getLeft().getMessage());
+ }
+ return;
}
@Override
- public Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey) {
+ public PaymentProviderAccount getPaymentProviderAccount(String accountKey)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.getPaymentProviderAccount(accountKey);
+ Either<PaymentErrorEvent, PaymentProviderAccount> result = plugin.getPaymentProviderAccount(accountKey);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_GET_PAYMENT_PROVIDER, accountKey, result.getLeft().getMessage());
+ }
+ return result.getRight();
}
@Override
- public Either<PaymentErrorEvent, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context) {
+ public String addPaymentMethod(String accountKey, PaymentMethodInfo paymentMethod, CallContext context)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.addPaymentMethod(accountKey, paymentMethod);
+ Either<PaymentErrorEvent, String> result = plugin.addPaymentMethod(accountKey, paymentMethod);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_ADD_PAYMENT_METHOD, accountKey, result.getLeft().getMessage());
+ }
+ return result.getRight();
}
+
@Override
- public Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context) {
+ public void deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.deletePaymentMethod(accountKey, paymentMethodId);
+ Either<PaymentErrorEvent, Void> result = plugin.deletePaymentMethod(accountKey, paymentMethodId);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_DEL_PAYMENT_METHOD, accountKey, result.getLeft().getMessage());
+ }
+ return;
}
@Override
- public Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context) {
+ public PaymentMethodInfo updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.updatePaymentMethod(accountKey, paymentMethodInfo);
+ Either<PaymentErrorEvent, PaymentMethodInfo> result = plugin.updatePaymentMethod(accountKey, paymentMethodInfo);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_UPD_PAYMENT_METHOD, accountKey, result.getLeft().getMessage());
+ }
+ return result.getRight();
}
@Override
- public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(String accountKey, List<String> invoiceIds, CallContext context) {
+ public List<PaymentInfoEvent> createPayment(String accountKey, List<String> invoiceIds, CallContext context)
+ throws PaymentApiException {
try {
final Account account = accountUserApi.getAccountByKey(accountKey);
return createPayment(account, invoiceIds, context);
} catch (AccountApiException e) {
- log.error("Error getting payment provider plugin.", e);
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> result = new ArrayList<Either<PaymentErrorEvent, PaymentInfoEvent>>();
- result.add(new Either.Left<PaymentErrorEvent, PaymentInfoEvent>((PaymentErrorEvent) new DefaultPaymentErrorEvent("createPaymentError", e.getMessage(),
- null,
- null,
- context.getUserToken())));
- return result;
+ throw new PaymentApiException(e);
}
-
}
@Override
- public Either<PaymentErrorEvent, PaymentInfoEvent> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context) {
+ public PaymentInfoEvent createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context)
+ throws PaymentApiException {
PaymentAttempt paymentAttempt = paymentDao.getPaymentAttemptById(paymentAttemptId);
if (paymentAttempt != null) {
@@ -165,40 +198,35 @@ public class DefaultPaymentApi implements PaymentApi {
if (invoice.getBalance().compareTo(BigDecimal.ZERO) <= 0 ) {
// TODO: send a notification that invoice was ignored?
log.info("Received invoice for payment with outstanding amount of 0 {} ", invoice);
- return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("invoice_balance_0",
- "Invoice balance was 0 or less",
- paymentAttempt.getAccountId(),
- paymentAttempt.getInvoiceId(),
- context.getUserToken()));
- }
- else {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_WITH_NON_POSITIVE_INV, account.getId());
+
+ } else {
+
PaymentAttempt newPaymentAttempt = new PaymentAttempt.Builder(paymentAttempt)
.setRetryCount(paymentAttempt.getRetryCount() + 1)
.setPaymentAttemptId(UUID.randomUUID())
.build();
paymentDao.createPaymentAttempt(newPaymentAttempt, context);
- return processPayment(getPaymentProviderPlugin(account), account, invoice, newPaymentAttempt, context);
+ Either<PaymentErrorEvent, PaymentInfoEvent> result = processPayment(getPaymentProviderPlugin(account), account, invoice, newPaymentAttempt, context);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT, account.getId(), paymentAttemptId, result.getLeft().getMessage());
+ }
+ return result.getRight();
+
}
}
} catch (AccountApiException e) {
- log.error("Error creating payment attempt.", e);
- return new Either.Left<PaymentErrorEvent, PaymentInfoEvent>((PaymentErrorEvent) new DefaultPaymentErrorEvent("createPaymentError", e.getMessage(),
- null,
- null,
- context.getUserToken()));
-
+ throw new PaymentApiException(e);
}
}
- return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("retry_payment_error",
- "Could not load payment attempt, invoice or account for id " + paymentAttemptId,
- paymentAttempt.getAccountId(),
- paymentAttempt.getInvoiceId(),
- context.getUserToken()));
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_BAD, paymentAttemptId);
}
@Override
- public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(Account account, List<String> invoiceIds, CallContext context) {
+ public List<PaymentInfoEvent> createPayment(Account account, List<String> invoiceIds, CallContext context)
+ throws PaymentApiException {
+
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
List<Either<PaymentErrorEvent, PaymentInfoEvent>> processedPaymentsOrErrors = new ArrayList<Either<PaymentErrorEvent, PaymentInfoEvent>>(invoiceIds.size());
@@ -225,7 +253,15 @@ public class DefaultPaymentApi implements PaymentApi {
}
}
- return processedPaymentsOrErrors;
+ List<Either<PaymentErrorEvent, PaymentInfoEvent>> result = processedPaymentsOrErrors;
+ List<PaymentInfoEvent> info = new LinkedList<PaymentInfoEvent>();
+ for (Either<PaymentErrorEvent, PaymentInfoEvent> cur : result) {
+ if (cur.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT, account.getId(), cur.getLeft().getMessage());
+ }
+ info.add(cur.getRight());
+ }
+ return info;
}
private Either<PaymentErrorEvent, PaymentInfoEvent> processPayment(PaymentProviderPlugin plugin, Account account, Invoice invoice,
@@ -271,10 +307,10 @@ public class DefaultPaymentApi implements PaymentApi {
invoice.getId(),
paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : paymentInfo.getAmount(),
// paymentInfo.getRefundAmount(), TODO
- paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency(),
- paymentAttempt.getPaymentAttemptId(),
- paymentAttempt.getPaymentAttemptDate(),
- context);
+ paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency(),
+ paymentAttempt.getPaymentAttemptId(),
+ paymentAttempt.getPaymentAttemptDate(),
+ context);
return paymentOrError;
}
@@ -311,24 +347,29 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account, CallContext context) {
+ public String createPaymentProviderAccount(Account account, CallContext context)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin((Account)null);
- return plugin.createPaymentProviderAccount(account);
+ Either<PaymentErrorEvent, String> result = plugin.createPaymentProviderAccount(account);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_PROVIDER_ACCOUNT, account.getId(), result.getLeft().getMessage());
+ }
+ return result.getRight();
}
@Override
- public Either<PaymentErrorEvent, Void> updatePaymentProviderAccountContact(String externalKey, CallContext context) {
+ public void updatePaymentProviderAccountContact(String externalKey, CallContext context)
+ throws PaymentApiException {
try {
Account account = accountUserApi.getAccountByKey(externalKey);
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
- return plugin.updatePaymentProviderAccountExistingContact(account);
+ Either<PaymentErrorEvent, Void> result = plugin.updatePaymentProviderAccountExistingContact(account);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_UPD_PAYMENT_PROVIDER_ACCOUNT, account.getId(), result.getLeft().getMessage());
+ }
+ return;
} catch (AccountApiException e) {
- log.error("Error updating payment provider account contact.", e);
- return new Either.Left<PaymentErrorEvent, Void>((PaymentErrorEvent) new DefaultPaymentErrorEvent("updatePaymentProviderAccountContactError", e.getMessage(),
- null,
- null,
- context.getUserToken()));
-
+ throw new PaymentApiException(e);
}
}
@@ -338,11 +379,19 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createRefund(Account account,
- List<String> invoiceIds,
- CallContext context) {
+ public List<PaymentInfoEvent> createRefund(Account account, List<String> invoiceIds, CallContext context)
+ throws PaymentApiException {
+
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
- return plugin.processRefund(account);
+ List<Either<PaymentErrorEvent, PaymentInfoEvent>> result = plugin.processRefund(account);
+ List<PaymentInfoEvent> info = new LinkedList<PaymentInfoEvent>();
+ for (Either<PaymentErrorEvent, PaymentInfoEvent> cur : result) {
+ if (cur.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_REFUND, account.getId(), cur.getLeft().getMessage());
+ }
+ info.add(cur.getRight());
+ }
+ return info;
}
@Override
diff --git a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
index 3102e5c..2077c5e 100644
--- a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
@@ -18,23 +18,29 @@ package com.ning.billing.payment;
import java.util.Arrays;
import java.util.List;
+import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.payment.api.DefaultPaymentErrorEvent;
import com.ning.billing.payment.api.Either;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentErrorEvent;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.bus.Bus.EventBusException;
+import com.ning.billing.util.bus.BusEvent.BusEventType;
+import com.ning.billing.util.bus.BusEvent;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallOrigin;
import com.ning.billing.util.callcontext.DefaultCallContext;
@@ -52,39 +58,51 @@ public class RequestProcessor {
@Inject
public RequestProcessor(Clock clock,
- AccountUserApi accountUserApi,
- PaymentApi paymentApi,
- PaymentProviderPluginRegistry pluginRegistry,
- Bus eventBus) {
+ AccountUserApi accountUserApi,
+ PaymentApi paymentApi,
+ PaymentProviderPluginRegistry pluginRegistry,
+ Bus eventBus) {
this.clock = clock;
this.accountUserApi = accountUserApi;
this.paymentApi = paymentApi;
this.eventBus = eventBus;
}
+
+ private void postPaymentEvent(BusEvent ev, UUID accountId) {
+ if (ev == null) {
+ return;
+ }
+ try {
+ eventBus.post(ev);
+ } catch (EventBusException e) {
+ log.error("Failed to post Payment event event for account {} ", accountId, e);
+ }
+ }
@Subscribe
public void receiveInvoice(InvoiceCreationEvent event) {
+
+
log.info("Received invoice creation notification for account {} and invoice {}", event.getAccountId(), event.getInvoiceId());
+ PaymentErrorEvent errorEvent = null;
try {
final Account account = accountUserApi.getAccountById(event.getAccountId());
-
- if (account == null) {
- log.info("could not process invoice payment: could not find a valid account for event {}", event);
- }
- else {
+ if (account != null) {
CallContext context = new DefaultCallContext("PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, clock);
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account, Arrays.asList(event.getInvoiceId().toString()), context);
- if (!results.isEmpty()) {
- Either<PaymentErrorEvent, PaymentInfoEvent> result = results.get(0);
- try {
- eventBus.post(result.isLeft() ? result.getLeft() : result.getRight());
- } catch (EventBusException e) {
- log.error("Failed to post Payment event event for account {} ", account.getId(), e);
- }
- }
+ List<PaymentInfoEvent> results = paymentApi.createPayment(account, Arrays.asList(event.getInvoiceId().toString()), context);
+ PaymentInfoEvent infoEvent = (!results.isEmpty()) ? results.get(0) : null;
+ postPaymentEvent(infoEvent, account.getId());
+ return;
+ } else {
+ errorEvent = new DefaultPaymentErrorEvent(null, "Failed to retrieve account", event.getAccountId(), null, null);
}
} catch(AccountApiException e) {
- log.warn("could not process invoice payment", e);
+ log.error("Failed to process invoice payment", e);
+ errorEvent = new DefaultPaymentErrorEvent(null, e.getMessage(), event.getAccountId(), null, null);
+ } catch (PaymentApiException e) {
+ log.error("Failed to process invoice payment", e);
+ errorEvent = new DefaultPaymentErrorEvent(null, e.getMessage(), event.getAccountId(), null, null);
}
+ postPaymentEvent(errorEvent, event.getAccountId());
}
}
diff --git a/payment/src/main/java/com/ning/billing/payment/RetryService.java b/payment/src/main/java/com/ning/billing/payment/RetryService.java
index 447bb74..abc1fde 100644
--- a/payment/src/main/java/com/ning/billing/payment/RetryService.java
+++ b/payment/src/main/java/com/ning/billing/payment/RetryService.java
@@ -24,6 +24,8 @@ import com.ning.billing.util.callcontext.DefaultCallContext;
import com.ning.billing.util.callcontext.UserType;
import com.ning.billing.util.clock.Clock;
import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.ning.billing.config.PaymentConfig;
@@ -31,6 +33,7 @@ import com.ning.billing.lifecycle.KillbillService;
import com.ning.billing.lifecycle.LifecycleHandlerType;
import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.payment.api.PaymentStatus;
@@ -42,6 +45,9 @@ import com.ning.billing.util.notificationq.NotificationQueueService.Notification
import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
public class RetryService implements KillbillService {
+
+ private static final Logger log = LoggerFactory.getLogger(RetryService.class);
+
public static final String SERVICE_NAME = "retry-service";
public static final String QUEUE_NAME = "retry-events";
@@ -107,15 +113,14 @@ public class RetryService implements KillbillService {
}
private void retry(String paymentAttemptId, CallContext context) {
- PaymentInfoEvent paymentInfo = paymentApi.getPaymentInfoForPaymentAttemptId(paymentAttemptId);
-
- if (paymentInfo != null && PaymentStatus.Processed.equals(PaymentStatus.valueOf(paymentInfo.getStatus()))) {
- // update payment attempt with success and notify invoice api of payment
- System.out.println("Found processed payment");
- }
- else {
- System.out.println("Creating payment for payment attempt " + paymentAttemptId);
+ try {
+ PaymentInfoEvent paymentInfo = paymentApi.getPaymentInfoForPaymentAttemptId(paymentAttemptId);
+ if (paymentInfo != null && PaymentStatus.Processed.equals(PaymentStatus.valueOf(paymentInfo.getStatus()))) {
+ return;
+ }
paymentApi.createPaymentForPaymentAttempt(UUID.fromString(paymentAttemptId), context);
+ } catch (PaymentApiException e) {
+ log.error(String.format("Failed to retry payment for %s"), e);
}
}
}
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
index 4d3c630..85aa07b 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
@@ -102,12 +102,11 @@ public abstract class TestPaymentApi {
new BigDecimal("1.0"),
Currency.USD));
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
+ List<PaymentInfoEvent> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
assertEquals(results.size(), 1);
- assertTrue(results.get(0).isRight());
- PaymentInfoEvent paymentInfo = results.get(0).getRight();
+ PaymentInfoEvent paymentInfo = results.get(0);
assertNotNull(paymentInfo.getPaymentId());
assertTrue(paymentInfo.getAmount().compareTo(amount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
@@ -145,7 +144,7 @@ public abstract class TestPaymentApi {
}
- private PaymentProviderAccount setupAccountWithPaypalPaymentMethod() throws AccountApiException, EntityPersistenceException {
+ private PaymentProviderAccount setupAccountWithPaypalPaymentMethod() throws Exception {
final Account account = testHelper.createTestPayPalAccount();
paymentApi.createPaymentProviderAccount(account, context);
@@ -156,32 +155,23 @@ public abstract class TestPaymentApi {
.setEmail(account.getEmail())
.setDefaultMethod(true)
.build();
- Either<PaymentErrorEvent, String> paymentMethodIdOrError = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
+ String paymentMethodId = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
- assertTrue(paymentMethodIdOrError.isRight());
- assertNotNull(paymentMethodIdOrError.getRight());
+ PaymentMethodInfo paymentMethodInfo = paymentApi.getPaymentMethod(accountKey, paymentMethodId);
- Either<PaymentErrorEvent, PaymentMethodInfo> paymentMethodInfoOrError = paymentApi.getPaymentMethod(accountKey, paymentMethodIdOrError.getRight());
-
- assertTrue(paymentMethodInfoOrError.isRight());
- assertNotNull(paymentMethodInfoOrError.getRight());
-
- Either<PaymentErrorEvent, PaymentProviderAccount> accountOrError = paymentApi.getPaymentProviderAccount(accountKey);
-
- assertTrue(accountOrError.isRight());
-
- return accountOrError.getRight();
+ PaymentProviderAccount accountResult = paymentApi.getPaymentProviderAccount(accountKey);
+ return accountResult;
}
@Test(enabled=true)
- public void testCreatePaypalPaymentMethod() throws AccountApiException, EntityPersistenceException {
+ public void testCreatePaypalPaymentMethod() throws Exception {
PaymentProviderAccount account = setupAccountWithPaypalPaymentMethod();
assertNotNull(account);
paymentApi.getPaymentMethods(account.getAccountKey());
}
@Test(enabled=true)
- public void testUpdatePaymentProviderAccountContact() throws AccountApiException, EntityPersistenceException {
+ public void testUpdatePaymentProviderAccountContact() throws Exception {
final Account account = testHelper.createTestPayPalAccount();
paymentApi.createPaymentProviderAccount(account, context);
@@ -198,19 +188,12 @@ public abstract class TestPaymentApi {
.billingCycleDay(account.getBillCycleDay())
.build();
- Either<PaymentErrorEvent, Void> voidOrError = paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey(), context);
- assertTrue(voidOrError.isRight());
+ paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey(), context);
}
@Test(enabled=true)
- public void testCannotDeleteDefaultPaymentMethod() throws AccountApiException, EntityPersistenceException {
+ public void testCannotDeleteDefaultPaymentMethod() throws Exception {
PaymentProviderAccount account = setupAccountWithPaypalPaymentMethod();
-
- Either<PaymentErrorEvent, Void> errorOrVoid = paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId(), context);
-
- assertTrue(errorOrVoid.isLeft());
+ paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId(), context);
}
-
-
-
}
diff --git a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
index 5ab2157..9a49780 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -44,6 +44,7 @@ import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
import com.ning.billing.mock.glue.MockJunctionModule;
import com.ning.billing.payment.api.Either;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentErrorEvent;
import com.ning.billing.payment.api.PaymentInfoEvent;
@@ -139,11 +140,13 @@ public class TestRetryService {
Currency.USD));
mockPaymentProviderPlugin.makeNextInvoiceFail();
-
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
-
- assertEquals(results.size(), 1);
- assertTrue(results.get(0).isLeft());
+ boolean failed = false;
+ try {
+ paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
+ } catch (PaymentApiException e) {
+ failed = true;
+ }
+ assertTrue(failed);
List<Notification> pendingNotifications = mockNotificationQueue.getPendingEvents();