docs: @Override
      public InvoiceWithMetadata generateInvoice(final ImmutableAccountData account,
                                                 @Nullable final BillingEventSet events,
                                                 @Nullable final Iterable<Invoice> existingInvoices,
                                                 @Nullable final UUID targetInvoiceId,
                                                 final LocalDate targetDate,
                                                 final Currency targetCurrency,
                                                 final InternalCallContext context) throws InvoiceApiException {
          if ((events == null) || (events.size() == 0) || events.isAccountAutoInvoiceOff()) {
              return new InvoiceWithMetadata(null, ImmutableSet.of(), ImmutableMap.<UUID, SubscriptionFutureNotificationDates>of());
          }
  
          validateTargetDate(targetDate, context);
          final LocalDate adjustedTargetDate = adjustTargetDate(existingInvoices, targetDate);
  
          final LocalDate invoiceDate = context.toLocalDate(context.getCreatedDate());
          final InvoiceStatus invoiceStatus = events.isAccountAutoInvoiceDraft() ? InvoiceStatus.DRAFT : InvoiceStatus.COMMITTED;
          final DefaultInvoice invoice = targetInvoiceId != null ?
                                         new DefaultInvoice(targetInvoiceId, account.getId(), null, invoiceDate, adjustedTargetDate, targetCurrency, false, invoiceStatus) :
                                         new DefaultInvoice(account.getId(), invoiceDate, adjustedTargetDate, targetCurrency, invoiceStatus);
  
          final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates = new HashMap<UUID, SubscriptionFutureNotificationDates>();
  
          final InvoiceGeneratorResult fixedAndRecurringItems = recurringInvoiceItemGenerator.generateItems(account, invoice.getId(), events, existingInvoices, adjustedTargetDate, targetCurrency, perSubscriptionFutureNotificationDates, context);
          invoice.addInvoiceItems(fixedAndRecurringItems.getItems());
  
          final InvoiceGeneratorResult usageItemsWithTrackingIds = usageInvoiceItemGenerator.generateItems(account, invoice.getId(), events, existingInvoices, adjustedTargetDate, targetCurrency, perSubscriptionFutureNotificationDates, context);
          invoice.addInvoiceItems(usageItemsWithTrackingIds.getItems());
  
          if (targetInvoiceId != null) {
              final Invoice originalInvoice = Iterables.tryFind(existingInvoices, new Predicate<Invoice>() {
                  @Override
                  public boolean apply(final Invoice input) {
                      return input.getId().equals(targetInvoiceId);
                  }
              }).orNull();
              Preconditions.checkNotNull(originalInvoice, "Expecting to find an existing invoice matching the targetInvoiceId");
              invoice.addInvoiceItems(originalInvoice.getInvoiceItems());
          }
  
          return new InvoiceWithMetadata(invoice.getInvoiceItems().isEmpty() ? null : invoice,
                                         usageItemsWithTrackingIds.getTrackingIds(),
                                         perSubscriptionFutureNotificationDates);
      }