use of org.killbill.billing.catalog.api.Currency in project killbill by killbill.
the class TestInvoiceDispatcher method testWithParking.
@Test(groups = "slow")
public void testWithParking() throws InvoiceApiException, AccountApiException, CatalogApiException, SubscriptionBaseApiException, TagDefinitionApiException {
final UUID accountId = account.getId();
final BillingEventSet events = new MockBillingEventSet();
final Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
final PlanPhase planPhase = MockPlanPhase.create1USDMonthlyEvergreen();
final DateTime effectiveDate = clock.getUTCNow().minusDays(1);
final Currency currency = Currency.USD;
final BigDecimal fixedPrice = null;
events.add(invoiceUtil.createMockBillingEvent(account, subscription, effectiveDate, plan, planPhase, fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1, BillingMode.IN_ADVANCE, "", 1L, SubscriptionBaseTransitionType.CREATE));
Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<DryRunArguments>any(), Mockito.<LocalDate>any(), Mockito.<InternalCallContext>any())).thenReturn(events);
final LocalDate target = internalCallContext.toLocalDate(effectiveDate);
final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao, internalCallContextFactory, invoicePluginDispatcher, locker, bus, notificationQueueService, invoiceConfig, clock, invoiceOptimizer, parkedAccountsManager);
// Verify initial tags state for account
Assert.assertTrue(tagUserApi.getTagsForAccount(accountId, true, callContext).isEmpty());
// Create chaos on disk
final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(accountId, target, target, currency, false);
final InvoiceItemModelDao invoiceItemModelDao1 = new InvoiceItemModelDao(clock.getUTCNow(), InvoiceItemType.RECURRING, invoiceModelDao.getId(), accountId, subscription.getBundleId(), subscription.getId(), "Bad data", null, plan.getName(), planPhase.getName(), null, null, effectiveDate.toLocalDate(), effectiveDate.plusMonths(1).toLocalDate(), BigDecimal.TEN, BigDecimal.ONE, currency, null);
final InvoiceItemModelDao invoiceItemModelDao2 = new InvoiceItemModelDao(clock.getUTCNow(), InvoiceItemType.RECURRING, invoiceModelDao.getId(), accountId, subscription.getBundleId(), subscription.getId(), "Bad data", null, plan.getName(), planPhase.getName(), null, null, effectiveDate.plusDays(1).toLocalDate(), effectiveDate.plusMonths(1).toLocalDate(), BigDecimal.TEN, BigDecimal.ONE, currency, null);
invoiceModelDao.addInvoiceItem(invoiceItemModelDao1);
invoiceModelDao.addInvoiceItem(invoiceItemModelDao2);
invoiceDao.createInvoices(ImmutableList.<InvoiceModelDao>of(invoiceModelDao), events, ImmutableSet.of(), context);
try {
dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), false, context);
Assert.fail();
} catch (final InvoiceApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.UNEXPECTED_ERROR.getCode());
Assert.assertTrue(e.getCause().getMessage().startsWith("Double billing detected"));
}
// Dry-run: no side effect on disk
Assert.assertEquals(invoiceDao.getInvoicesByAccount(false, context).size(), 1);
Assert.assertTrue(tagUserApi.getTagsForAccount(accountId, true, callContext).isEmpty());
try {
dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, null, false, context);
Assert.fail();
} catch (final InvoiceApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.UNEXPECTED_ERROR.getCode());
Assert.assertTrue(e.getCause().getMessage().startsWith("Double billing detected"));
}
Assert.assertEquals(invoiceDao.getInvoicesByAccount(false, context).size(), 1);
// No dry-run: account is parked
final List<Tag> tags = tagUserApi.getTagsForAccount(accountId, false, callContext);
Assert.assertEquals(tags.size(), 1);
Assert.assertEquals(tags.get(0).getTagDefinitionId(), SystemTags.PARK_TAG_DEFINITION_ID);
// isApiCall=false
final Invoice nullInvoice1 = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, null, false, context);
Assert.assertNull(nullInvoice1);
// No dry-run and isApiCall=true
try {
dispatcher.processAccount(true, accountId, target, null, false, context);
Assert.fail();
} catch (final InvoiceApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.UNEXPECTED_ERROR.getCode());
Assert.assertTrue(e.getCause().getMessage().startsWith("Double billing detected"));
}
// Idempotency
Assert.assertEquals(invoiceDao.getInvoicesByAccount(false, context).size(), 1);
Assert.assertEquals(tagUserApi.getTagsForAccount(accountId, false, callContext), tags);
// Fix state
dbi.withHandle(new HandleCallback<Void>() {
@Override
public Void withHandle(final Handle handle) throws Exception {
handle.execute("delete from invoices");
handle.execute("delete from invoice_items");
return null;
}
});
// Dry-run and isApiCall=false: still parked
final Invoice nullInvoice2 = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), false, context);
Assert.assertNull(nullInvoice2);
// Dry-run and isApiCall=true: call goes through
final Invoice invoice1 = dispatcher.processAccount(true, accountId, target, new DryRunFutureDateArguments(), false, context);
Assert.assertNotNull(invoice1);
Assert.assertEquals(invoiceDao.getInvoicesByAccount(false, context).size(), 0);
// Dry-run: still parked
Assert.assertEquals(tagUserApi.getTagsForAccount(accountId, false, callContext).size(), 1);
// No dry-run and isApiCall=true: call goes through
final Invoice invoice2 = dispatcher.processAccount(true, accountId, target, null, false, context);
Assert.assertNotNull(invoice2);
Assert.assertEquals(invoiceDao.getInvoicesByAccount(false, context).size(), 1);
// No dry-run: now unparked
Assert.assertEquals(tagUserApi.getTagsForAccount(accountId, false, callContext).size(), 0);
Assert.assertEquals(tagUserApi.getTagsForAccount(accountId, true, callContext).size(), 1);
}
use of org.killbill.billing.catalog.api.Currency in project killbill by killbill.
the class TestInvoiceDao method testInvoiceForFreeTrial.
@Test(groups = "slow")
public void testInvoiceForFreeTrial() throws InvoiceApiException, CatalogApiException {
final Currency currency = Currency.USD;
final DefaultPrice price = new DefaultPrice(BigDecimal.ZERO, Currency.USD);
final MockInternationalPrice fixedPrice = new MockInternationalPrice(price);
final MockPlanPhase phase = new MockPlanPhase(null, fixedPrice);
final MockPlan plan = new MockPlan(phase);
final SubscriptionBase subscription = getZombieSubscription();
final DateTime effectiveDate = invoiceUtil.buildDate(2011, 1, 1).toDateTimeAtStartOfDay();
final BillingEvent event = invoiceUtil.createMockBillingEvent(null, subscription, effectiveDate, plan, phase, fixedPrice.getPrice(currency), null, currency, BillingPeriod.MONTHLY, 15, BillingMode.IN_ADVANCE, "testEvent", 1L, SubscriptionBaseTransitionType.CREATE);
final BillingEventSet events = new MockBillingEventSet();
events.add(event);
final LocalDate targetDate = invoiceUtil.buildDate(2011, 1, 15);
final InvoiceWithMetadata invoiceWithMetadata = generator.generateInvoice(account, events, new AccountInvoices(), null, targetDate, Currency.USD, null, context);
final Invoice invoice = invoiceWithMetadata.getInvoice();
assertNotNull(invoice);
}
use of org.killbill.billing.catalog.api.Currency in project killbill by killbill.
the class TestDefaultPaymentDao method testPaymentCRUDForAccount.
private void testPaymentCRUDForAccount(final int runNb) throws Exception {
final Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
final UUID accountId = account.getId();
final PaymentModelDao specifiedFirstPaymentModelDao = generatePaymentModelDao(accountId);
final PaymentTransactionModelDao specifiedFirstPaymentTransactionModelDao = generatePaymentTransactionModelDao(specifiedFirstPaymentModelDao.getId());
// Create and verify the payment and transaction
final PaymentModelDao firstPaymentModelDao = paymentDao.insertPaymentWithFirstTransaction(specifiedFirstPaymentModelDao, specifiedFirstPaymentTransactionModelDao, internalCallContext).getPaymentModelDao();
verifyPayment(firstPaymentModelDao, specifiedFirstPaymentModelDao);
verifyPaymentAndTransactions(internalCallContext, specifiedFirstPaymentModelDao, specifiedFirstPaymentTransactionModelDao);
// Create a second transaction for the same payment
final PaymentTransactionModelDao specifiedSecondPaymentTransactionModelDao = generatePaymentTransactionModelDao(specifiedFirstPaymentModelDao.getId());
final PaymentTransactionModelDao secondTransactionModelDao = paymentDao.updatePaymentWithNewTransaction(specifiedFirstPaymentTransactionModelDao.getPaymentId(), specifiedSecondPaymentTransactionModelDao, internalCallContext);
verifyPaymentTransaction(secondTransactionModelDao, specifiedSecondPaymentTransactionModelDao);
verifyPaymentAndTransactions(internalCallContext, specifiedFirstPaymentModelDao, specifiedFirstPaymentTransactionModelDao, specifiedSecondPaymentTransactionModelDao);
// Update the latest transaction
final BigDecimal processedAmount = new BigDecimal("902341.23232");
final Currency processedCurrency = Currency.USD;
final String gatewayErrorCode = UUID.randomUUID().toString().substring(0, 5);
final String gatewayErrorMsg = UUID.randomUUID().toString();
paymentDao.updatePaymentAndTransactionOnCompletion(accountId, specifiedSecondPaymentTransactionModelDao.getAttemptId(), specifiedSecondPaymentTransactionModelDao.getPaymentId(), specifiedFirstPaymentTransactionModelDao.getTransactionType(), PaymentStateMachineHelper.STATE_NAMES[0], PaymentStateMachineHelper.STATE_NAMES[0], specifiedSecondPaymentTransactionModelDao.getId(), TransactionStatus.PAYMENT_FAILURE, processedAmount, processedCurrency, gatewayErrorCode, gatewayErrorMsg, true, internalCallContext);
final PaymentTransactionModelDao updatedSecondPaymentTransactionModelDao = paymentDao.getPaymentTransaction(specifiedSecondPaymentTransactionModelDao.getId(), internalCallContext);
Assert.assertEquals(updatedSecondPaymentTransactionModelDao.getTransactionStatus(), TransactionStatus.PAYMENT_FAILURE);
Assert.assertEquals(updatedSecondPaymentTransactionModelDao.getGatewayErrorMsg(), gatewayErrorMsg);
Assert.assertEquals(updatedSecondPaymentTransactionModelDao.getGatewayErrorMsg(), gatewayErrorMsg);
// Create multiple payments for that account
for (int i = 0; i < 3; i++) {
final PaymentModelDao paymentModelDao = generatePaymentModelDao(accountId);
final PaymentTransactionModelDao paymentTransactionModelDao = generatePaymentTransactionModelDao(paymentModelDao.getId());
final PaymentModelDao insertedPaymentModelDao = paymentDao.insertPaymentWithFirstTransaction(paymentModelDao, paymentTransactionModelDao, internalCallContext).getPaymentModelDao();
verifyPayment(insertedPaymentModelDao, paymentModelDao);
// Verify search APIs
Assert.assertEquals(ImmutableList.<PaymentModelDao>copyOf(paymentDao.searchPayments(paymentModelDao.getPaymentMethodId().toString(), 0L, 100L, internalCallContext).iterator()).size(), 1);
Assert.assertEquals(ImmutableList.<PaymentModelDao>copyOf(paymentDao.searchPayments(paymentModelDao.getExternalKey(), 0L, 100L, internalCallContext).iterator()).size(), 1);
}
Assert.assertEquals(paymentDao.getPaymentsForAccount(specifiedFirstPaymentModelDao.getAccountId(), internalCallContext).size(), 4);
// Verify search APIs
Assert.assertEquals(ImmutableList.<PaymentModelDao>copyOf(paymentDao.searchPayments(accountId.toString(), 0L, 100L, internalCallContext).iterator()).size(), 4);
Assert.assertEquals(ImmutableList.<PaymentModelDao>copyOf(paymentDao.searchPayments("_ERRORED", 0L, 100L, internalCallContext).iterator()).size(), runNb);
}
use of org.killbill.billing.catalog.api.Currency in project killbill by killbill.
the class MockPaymentProviderPlugin method getPaymentTransactionInfoPluginResult.
private PaymentTransactionInfoPlugin getPaymentTransactionInfoPluginResult(final UUID kbPaymentId, final UUID kbTransactionId, final TransactionType type, @Nullable final BigDecimal amount, @Nullable final Currency currency, final Iterable<PluginProperty> pluginProperties) throws PaymentPluginApiException {
if (makePluginWaitSomeMilliseconds.get() > 0) {
try {
Thread.sleep(makePluginWaitSomeMilliseconds.get());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new PaymentPluginApiException("An Interruption occurred while the Thread was sleeping.", e);
}
}
if (makeNextPaymentFailWithException.getAndSet(false)) {
throw new PaymentPluginApiException("", "test error");
}
final PluginProperty paymentPluginStatusOverride = Iterables.tryFind(pluginProperties, new Predicate<PluginProperty>() {
@Override
public boolean apply(final PluginProperty input) {
return PLUGIN_PROPERTY_PAYMENT_PLUGIN_STATUS_OVERRIDE.equals(input.getKey());
}
}).orNull();
final PaymentPluginStatus status;
if (paymentPluginStatusOverride != null && paymentPluginStatusOverride.getValue() != null) {
status = PaymentPluginStatus.valueOf(paymentPluginStatusOverride.getValue().toString());
} else if (makeAllPaymentsFailWithError.get() || makeNextPaymentFailWithError.getAndSet(false)) {
status = PaymentPluginStatus.ERROR;
} else if (makeNextPaymentFailWithCancellation.getAndSet(false)) {
status = PaymentPluginStatus.CANCELED;
} else if (makeNextPaymentPending.getAndSet(false)) {
status = PaymentPluginStatus.PENDING;
} else if (makeNextPaymentUnknown.getAndSet(false)) {
status = PaymentPluginStatus.UNDEFINED;
} else {
status = PaymentPluginStatus.PROCESSED;
}
final String errorCode = status == PaymentPluginStatus.PROCESSED ? "" : GATEWAY_ERROR_CODE;
final String error = status == PaymentPluginStatus.PROCESSED ? "" : GATEWAY_ERROR;
InternalPaymentInfo info = payments.get(kbPaymentId.toString());
if (info == null) {
info = new InternalPaymentInfo();
payments.put(kbPaymentId.toString(), info);
}
final BigDecimal overrideNextProcessedAmount = this.overrideNextProcessedAmount.getAndSet(null);
final BigDecimal processedAmount = overrideNextProcessedAmount != null ? overrideNextProcessedAmount : amount;
Currency processedCurrency = overrideNextProcessedCurrency.getAndSet(null);
if (processedCurrency == null) {
processedCurrency = currency;
}
final PaymentTransactionInfoPlugin result = new DefaultNoOpPaymentInfoPlugin(kbPaymentId, kbTransactionId, type, processedAmount, processedCurrency, clock.getUTCNow(), clock.getUTCNow(), status, errorCode, error, null, null, ImmutableList.<PluginProperty>copyOf(pluginProperties));
List<PaymentTransactionInfoPlugin> existingTransactions = paymentTransactions.get(kbPaymentId.toString());
if (existingTransactions == null) {
existingTransactions = new ArrayList<PaymentTransactionInfoPlugin>();
paymentTransactions.put(kbPaymentId.toString(), existingTransactions);
}
final Iterator<PaymentTransactionInfoPlugin> iterator = existingTransactions.iterator();
while (iterator.hasNext()) {
final PaymentTransactionInfoPlugin existingTransaction = iterator.next();
if (existingTransaction.getKbTransactionPaymentId().equals(kbTransactionId)) {
info.addAmount(type, existingTransaction.getAmount().negate());
iterator.remove();
}
}
existingTransactions.add(result);
info.addAmount(type, result.getAmount());
return result;
}
use of org.killbill.billing.catalog.api.Currency in project killbill by killbill.
the class ControlPluginRunner method executePluginPriorCalls.
public PriorPaymentControlResult executePluginPriorCalls(final Account account, final UUID paymentMethodId, final String pluginName, final UUID paymentAttemptId, final UUID paymentId, final String paymentExternalKey, final UUID paymentTransactionId, final String paymentTransactionExternalKey, final PaymentApiType paymentApiType, final TransactionType transactionType, final HPPType hppType, final BigDecimal amount, final Currency currency, final BigDecimal processedAmount, final Currency processedCurrency, final boolean isApiPayment, final List<String> paymentControlPluginNames, final Iterable<PluginProperty> pluginProperties, final CallContext callContext) throws PaymentControlApiException {
// Return as soon as the first plugin aborts, or the last result for the last plugin
PriorPaymentControlResult prevResult = new DefaultPriorPaymentControlResult(false, amount, currency, paymentMethodId, null, pluginProperties);
// Those values are adjusted prior each call with the result of what previous call to plugin returned
UUID inputPaymentMethodId = paymentMethodId;
String inputPaymentMethodName = pluginName;
BigDecimal inputAmount = amount;
Currency inputCurrency = currency;
Iterable<PluginProperty> inputPluginProperties = pluginProperties;
final UUID accountId = account != null ? account.getId() : null;
for (final String controlPluginName : paymentControlPluginNames) {
final PaymentControlContext inputPaymentControlContext = new DefaultPaymentControlContext(accountId, inputPaymentMethodId, controlPluginName, paymentAttemptId, paymentId, paymentExternalKey, paymentTransactionId, paymentTransactionExternalKey, paymentApiType, transactionType, hppType, inputAmount, inputCurrency, processedAmount, processedCurrency, isApiPayment, callContext);
final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(controlPluginName);
if (plugin == null) {
// First call to plugin, we log warn, if plugin is not registered
log.warn("Skipping unknown payment control plugin {} when fetching results", controlPluginName);
continue;
}
log.debug("Calling priorCall of plugin {}", controlPluginName);
prevResult = plugin.priorCall(inputPaymentControlContext, inputPluginProperties);
log.debug("Successful executed priorCall of plugin {}", controlPluginName);
if (prevResult == null) {
// Nothing returned by the plugin
continue;
}
if (prevResult.getAdjustedPaymentMethodId() != null) {
// unless the property isAllowedToOverwritePaymentMethodId was explicitly configured to allow this
if (!paymentConfig.isAllowedToOverwritePaymentMethodId() && paymentMethodId != null) {
throw new PaymentControlApiException(String.format("Not allowed to overwrite paymentMethodId '%s' for payment '%s'", paymentMethodId, paymentId));
}
inputPaymentMethodId = prevResult.getAdjustedPaymentMethodId();
}
if (prevResult.getAdjustedPluginName() != null) {
inputPaymentMethodName = prevResult.getAdjustedPluginName();
}
if (prevResult.getAdjustedAmount() != null) {
inputAmount = prevResult.getAdjustedAmount();
}
if (prevResult.getAdjustedCurrency() != null) {
inputCurrency = prevResult.getAdjustedCurrency();
}
if (prevResult.getAdjustedPluginProperties() != null) {
inputPluginProperties = prevResult.getAdjustedPluginProperties();
}
if (prevResult.isAborted()) {
throw new PaymentControlApiAbortException(controlPluginName);
}
}
// Rebuild latest result to include inputPluginProperties
prevResult = new DefaultPriorPaymentControlResult(prevResult != null && prevResult.isAborted(), inputPaymentMethodId, inputPaymentMethodName, inputAmount, inputCurrency, inputPluginProperties);
return prevResult;
}
Aggregations