docs: private List<InvoiceItem> processRecurringEvent(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent, @Nullable final BillingEvent nextEvent,
                                                      final LocalDate targetDate, final Currency currency,
                                                      final InvoiceItemGeneratorLogger invoiceItemGeneratorLogger, final BillingMode billingMode,
                                                      final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
                                                      final InternalCallContext internalCallContext) throws InvoiceApiException {
  
          try {
              final List<InvoiceItem> items = new ArrayList<InvoiceItem>();
  
              // For FIXEDTERM phases we need to stop when the specified duration has been reached
              final LocalDate maxEndDate = thisEvent.getPlanPhase().getPhaseType() == PhaseType.FIXEDTERM ?
                                           thisEvent.getPlanPhase().getDuration().addToLocalDate(internalCallContext.toLocalDate(thisEvent.getEffectiveDate())) :
                                           null;
  
              // Handle recurring items
              final BillingPeriod billingPeriod = thisEvent.getBillingPeriod();
              if (billingPeriod != BillingPeriod.NO_BILLING_PERIOD) {
                  final LocalDate startDate = internalCallContext.toLocalDate(thisEvent.getEffectiveDate());
  
                  if (!startDate.isAfter(targetDate)) {
                      final LocalDate endDate = (nextEvent == null) ? null : internalCallContext.toLocalDate(nextEvent.getEffectiveDate());
  
                      final int billCycleDayLocal = thisEvent.getBillCycleDayLocal();
  
                      final RecurringInvoiceItemDataWithNextBillingCycleDate itemDataWithNextBillingCycleDate;
                      try {
                          itemDataWithNextBillingCycleDate = generateInvoiceItemData(startDate, endDate, targetDate, billCycleDayLocal, billingPeriod, billingMode);
                      } catch (final InvalidDateSequenceException e) {
                          throw new InvoiceApiException(ErrorCode.INVOICE_INVALID_DATE_SEQUENCE, startDate, endDate, targetDate);
                      }
                      for (final RecurringInvoiceItemData itemDatum : itemDataWithNextBillingCycleDate.getItemData()) {
  
                          // Stop if there a maxEndDate and we have reached it
                          if (maxEndDate != null && maxEndDate.compareTo(itemDatum.getEndDate()) < 0) {
                              break;
                          }
  
                          final BigDecimal rate = thisEvent.getRecurringPrice(internalCallContext.toUTCDateTime(itemDatum.getStartDate()));
                          if (rate != null) {
                              final BigDecimal amount = KillBillMoney.of(itemDatum.getNumberOfCycles().multiply(rate), currency);
                              final RecurringInvoiceItem recurringItem = new RecurringInvoiceItem(invoiceId,
                                                                                                  accountId,
                                                                                                  thisEvent.getBundleId(),
                                                                                                  thisEvent.getSubscriptionId(),
                                                                                                  thisEvent.getPlan().getProduct().getName(),
                                                                                                  thisEvent.getPlan().getName(),
                                                                                                  thisEvent.getPlanPhase().getName(),
                                                                                                  itemDatum.getStartDate(),
                                                                                                  itemDatum.getEndDate(),
                                                                                                  amount, rate, currency);
                              items.add(recurringItem);
                          }
                      }
                      updatePerSubscriptionNextNotificationDate(thisEvent.getSubscriptionId(), itemDataWithNextBillingCycleDate.getNextBillingCycleDate(), items, billingMode,
                                                                perSubscriptionFutureNotificationDate);
                  }
              }
  
              // For debugging purposes
              invoiceItemGeneratorLogger.append(thisEvent, items);
  
              return items;
          } catch (final CatalogApiException e) {
              throw new InvoiceApiException(e);
          }
      }