Commit
Code is in place and test pass. Need a second code review pass, and iron details about what should be a payment config property, versus hard-coded value
- Loading branch information
There are no files selected for viewing
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
|
@@ -17,15 +17,20 @@ | ||
|
|
||
import java.util.UUID; | import java.util.UUID; | ||
|
|
||
import org.killbill.billing.payment.api.TransactionStatus; | |||
import org.killbill.billing.payment.api.TransactionType; | import org.killbill.billing.payment.api.TransactionType; | ||
|
|
||
public interface PaymentErrorInternalEvent extends BusInternalEvent { | public interface PaymentErrorInternalEvent extends PaymentInternalEvent { | ||
|
|
||
public String getMessage(); | public String getMessage(); | ||
|
|
||
public UUID getAccountId(); | public UUID getAccountId(); | ||
|
|
||
public UUID getPaymentId(); | public UUID getPaymentId(); | ||
|
|
||
public UUID getPaymentTransactionId(); | |||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
sbrossie
Author
Member
|
|||
|
|||
public TransactionStatus getStatus(); | |||
|
|||
public TransactionType getTransactionType(); | public TransactionType getTransactionType(); | ||
} | } |
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,37 @@ | |||
/* | |||
* Copyright 2014-2015 Groupon, Inc | |||
* Copyright 2014-2015 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.events; | |||
|
|||
import java.util.UUID; | |||
|
|||
import org.killbill.billing.payment.api.TransactionStatus; | |||
import org.killbill.billing.payment.api.TransactionType; | |||
|
|||
public interface PaymentInternalEvent extends BusInternalEvent { | |||
|
|||
public UUID getAccountId(); | |||
|
|||
public UUID getPaymentId(); | |||
|
|||
public UUID getPaymentTransactionId(); | |||
|
|||
public TransactionType getTransactionType(); | |||
|
|||
public TransactionStatus getStatus(); | |||
|
|||
} |
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
|
@@ -18,6 +18,7 @@ | ||
|
|
||
package org.killbill.billing.payment.bus; | package org.killbill.billing.payment.bus; | ||
|
|
||
import java.io.IOException; | |||
import java.math.BigDecimal; | import java.math.BigDecimal; | ||
import java.util.ArrayList; | import java.util.ArrayList; | ||
import java.util.LinkedList; | import java.util.LinkedList; | ||
|
@@ -29,9 +30,12 @@ | ||
import org.killbill.billing.account.api.AccountInternalApi; | import org.killbill.billing.account.api.AccountInternalApi; | ||
import org.killbill.billing.callcontext.InternalCallContext; | import org.killbill.billing.callcontext.InternalCallContext; | ||
import org.killbill.billing.events.InvoiceCreationInternalEvent; | import org.killbill.billing.events.InvoiceCreationInternalEvent; | ||
import org.killbill.billing.events.PaymentInternalEvent; | |||
import org.killbill.billing.payment.api.DefaultPaymentInfoEvent; | |||
import org.killbill.billing.payment.api.PaymentApiException; | import org.killbill.billing.payment.api.PaymentApiException; | ||
import org.killbill.billing.payment.api.PluginProperty; | import org.killbill.billing.payment.api.PluginProperty; | ||
import org.killbill.billing.payment.core.PluginRoutingPaymentProcessor; | import org.killbill.billing.payment.core.PluginRoutingPaymentProcessor; | ||
import org.killbill.billing.payment.core.janitor.Janitor; | |||
import org.killbill.billing.payment.invoice.InvoicePaymentRoutingPluginApi; | import org.killbill.billing.payment.invoice.InvoicePaymentRoutingPluginApi; | ||
import org.killbill.billing.util.UUIDs; | import org.killbill.billing.util.UUIDs; | ||
import org.killbill.billing.util.callcontext.CallContext; | import org.killbill.billing.util.callcontext.CallContext; | ||
|
@@ -46,26 +50,39 @@ | ||
import com.google.common.eventbus.Subscribe; | import com.google.common.eventbus.Subscribe; | ||
import com.google.inject.Inject; | import com.google.inject.Inject; | ||
|
|
||
public class InvoiceHandler { | public class PaymentBusEventHandler { | ||
|
|
||
private final AccountInternalApi accountApi; | private final AccountInternalApi accountApi; | ||
private final InternalCallContextFactory internalCallContextFactory; | private final InternalCallContextFactory internalCallContextFactory; | ||
private final PluginRoutingPaymentProcessor pluginRoutingPaymentProcessor; | private final PluginRoutingPaymentProcessor pluginRoutingPaymentProcessor; | ||
private final PaymentConfig paymentConfig; | private final PaymentConfig paymentConfig; | ||
private final Janitor janitor; | |||
|
|
||
private static final Logger log = LoggerFactory.getLogger(InvoiceHandler.class); | private static final Logger log = LoggerFactory.getLogger(PaymentBusEventHandler.class); | ||
|
|
||
@Inject | @Inject | ||
public InvoiceHandler(final PaymentConfig paymentConfig, | public PaymentBusEventHandler(final PaymentConfig paymentConfig, | ||
final AccountInternalApi accountApi, | final AccountInternalApi accountApi, | ||
final PluginRoutingPaymentProcessor pluginRoutingPaymentProcessor, | final PluginRoutingPaymentProcessor pluginRoutingPaymentProcessor, | ||
final InternalCallContextFactory internalCallContextFactory) { | final Janitor janitor, | ||
final InternalCallContextFactory internalCallContextFactory) { | |||
this.paymentConfig = paymentConfig; | this.paymentConfig = paymentConfig; | ||
this.accountApi = accountApi; | this.accountApi = accountApi; | ||
this.janitor = janitor; | |||
this.internalCallContextFactory = internalCallContextFactory; | this.internalCallContextFactory = internalCallContextFactory; | ||
this.pluginRoutingPaymentProcessor = pluginRoutingPaymentProcessor; | this.pluginRoutingPaymentProcessor = pluginRoutingPaymentProcessor; | ||
} | } | ||
|
|
||
@AllowConcurrentEvents | |||
@Subscribe | |||
public void processPaymentEvent(final PaymentInternalEvent event) { | |||
try { | |||
janitor.processPaymentEvent(event); | |||
} catch (IOException e) { | |||
This comment has been minimized.
Sorry, something went wrong.
pierre
Member
|
|||
log.error("Failed to process payment event {}", e.toString()); | |||
} | |||
} | |||
|
|||
@AllowConcurrentEvents | @AllowConcurrentEvents | ||
@Subscribe | @Subscribe | ||
public void processInvoiceEvent(final InvoiceCreationInternalEvent event) { | public void processInvoiceEvent(final InvoiceCreationInternalEvent event) { | ||
|
7 comments
on commit 16e2e51
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thought regarding configuration: it seems it would be easy to have a configuration per plugin (from the payment, we can retrieve the payment method and hence the plugin name)? While this would not completely solve the problem to determine wether a payment is ACH pending or HPP pending in the case of Adyen for instance, it would help optimize certain scenarii (e.g. disable completely the polling for CyberSource in case the report API isn't configured).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding terminal states, we currently don't have UNKNOWN_ABORTED
/PENDING_ABORTED
, i.e. it is possible to have payments stuck in UNKNOWN
/PENDING
forever. Would it make sense to force a transition from PENDING
to UNKNOWN
after the retries delay has expired (e.g. 7 days)? This would make it easy to spot problematic transactions to fix manually (all UNKNOWN
ones).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall 👍!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Github's comments are 'at least once' semantics, but more than once this is 'at least 3 times' semantics...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thought regarding configuration: it seems it would be easy to have a configuration per plugin (from the payment, we can retrieve the payment method and hence the plugin name)? While this would not completely solve the problem to determine wether a payment is ACH pending or HPP pending in the case of Adyen for instance, it would help optimize certain scenarii (e.g. disable completely the polling for CyberSource in case the report API isn't configured).
But does it mean adding a new payment plugin API? In some ways that seem related to #331
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding terminal states, we currently don't have UNKNOWN_ABORTED/PENDING_ABORTED, i.e. it is possible to have payments stuck in UNKNOWN/PENDING forever.
Yes. And we said that some human at some point should look for OLD UNKNOWN/PENDING and do something with it.
Would it make sense to force a transition from PENDING to UNKNOWN after the retries delay has expired (e.g. 7 days)? This would make it easy to spot problematic transactions to fix manually (all UNKNOWN ones).
I don't like too much because we can't then differentiate easily the between the original UNKNOWN and the original PENDING (unless of course we look at the history). I 'd be more inclined to introduce the new state UNKNOWN_ABORTED/PENDING_ABORTED
in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But does it mean adding a new payment plugin API?
No, I actually thought we could simply specify it via properties (e.g. org.killbill.billing.payment.killbill-adyen.janitorRetries=1,3,3,3,60,60,60,...
). But I see your point, it should be provided by the plugin (it has the knowledge)... One way would be to make OSGIConfigPropertiesService
r/w instead of r/o and the plugin could simply set these properties on startup. More thinking needed here...
I don't like too much because we can't then differentiate easily the between the original UNKNOWN and the original PENDING (unless of course we look at the history)
Yeah, I see. Scratch my comment!
Both shouldn't required anymore (present in
PaymentInternalEvent
).