use of org.killbill.billing.util.callcontext.CallContext in project killbill by killbill.
the class InvoiceResource method createMigrationInvoice.
@TimedResource
@POST
@Path("/" + MIGRATION + "/{accountId:" + UUID_PATTERN + "}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Create a migration invoice", response = InvoiceJson.class)
@ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid account id or target datetime supplied") })
public Response createMigrationInvoice(final Iterable<InvoiceItemJson> items, @PathParam("accountId") final String accountId, @Nullable @QueryParam(QUERY_TARGET_DATE) final String targetDate, @HeaderParam(HDR_CREATED_BY) final String createdBy, @HeaderParam(HDR_REASON) final String reason, @HeaderParam(HDR_COMMENT) final String comment, @javax.ws.rs.core.Context final HttpServletRequest request, @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
final CallContext callContext = context.createContext(createdBy, reason, comment, request);
final Account account = accountUserApi.getAccountById(UUID.fromString(accountId), callContext);
final Iterable<InvoiceItem> sanitizedInvoiceItems = validateSanitizeAndTranformInputItems(account.getCurrency(), items);
final LocalDate resolvedTargetDate = toLocalDateDefaultToday(account, targetDate, callContext);
final UUID invoiceId = invoiceApi.createMigrationInvoice(UUID.fromString(accountId), resolvedTargetDate, sanitizedInvoiceItems, callContext);
return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", invoiceId, request);
}
use of org.killbill.billing.util.callcontext.CallContext in project killbill by killbill.
the class InvoiceResource method createFutureInvoice.
@TimedResource
@POST
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Trigger an invoice generation", response = InvoiceJson.class)
@ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid account id or target datetime supplied") })
public Response createFutureInvoice(@QueryParam(QUERY_ACCOUNT_ID) final String accountId, @QueryParam(QUERY_TARGET_DATE) final String targetDate, @HeaderParam(HDR_CREATED_BY) final String createdBy, @HeaderParam(HDR_REASON) final String reason, @HeaderParam(HDR_COMMENT) final String comment, @javax.ws.rs.core.Context final HttpServletRequest request, @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
final CallContext callContext = context.createContext(createdBy, reason, comment, request);
final LocalDate inputDate = toLocalDate(targetDate);
try {
final Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, null, callContext);
return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", generatedInvoice.getId(), request);
} catch (InvoiceApiException e) {
if (e.getCode() == ErrorCode.INVOICE_NOTHING_TO_DO.getCode()) {
return Response.status(Status.NOT_FOUND).build();
}
throw e;
}
}
use of org.killbill.billing.util.callcontext.CallContext in project killbill by killbill.
the class InvoiceResource method adjustInvoiceItem.
@TimedResource
@POST
@Path("/{invoiceId:" + UUID_PATTERN + "}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Adjust an invoice item")
@ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid account id, invoice id or invoice item id supplied"), @ApiResponse(code = 404, message = "Invoice not found") })
public Response adjustInvoiceItem(final InvoiceItemJson json, @PathParam("invoiceId") final String invoiceId, @QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString, @HeaderParam(HDR_CREATED_BY) final String createdBy, @HeaderParam(HDR_REASON) final String reason, @HeaderParam(HDR_COMMENT) final String comment, @javax.ws.rs.core.Context final HttpServletRequest request, @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
verifyNonNullOrEmpty(json, "InvoiceItemJson body should be specified");
verifyNonNullOrEmpty(json.getAccountId(), "InvoiceItemJson accountId needs to be set", json.getInvoiceItemId(), "InvoiceItemJson invoiceItemId needs to be set");
final CallContext callContext = context.createContext(createdBy, reason, comment, request);
final UUID accountId = UUID.fromString(json.getAccountId());
final LocalDate requestedDate = toLocalDateDefaultToday(accountId, requestedDateTimeString, callContext);
final InvoiceItem adjustmentItem;
if (json.getAmount() == null) {
adjustmentItem = invoiceApi.insertInvoiceItemAdjustment(accountId, UUID.fromString(invoiceId), UUID.fromString(json.getInvoiceItemId()), requestedDate, json.getDescription(), callContext);
} else {
adjustmentItem = invoiceApi.insertInvoiceItemAdjustment(accountId, UUID.fromString(invoiceId), UUID.fromString(json.getInvoiceItemId()), requestedDate, json.getAmount(), Currency.valueOf(json.getCurrency()), json.getDescription(), callContext);
}
return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", adjustmentItem.getInvoiceId(), request);
}
use of org.killbill.billing.util.callcontext.CallContext in project killbill by killbill.
the class InvoiceDispatcher method processAccountWithLockAndInputTargetDate.
private Invoice processAccountWithLockAndInputTargetDate(final UUID accountId, final LocalDate targetDate, final BillingEventSet billingEvents, final boolean isDryRun, final InternalCallContext context) throws InvoiceApiException {
try {
final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
final List<Invoice> invoices = billingEvents.isAccountAutoInvoiceOff() ? ImmutableList.<Invoice>of() : ImmutableList.<Invoice>copyOf(Collections2.transform(invoiceDao.getInvoicesByAccount(context), new Function<InvoiceModelDao, Invoice>() {
@Override
public Invoice apply(final InvoiceModelDao input) {
return new DefaultInvoice(input);
}
}));
final Currency targetCurrency = account.getCurrency();
final InvoiceWithMetadata invoiceWithMetadata = generator.generateInvoice(account, billingEvents, invoices, targetDate, targetCurrency, context);
final DefaultInvoice invoice = invoiceWithMetadata.getInvoice();
// Compute future notifications
final FutureAccountNotifications futureAccountNotifications = createNextFutureNotificationDate(invoiceWithMetadata, context);
//
if (invoice == null) {
if (isDryRun) {
log.info("Generated null dryRun invoice for accountId='{}', targetDate='{}'", accountId, targetDate);
} else {
log.info("Generated null invoice for accountId='{}', targetDate='{}'", accountId, targetDate);
final BusInternalEvent event = new DefaultNullInvoiceEvent(accountId, clock.getUTCToday(), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
commitInvoiceAndSetFutureNotifications(account, null, futureAccountNotifications, context);
postEvent(event);
}
return null;
}
// Generate missing credit (> 0 for generation and < 0 for use) prior we call the plugin
final InvoiceItem cbaItemPreInvoicePlugins = computeCBAOnExistingInvoice(invoice, context);
DefaultInvoice tmpInvoiceForInvoicePlugins = invoice;
if (cbaItemPreInvoicePlugins != null) {
tmpInvoiceForInvoicePlugins = (DefaultInvoice) tmpInvoiceForInvoicePlugins.clone();
tmpInvoiceForInvoicePlugins.addInvoiceItem(cbaItemPreInvoicePlugins);
}
//
// Ask external invoice plugins if additional items (tax, etc) shall be added to the invoice
//
final CallContext callContext = buildCallContext(context);
final List<InvoiceItem> additionalInvoiceItemsFromPlugins = invoicePluginDispatcher.getAdditionalInvoiceItems(tmpInvoiceForInvoicePlugins, isDryRun, callContext);
if (additionalInvoiceItemsFromPlugins.isEmpty()) {
// PERF: avoid re-computing the CBA if no change was made
if (cbaItemPreInvoicePlugins != null) {
invoice.addInvoiceItem(cbaItemPreInvoicePlugins);
}
} else {
invoice.addInvoiceItems(additionalInvoiceItemsFromPlugins);
// Use credit after we call the plugin (https://github.com/killbill/killbill/issues/637)
final InvoiceItem cbaItemPostInvoicePlugins = computeCBAOnExistingInvoice(invoice, context);
if (cbaItemPostInvoicePlugins != null) {
invoice.addInvoiceItem(cbaItemPostInvoicePlugins);
}
}
if (!isDryRun) {
// Compute whether this is a new invoice object (or just some adjustments on an existing invoice), and extract invoiceIds for later use
final Set<UUID> uniqueInvoiceIds = getUniqueInvoiceIds(invoice);
final boolean isRealInvoiceWithItems = uniqueInvoiceIds.remove(invoice.getId());
final Set<UUID> adjustedUniqueOtherInvoiceId = uniqueInvoiceIds;
logInvoiceWithItems(account, invoice, targetDate, adjustedUniqueOtherInvoiceId, isRealInvoiceWithItems);
// Transformation to Invoice -> InvoiceModelDao
final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
final List<InvoiceItemModelDao> invoiceItemModelDaos = transformToInvoiceModelDao(invoice.getInvoiceItems());
invoiceModelDao.addInvoiceItems(invoiceItemModelDaos);
// Commit invoice on disk
final boolean isThereAnyItemsLeft = commitInvoiceAndSetFutureNotifications(account, invoiceModelDao, futureAccountNotifications, context);
final boolean isRealInvoiceWithNonEmptyItems = isThereAnyItemsLeft ? isRealInvoiceWithItems : false;
setChargedThroughDates(invoice.getInvoiceItems(FixedPriceInvoiceItem.class), invoice.getInvoiceItems(RecurringInvoiceItem.class), context);
if (InvoiceStatus.COMMITTED.equals(invoice.getStatus())) {
notifyAccountIfEnabled(account, invoice, isRealInvoiceWithNonEmptyItems, context);
}
}
return invoice;
} catch (final AccountApiException e) {
log.error("Failed handling SubscriptionBase change.", e);
return null;
} catch (final SubscriptionBaseApiException e) {
log.error("Failed handling SubscriptionBase change.", e);
return null;
}
}
use of org.killbill.billing.util.callcontext.CallContext in project killbill by killbill.
the class OverdueStateApplicator method cancelSubscriptionsIfRequired.
private void cancelSubscriptionsIfRequired(final DateTime effectiveDate, final ImmutableAccountData account, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
if (nextOverdueState.getOverdueCancellationPolicy() == OverdueCancellationPolicy.NONE) {
return;
}
final CallContext callContext = internalCallContextFactory.createCallContext(context);
try {
final BillingActionPolicy actionPolicy;
switch(nextOverdueState.getOverdueCancellationPolicy()) {
case END_OF_TERM:
actionPolicy = BillingActionPolicy.END_OF_TERM;
break;
case IMMEDIATE:
actionPolicy = BillingActionPolicy.IMMEDIATE;
break;
default:
throw new IllegalStateException("Unexpected OverdueCancellationPolicy " + nextOverdueState.getOverdueCancellationPolicy());
}
final List<Entitlement> toBeCancelled = new LinkedList<Entitlement>();
computeEntitlementsToCancel(account, toBeCancelled, callContext);
try {
entitlementInternalApi.cancel(toBeCancelled, context.toLocalDate(effectiveDate), actionPolicy, ImmutableList.<PluginProperty>of(), context);
} catch (final EntitlementApiException e) {
throw new OverdueException(e);
}
} catch (final EntitlementApiException e) {
throw new OverdueException(e);
}
}
Aggregations