use of org.killbill.billing.payment.api.TransactionType in project killbill by killbill.
the class AccountResource method processPayment.
private Response processPayment(final PaymentTransactionJson json, final Account account, final String paymentMethodIdStr, final List<String> paymentControlPluginNames, final List<String> pluginPropertiesString, final UriInfo uriInfo, final CallContext callContext, final HttpServletRequest request) throws PaymentApiException {
verifyNonNullOrEmpty(json, "PaymentTransactionJson body should be specified");
verifyNonNullOrEmpty(json.getTransactionType(), "PaymentTransactionJson transactionType needs to be set", json.getAmount(), "PaymentTransactionJson amount needs to be set");
final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
final Currency currency = json.getCurrency() == null ? account.getCurrency() : Currency.valueOf(json.getCurrency());
final UUID paymentId = json.getPaymentId() == null ? null : UUID.fromString(json.getPaymentId());
//
// If paymentId was specified, it means we are attempting a payment completion. The preferred way is to use the PaymentResource
// (PUT /1.0/kb/payments/{paymentId}/completeTransaction), but for backward compatibility we still allow the call to proceed
// as long as the request/existing state is healthy (i.e there is a matching PENDING transaction)
//
final UUID paymentMethodId;
if (paymentId != null) {
final Payment initialPayment = paymentApi.getPayment(paymentId, false, false, pluginProperties, callContext);
final PaymentTransaction pendingOrSuccessTransaction = lookupPendingOrSuccessTransaction(initialPayment, json != null ? json.getTransactionId() : null, json != null ? json.getTransactionExternalKey() : null, json != null ? json.getTransactionType() : null);
// If transaction was already completed, return early (See #626)
if (pendingOrSuccessTransaction.getTransactionStatus() == TransactionStatus.SUCCESS) {
return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", pendingOrSuccessTransaction.getPaymentId(), request);
}
paymentMethodId = initialPayment.getPaymentMethodId();
} else {
paymentMethodId = paymentMethodIdStr == null ? account.getPaymentMethodId() : UUID.fromString(paymentMethodIdStr);
}
validatePaymentMethodForAccount(account.getId(), paymentMethodId, callContext);
final TransactionType transactionType = TransactionType.valueOf(json.getTransactionType());
final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
final Payment result;
switch(transactionType) {
case AUTHORIZE:
result = paymentApi.createAuthorizationWithPaymentControl(account, paymentMethodId, paymentId, json.getAmount(), currency, json.getPaymentExternalKey(), json.getTransactionExternalKey(), pluginProperties, paymentOptions, callContext);
break;
case PURCHASE:
result = paymentApi.createPurchaseWithPaymentControl(account, paymentMethodId, paymentId, json.getAmount(), currency, json.getPaymentExternalKey(), json.getTransactionExternalKey(), pluginProperties, paymentOptions, callContext);
break;
case CREDIT:
result = paymentApi.createCreditWithPaymentControl(account, paymentMethodId, paymentId, json.getAmount(), currency, json.getPaymentExternalKey(), json.getTransactionExternalKey(), pluginProperties, paymentOptions, callContext);
break;
default:
return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + transactionType + " is not allowed for an account").build();
}
return createPaymentResponse(uriInfo, result, transactionType, json.getTransactionExternalKey(), request);
}
use of org.killbill.billing.payment.api.TransactionType in project killbill by killbill.
the class InvoicePaymentControlPluginApi method onSuccessCall.
@Override
public OnSuccessPaymentControlResult onSuccessCall(final PaymentControlContext paymentControlContext, final Iterable<PluginProperty> pluginProperties) throws PaymentControlApiException {
final TransactionType transactionType = paymentControlContext.getTransactionType();
Preconditions.checkArgument(transactionType == TransactionType.PURCHASE || transactionType == TransactionType.REFUND || transactionType == TransactionType.CHARGEBACK || transactionType == TransactionType.CREDIT);
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(paymentControlContext.getAccountId(), paymentControlContext);
try {
final InvoicePayment existingInvoicePayment;
switch(transactionType) {
case PURCHASE:
final UUID invoiceId = getInvoiceId(pluginProperties);
existingInvoicePayment = invoiceApi.getInvoicePaymentForAttempt(paymentControlContext.getPaymentId(), internalContext);
if (existingInvoicePayment != null && existingInvoicePayment.isSuccess()) {
// Only one successful purchase per payment (the invoice could be linked to multiple successful payments though)
log.info("onSuccessCall was already completed for purchase paymentId='{}'", paymentControlContext.getPaymentId());
} else {
final BigDecimal invoicePaymentAmount;
if (paymentControlContext.getCurrency() == paymentControlContext.getProcessedCurrency()) {
invoicePaymentAmount = paymentControlContext.getProcessedAmount();
} else {
log.warn("processedCurrency='{}' of invoice paymentId='{}' doesn't match invoice currency='{}', assuming it is a full payment", paymentControlContext.getProcessedCurrency(), paymentControlContext.getPaymentId(), paymentControlContext.getCurrency());
invoicePaymentAmount = paymentControlContext.getAmount();
}
final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(paymentControlContext.getTransactionId(), internalContext);
// If it's not SUCCESS, it is PENDING
final boolean success = paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.SUCCESS;
log.debug("Notifying invoice of {} paymentId='{}', amount='{}', currency='{}', invoiceId='{}'", success ? "successful" : "pending", paymentControlContext.getPaymentId(), invoicePaymentAmount, paymentControlContext.getCurrency(), invoiceId);
// For PENDING payments, the attempt will be kept as unsuccessful and an InvoicePaymentErrorInternalEvent sent on the bus (e.g. for Overdue)
invoiceApi.recordPaymentAttemptCompletion(invoiceId, invoicePaymentAmount, paymentControlContext.getCurrency(), paymentControlContext.getProcessedCurrency(), paymentControlContext.getPaymentId(), paymentControlContext.getTransactionExternalKey(), paymentControlContext.getCreatedDate(), success, internalContext);
}
break;
case REFUND:
final Map<UUID, BigDecimal> idWithAmount = extractIdsWithAmountFromProperties(pluginProperties);
final PluginProperty prop = getPluginProperty(pluginProperties, PROP_IPCD_REFUND_WITH_ADJUSTMENTS);
final boolean isAdjusted = prop != null ? Boolean.valueOf((String) prop.getValue()) : false;
invoiceApi.recordRefund(paymentControlContext.getPaymentId(), paymentControlContext.getAmount(), isAdjusted, idWithAmount, paymentControlContext.getTransactionExternalKey(), internalContext);
break;
case CHARGEBACK:
existingInvoicePayment = invoiceApi.getInvoicePaymentForChargeback(paymentControlContext.getPaymentId(), internalContext);
if (existingInvoicePayment != null) {
// We don't support partial chargebacks (yet?)
log.info("onSuccessCall was already completed for chargeback paymentId='{}'", paymentControlContext.getPaymentId());
} else {
final InvoicePayment linkedInvoicePayment = invoiceApi.getInvoicePaymentForAttempt(paymentControlContext.getPaymentId(), internalContext);
final BigDecimal amount;
final Currency currency;
if (linkedInvoicePayment.getCurrency().equals(paymentControlContext.getProcessedCurrency()) && paymentControlContext.getProcessedAmount() != null) {
amount = paymentControlContext.getProcessedAmount();
currency = paymentControlContext.getProcessedCurrency();
} else if (linkedInvoicePayment.getCurrency().equals(paymentControlContext.getCurrency()) && paymentControlContext.getAmount() != null) {
amount = paymentControlContext.getAmount();
currency = paymentControlContext.getCurrency();
} else {
amount = linkedInvoicePayment.getAmount();
currency = linkedInvoicePayment.getCurrency();
}
invoiceApi.recordChargeback(paymentControlContext.getPaymentId(), paymentControlContext.getTransactionExternalKey(), amount, currency, internalContext);
}
break;
case CREDIT:
final Map<UUID, BigDecimal> idWithAmountMap = extractIdsWithAmountFromProperties(pluginProperties);
final PluginProperty properties = getPluginProperty(pluginProperties, PROP_IPCD_REFUND_WITH_ADJUSTMENTS);
final boolean isInvoiceAdjusted = properties != null ? Boolean.valueOf((String) properties.getValue()) : false;
final PluginProperty legacyPayment = getPluginProperty(pluginProperties, PROP_IPCD_PAYMENT_ID);
final UUID paymentId = legacyPayment != null ? (UUID) legacyPayment.getValue() : paymentControlContext.getPaymentId();
invoiceApi.recordRefund(paymentId, paymentControlContext.getAmount(), isInvoiceAdjusted, idWithAmountMap, paymentControlContext.getTransactionExternalKey(), internalContext);
break;
default:
throw new IllegalStateException("Unexpected transactionType " + transactionType);
}
} catch (final InvoiceApiException e) {
log.warn("onSuccessCall failed for attemptId='{}', transactionType='{}'", paymentControlContext.getAttemptPaymentId(), transactionType, e);
}
return new DefaultOnSuccessPaymentControlResult();
}
use of org.killbill.billing.payment.api.TransactionType in project killbill by killbill.
the class InvoicePaymentControlPluginApi method priorCall.
@Override
public PriorPaymentControlResult priorCall(final PaymentControlContext paymentControlContext, final Iterable<PluginProperty> pluginProperties) throws PaymentControlApiException {
final TransactionType transactionType = paymentControlContext.getTransactionType();
Preconditions.checkArgument(paymentControlContext.getPaymentApiType() == PaymentApiType.PAYMENT_TRANSACTION);
Preconditions.checkArgument(transactionType == TransactionType.PURCHASE || transactionType == TransactionType.REFUND || transactionType == TransactionType.CHARGEBACK || transactionType == TransactionType.CREDIT);
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(paymentControlContext.getAccountId(), paymentControlContext);
switch(transactionType) {
case PURCHASE:
return getPluginPurchaseResult(paymentControlContext, pluginProperties, internalContext);
case REFUND:
return getPluginRefundResult(paymentControlContext, pluginProperties, internalContext);
case CHARGEBACK:
return new DefaultPriorPaymentControlResult(false, paymentControlContext.getAmount());
case CREDIT:
return getPluginCreditResult(paymentControlContext, pluginProperties, internalContext);
default:
throw new IllegalStateException("Unexpected transactionType " + transactionType);
}
}
use of org.killbill.billing.payment.api.TransactionType in project killbill by killbill.
the class TestPaymentDao method testPaymentAttempt.
@Test(groups = "slow")
public void testPaymentAttempt() throws PluginPropertySerializerException {
final UUID transactionId = UUID.randomUUID();
final String paymentExternalKey = "vraiment?";
final String transactionExternalKey = "tduteuqweq";
final String stateName = "INIT";
final TransactionType transactionType = TransactionType.AUTHORIZE;
final String pluginName = "superPlugin";
final List<PluginProperty> properties = new ArrayList<PluginProperty>();
properties.add(new PluginProperty("key1", "value1", false));
properties.add(new PluginProperty("key2", "value2", false));
final byte[] serialized = PluginPropertySerializer.serialize(properties);
final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(UUID.randomUUID(), UUID.randomUUID(), clock.getUTCNow(), clock.getUTCNow(), paymentExternalKey, transactionId, transactionExternalKey, transactionType, stateName, BigDecimal.ZERO, Currency.ALL, ImmutableList.<String>of(pluginName), serialized);
PaymentAttemptModelDao savedAttempt = paymentDao.insertPaymentAttemptWithProperties(attempt, internalCallContext);
assertEquals(savedAttempt.getTransactionExternalKey(), transactionExternalKey);
assertEquals(savedAttempt.getTransactionType(), transactionType);
assertEquals(savedAttempt.getStateName(), stateName);
assertEquals(savedAttempt.getPluginName(), pluginName);
final Iterable<PluginProperty> deserialized = PluginPropertySerializer.deserialize(savedAttempt.getPluginProperties());
int i = 0;
for (PluginProperty cur : deserialized) {
Assert.assertEquals(cur, properties.get(i++));
}
final PaymentAttemptModelDao retrievedAttempt1 = paymentDao.getPaymentAttempt(attempt.getId(), internalCallContext);
assertEquals(retrievedAttempt1.getTransactionExternalKey(), transactionExternalKey);
assertEquals(retrievedAttempt1.getTransactionType(), transactionType);
assertEquals(retrievedAttempt1.getStateName(), stateName);
assertEquals(retrievedAttempt1.getPluginName(), pluginName);
final List<PaymentAttemptModelDao> retrievedAttempts = paymentDao.getPaymentAttemptByTransactionExternalKey(transactionExternalKey, internalCallContext);
assertEquals(retrievedAttempts.size(), 1);
assertEquals(retrievedAttempts.get(0).getTransactionExternalKey(), transactionExternalKey);
assertEquals(retrievedAttempts.get(0).getTransactionType(), transactionType);
assertEquals(retrievedAttempts.get(0).getStateName(), stateName);
assertEquals(retrievedAttempts.get(0).getPluginName(), pluginName);
}
Aggregations