killbill-uncached
Details
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java b/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
index e815d1f..1437745 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
@@ -140,7 +140,7 @@ public abstract class InvoiceCalculatorUtils {
for (final InvoiceItem invoiceItem : invoiceItems) {
if (isCharge(invoiceItem) &&
- invoiceItem.getCreatedDate().equals(invoiceCreatedDate)) {
+ (invoiceItem.getCreatedDate() != null && invoiceItem.getCreatedDate().equals(invoiceCreatedDate))) {
amountCharged = amountCharged.add(invoiceItem.getAmount());
}
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java b/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
index 7eeda4b..77fd9e3 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
@@ -23,7 +23,6 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
-
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.invoice.api.InvoiceItem;
import org.killbill.billing.invoice.api.InvoiceItemType;
@@ -86,7 +85,7 @@ public class InvoiceItemFactory {
item = new UsageInvoiceItem(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, usageName, startDate, endDate, description, amount, currency);
break;
case TAX:
- item = new TaxInvoiceItem(id, createdDate, invoiceId, accountId, bundleId, description, startDate, amount, currency);
+ item = new TaxInvoiceItem(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, usageName, startDate, description, amount, currency, linkedItemId);
break;
default:
throw new RuntimeException("Unexpected type of event item " + type);
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/TaxInvoiceItem.java b/invoice/src/main/java/org/killbill/billing/invoice/model/TaxInvoiceItem.java
index 24fb389..16d0970 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/TaxInvoiceItem.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/TaxInvoiceItem.java
@@ -35,12 +35,13 @@ public class TaxInvoiceItem extends InvoiceItemBase {
public TaxInvoiceItem(final UUID id, final UUID invoiceId, final UUID accountId, @Nullable final UUID bundleId,
@Nullable final String description, final LocalDate date, final BigDecimal amount, final Currency currency) {
- this(id, null, invoiceId, accountId, bundleId, description, date, amount, currency);
+ this(id, null, invoiceId, accountId, bundleId, null, null, null, null, date, description, amount, currency, null);
}
public TaxInvoiceItem(final UUID id, @Nullable final DateTime createdDate, final UUID invoiceId, final UUID accountId, @Nullable final UUID bundleId,
- @Nullable final String description, final LocalDate date, final BigDecimal amount, final Currency currency) {
- super(id, createdDate, invoiceId, accountId, bundleId, null, description, null, null, null, date, null, amount, currency);
+ @Nullable final UUID subscriptionId, @Nullable final String planName, @Nullable final String phaseName, @Nullable final String usageName,
+ final LocalDate date, @Nullable final String description, final BigDecimal amount, final Currency currency, @Nullable final UUID linkedItemId) {
+ super(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, description, planName, phaseName, usageName, date, null, amount, currency, linkedItemId);
}
@Override
NEWS 15(+15 -0)
diff --git a/NEWS b/NEWS
index e34c46a..ff90da8 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,18 @@
+0.13.1
+ https://github.com/killbill/killbill/issues/226
+ https://github.com/killbill/killbill/issues/233
+ https://github.com/killbill/killbill/issues/234
+ https://github.com/killbill/killbill/issues/235
+ https://github.com/killbill/killbill/issues/236
+ https://github.com/killbill/killbill/issues/245
+ Add support for invoice plugins
+ Export more fields in TaxInvoiceItem
+ Update killbill-oss-parent to 0.9.7
+
+0.12.2
+ Fix state machine flow for PENDING payments
+ Fix Guice wiring in JAX-RS
+
0.12.1
Fix NPE in case of aborted payments
Add missing headers for CORS
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
index ffbb208..e01c8ab 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
@@ -17,14 +17,10 @@
package org.killbill.billing.payment.core;
-import java.util.UUID;
import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import javax.annotation.Nullable;
import javax.inject.Inject;
import org.killbill.billing.ErrorCode;
@@ -47,10 +43,8 @@ import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.config.PaymentConfig;
import org.killbill.billing.util.dao.NonEntityDao;
-import org.killbill.bus.api.PersistentBus;
import org.killbill.clock.Clock;
import org.killbill.commons.locker.GlobalLocker;
-import org.killbill.commons.locker.LockFailedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,6 +53,11 @@ import com.google.inject.name.Named;
import static org.killbill.billing.payment.glue.PaymentModule.PLUGIN_EXECUTOR_NAMED;
+// We don't take any lock here because the call needs to be re-entrant
+// from the plugin: for example, the BitPay plugin will create the payment during the
+// processNotification call, while the PayU plugin will create it during buildFormDescriptor.
+// These calls are not necessarily idempotent though (the PayU plugin will create
+// a voucher in the gateway during the buildFormDescriptor call).
public class PaymentGatewayProcessor extends ProcessorBase {
private final PluginDispatcher<HostedPaymentPageFormDescriptor> paymentPluginFormDispatcher;
@@ -93,35 +92,29 @@ public class PaymentGatewayProcessor extends ProcessorBase {
try {
final GatewayNotification result = plugin.processNotification(notification, properties, callContext);
return PluginDispatcher.createPluginDispatcherReturnType(result);
- } catch (PaymentPluginApiException e) {
+ } catch (final PaymentPluginApiException e) {
throw new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_EXCEPTION, e.getErrorMessage());
}
}
}, paymentPluginNotificationDispatcher);
}
-
-
public HostedPaymentPageFormDescriptor buildFormDescriptor(final Account account, final Iterable<PluginProperty> customFields, final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return dispatchWithExceptionHandling(account,
- new CallableWithAccountLock<HostedPaymentPageFormDescriptor, PaymentApiException>(locker,
- account.getExternalKey(),
- new WithAccountLockCallback<PluginDispatcherReturnType<HostedPaymentPageFormDescriptor>, PaymentApiException>() {
- @Override
- public PluginDispatcherReturnType<HostedPaymentPageFormDescriptor> doOperation() throws PaymentApiException {
- final PaymentPluginApi plugin = getPaymentProviderPlugin(account, internalCallContext);
+ new Callable<PluginDispatcherReturnType<HostedPaymentPageFormDescriptor>>() {
+ @Override
+ public PluginDispatcherReturnType<HostedPaymentPageFormDescriptor> call() throws PaymentApiException {
+ final PaymentPluginApi plugin = getPaymentProviderPlugin(account, internalCallContext);
- try {
- final HostedPaymentPageFormDescriptor result = plugin.buildFormDescriptor(account.getId(), customFields, properties, callContext);
- return PluginDispatcher.createPluginDispatcherReturnType(result);
- } catch (final RuntimeException e) {
- throw new PaymentApiException(e, ErrorCode.PAYMENT_INTERNAL_ERROR, Objects.firstNonNull(e.getMessage(), ""));
- } catch (final PaymentPluginApiException e) {
- throw new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_EXCEPTION, e.getErrorMessage());
- }
- }
- }),
- paymentPluginFormDispatcher);
+ try {
+ final HostedPaymentPageFormDescriptor result = plugin.buildFormDescriptor(account.getId(), customFields, properties, callContext);
+ return PluginDispatcher.createPluginDispatcherReturnType(result);
+ } catch (final RuntimeException e) {
+ throw new PaymentApiException(e, ErrorCode.PAYMENT_INTERNAL_ERROR, Objects.firstNonNull(e.getMessage(), ""));
+ } catch (final PaymentPluginApiException e) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_EXCEPTION, e.getErrorMessage());
+ }
+ }
+ }, paymentPluginFormDispatcher);
}
-
}
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 f4aeef9..fa8ccf3 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
+++ b/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
@@ -127,6 +127,7 @@
<stateMachine name="PURCHASE">
<states>
<state name="PURCHASE_INIT"/>
+ <state name="PURCHASE_PENDING"/>
<state name="PURCHASE_SUCCESS"/>
<state name="PURCHASE_FAILED"/>
<state name="PURCHASE_ERRORED"/>
@@ -147,6 +148,30 @@
<transition>
<initialState>PURCHASE_INIT</initialState>
<operation>OP_PURCHASE</operation>
+ <operationResult>PENDING</operationResult>
+ <finalState>PURCHASE_PENDING</finalState>
+ </transition>
+ <transition>
+ <initialState>PURCHASE_PENDING</initialState>
+ <operation>OP_PURCHASE</operation>
+ <operationResult>SUCCESS</operationResult>
+ <finalState>PURCHASE_SUCCESS</finalState>
+ </transition>
+ <transition>
+ <initialState>PURCHASE_PENDING</initialState>
+ <operation>OP_PURCHASE</operation>
+ <operationResult>FAILURE</operationResult>
+ <finalState>PURCHASE_FAILED</finalState>
+ </transition>
+ <transition>
+ <initialState>PURCHASE_PENDING</initialState>
+ <operation>OP_PURCHASE</operation>
+ <operationResult>EXCEPTION</operationResult>
+ <finalState>PURCHASE_ERRORED</finalState>
+ </transition>
+ <transition>
+ <initialState>PURCHASE_INIT</initialState>
+ <operation>OP_PURCHASE</operation>
<operationResult>EXCEPTION</operationResult>
<finalState>PURCHASE_ERRORED</finalState>
</transition>
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index de67363..0b1436a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
<parent>
<artifactId>killbill-oss-parent</artifactId>
<groupId>org.kill-bill.billing</groupId>
- <version>0.9.5</version>
+ <version>0.9.7</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.13.1-SNAPSHOT</version>
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java b/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
index c254cd0..29dc32c 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
@@ -125,17 +125,19 @@ public class TenantFilter implements Filter {
if (request instanceof HttpServletRequest) {
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+ // TODO Wrong - See https://github.com/killbill/killbill/issues/221
final String path = httpServletRequest.getRequestURI();
+ final String httpMethod = httpServletRequest.getMethod();
if ( // Chicken - egg problem
- ("/1.0/kb/tenants".equals(path) && "POST".equals(httpServletRequest.getMethod())) ||
+ isTenantCreationRequest(path, httpMethod) ||
// Retrieve user permissions should not require tenant info since this is cross tenants
- (("/1.0/kb/security/subject".equals(path) || "/1.0/kb/security/permissions".equals(path)) && "GET".equals(httpServletRequest.getMethod())) ||
+ isPermissionRequest(path, httpMethod) ||
// Metrics servlets
- (KillbillGuiceListener.METRICS_SERVLETS_PATHS.contains(path) && "GET".equals(httpServletRequest.getMethod())) ||
+ isMetricsRequest(path, httpMethod) ||
// See KillBillShiroWebModule#CorsBasicHttpAuthenticationFilter
- "OPTIONS".equals(httpServletRequest.getMethod()) ||
- // Welcome screen, static resources, etc.
- (!path.startsWith("/1.0") && "GET".equals(httpServletRequest.getMethod()))
+ isOptionsRequest(httpMethod) ||
+ // Static resources
+ isStaticResourceRequest(path, httpMethod)
) {
shouldSkip = true;
}
@@ -144,6 +146,53 @@ public class TenantFilter implements Filter {
return shouldSkip;
}
+ private boolean isPermissionRequest(final String path, final String httpMethod) {
+ return JaxrsResource.SECURITY_PATH.startsWith(path) && "GET".equals(httpMethod);
+ }
+
+ private boolean isTenantCreationRequest(final String path, final String httpMethod) {
+ return JaxrsResource.TENANTS_PATH.equals(path) && "POST".equals(httpMethod);
+ }
+
+ private boolean isMetricsRequest(final String path, final String httpMethod) {
+ return KillbillGuiceListener.METRICS_SERVLETS_PATHS.contains(path) && "GET".equals(httpMethod);
+ }
+
+ private boolean isOptionsRequest(final String httpMethod) {
+ return "OPTIONS".equals(httpMethod);
+ }
+
+ private boolean isStaticResourceRequest(final String path, final String httpMethod) {
+ if (isPluginRequest(path)) {
+ // For plugins requests, we want to validate the Tenant except for HTML, JS, etc. files
+ return isStaticFileRequest(path) && "GET".equals(httpMethod);
+ } else {
+ // Welcome screen, Swagger, etc.
+ return !isKbApiRequest(path) && "GET".equals(httpMethod);
+ }
+ }
+
+ private boolean isKbApiRequest(final String path) {
+ return path.startsWith(JaxrsResource.PREFIX);
+ }
+
+ private boolean isPluginRequest(final String path) {
+ return path.startsWith(JaxrsResource.PLUGINS_PATH);
+ }
+
+ private boolean isStaticFileRequest(final String path) {
+ return path.endsWith(".htm") ||
+ path.endsWith(".html") ||
+ path.endsWith(".js") ||
+ path.endsWith(".css") ||
+ path.endsWith(".gz") ||
+ path.endsWith(".xml") ||
+ path.endsWith(".txt") ||
+ path.endsWith(".map")||
+ path.endsWith(".woff")||
+ path.endsWith(".ttf");
+ }
+
private void sendAuthError(final ServletResponse response, final String errorMessage) throws IOException {
if (response instanceof HttpServletResponse) {
final HttpServletResponse httpServletResponse = (HttpServletResponse) response;