public I_C_Flatrate_Term extendTermManually(final TermAndOrder termAndOrder) {
    final TestConfig testConfig = helper.getConfig();

    final I_C_Flatrate_Term term = termAndOrder.term;

    helper
        .mkProcessHelper()
        .setProcessClass(C_Flatrate_Term_Extend.class)
        .setPO(term)
        .setParameter(I_C_Flatrate_Transition.COLUMNNAME_IsAutoCompleteNewTerm, "Y")
        .run();

    final GridWindowHelper termGridWindowHelper = helper.retrievTermGridWindowHelper(term);
    final I_C_Flatrate_Term termExtendedAndReloaded =
        termGridWindowHelper.getGridTabInterface(I_C_Flatrate_Term.class);
    assertThat(termExtendedAndReloaded.getAD_PInstance_EndOfTerm_ID(), greaterThan(0));
    assertThat(termExtendedAndReloaded.getC_FlatrateTerm_Next_ID(), greaterThan(0));
    termGridWindowHelper.assertFieldDisplayed(I_C_Flatrate_Term.COLUMNNAME_ExtendTerm, false);

    final boolean paramIsSimulation =
        testConfig.getCustomParamBool(FlatFeeScenario.PARAM_BOOL_IS_SIMULATION);

    final I_C_Flatrate_Term nextTerm = termExtendedAndReloaded.getC_FlatrateTerm_Next();
    // just some little guards
    assertThat(nextTerm.isSimulation(), is(paramIsSimulation));
    assertThat(nextTerm.getDocStatus(), equalTo(X_C_Flatrate_Term.DOCSTATUS_Completed));

    return nextTerm;
  }
  public void finishTerm(final TermAndOrder termAndOrder) {
    final TestConfig testConfig = helper.getConfig();

    final I_C_Flatrate_Term term = termAndOrder.term;
    final I_C_Order order = termAndOrder.order;
    final I_C_Flatrate_Conditions fc = term.getC_Flatrate_Conditions();

    final GridWindowHelper dataEntryHelper = helper.retrieveMainInvoicingEntry(fc, order);
    final I_C_Flatrate_DataEntry dataEntry =
        dataEntryHelper.getGridTabInterface(I_C_Flatrate_DataEntry.class);

    final boolean paramIsSimulation =
        testConfig.getCustomParamBool(FlatFeeScenario.PARAM_BOOL_IS_SIMULATION);

    if (!paramIsSimulation) {
      assertThat(
          FlatFeeScenario.PARAM_BD_EXP_ACTUAL_AMOUNT + " for " + dataEntry,
          dataEntry.getFlatrateAmt(),
          comparesEqualTo(testConfig.getCustomParamBD(FlatFeeScenario.PARAM_BD_EXP_ACTUAL_AMOUNT)));
      assertThat(
          FlatFeeScenario.PARAM_BD_EXP_ACTUAL_QTY_PER_UNIT + " for " + dataEntry,
          dataEntry.getActualQtyPerUnit(),
          comparesEqualTo(
              testConfig.getCustomParamBD(FlatFeeScenario.PARAM_BD_EXP_ACTUAL_QTY_PER_UNIT)));
      assertThat(
          FlatFeeScenario.PARAM_BD_EXP_ACTUAL_DIFF_PER_UNIT + " for " + dataEntry,
          dataEntry.getActualQtyDiffPerUOM(),
          comparesEqualTo(
              testConfig.getCustomParamBD(FlatFeeScenario.PARAM_BD_EXP_ACTUAL_DIFF_PER_UNIT)));

      assertThat(
          FlatFeeScenario.PARAM_BD_EXP_ACTUAL_DIFF_EFF_PERCENT + " for " + dataEntry,
          dataEntry.getActualQtyDiffPercentEff(),
          comparesEqualTo(
              testConfig.getCustomParamBD(FlatFeeScenario.PARAM_BD_EXP_ACTUAL_DIFF_EFF_PERCENT)));
      assertThat(
          FlatFeeScenario.PARAM_BD_EXP_ACTUAL_DIFF_PERCENT + " for " + dataEntry,
          dataEntry.getActualQtyDiffPercent(),
          comparesEqualTo(
              testConfig.getCustomParamBD(FlatFeeScenario.PARAM_BD_EXP_ACTUAL_DIFF_PERCENT)));
      assertThat(
          FlatFeeScenario.PARAM_BD_EXP_ACTUAL_CORR_AMOUNT + " for " + dataEntry,
          dataEntry.getFlatrateAmtCorr(),
          comparesEqualTo(
              testConfig.getCustomParamBD(FlatFeeScenario.PARAM_BD_EXP_ACTUAL_CORR_AMOUNT)));

      final I_C_Invoice_Candidate invoiceCand = dataEntry.getC_Invoice_Candidate();

      assertThat(invoiceCand.getM_Product_ID(), is(fc.getM_Product_Flatrate_ID()));

      if (fc.getM_Product_Actual_ID() == fc.getM_Product_Flatrate_ID()
          && !fc.isCorrectionAmtAtClosing()) {
        assertThat(dataEntry.getC_Invoice_Candidate_Corr_ID(), is(0));

        assertThat(
            invoiceCand.getNetAmtToInvoice(),
            comparesEqualTo(dataEntry.getFlatrateAmt().add(dataEntry.getFlatrateAmtCorr())));

        processCands(invoiceCandHelper, invoiceCand);

        assertThat(
            invoiceCand.getNetAmtInvoiced(),
            comparesEqualTo(dataEntry.getFlatrateAmt().add(dataEntry.getFlatrateAmtCorr())));
      } else {
        assertThat(invoiceCand.getNetAmtToInvoice(), comparesEqualTo(dataEntry.getFlatrateAmt()));

        if (testConfig.getCustomParamBool(FlatFeeScenario.PARAM_BOOL_IS_CORR_AFTER_CLOSING)) {
          assertThat(fc.isCorrectionAmtAtClosing(), is(true)); // just a little guard
          assertThat(
              dataEntry + " has wrong C_Invoice_Candidate_Corr_ID",
              dataEntry.getC_Invoice_Candidate_Corr_ID(),
              is(0));
          processCands(invoiceCandHelper, invoiceCand);
        } else {
          assertThat(fc.isCorrectionAmtAtClosing(), is(false)); // just a little guard
          assertThat(dataEntry.getC_Invoice_Candidate_Corr_ID(), greaterThan(0));
          final I_C_Invoice_Candidate invoiceCandCorr = dataEntry.getC_Invoice_Candidate_Corr();

          assertThat(invoiceCandCorr.getM_Product_ID(), is(fc.getM_Product_Actual_ID()));
          assertThat(
              invoiceCandCorr.getNetAmtToInvoice(),
              comparesEqualTo(dataEntry.getFlatrateAmtCorr()));

          processCands(invoiceCandHelper, invoiceCand, invoiceCandCorr);

          assertThat(
              invoiceCandCorr.getNetAmtInvoiced(), comparesEqualTo(dataEntry.getFlatrateAmtCorr()));
        }

        assertThat(invoiceCand.getNetAmtInvoiced(), comparesEqualTo(dataEntry.getFlatrateAmt()));
      }
    }

    // now complete all dataEntries with a Qty_reported of 1 each
    final List<I_C_Invoice_Candidate> allCandidates =
        helper.completeAllInvoicingEntries(term, BigDecimal.ONE);
    if (!paramIsSimulation) {
      assertThat(allCandidates.size(), greaterThan(0));
    }
    processCands(
        invoiceCandHelper, allCandidates.toArray(new I_C_Invoice_Candidate[allCandidates.size()]));

    if (!term.isClosingWithCorrectionSum()) {
      // we are done
      return;
    }

    final MPeriod closingPeriod =
        MPeriod.findByCalendar(
            driver.getCtx(),
            term.getEndDate(),
            fc.getC_Flatrate_Transition().getC_Calendar_Contract_ID(),
            driver.getTrxName());

    helper
        .mkProcessHelper()
        .setProcessClass(C_Flatrate_Term_Prepare_Closing.class)
        .setPO(term)
        .setParameter(I_C_Period.COLUMNNAME_C_Period_ID, closingPeriod.getC_Period_ID())
        .run();

    final GridWindowHelper entryGridWindowHelper = helper.retrieveMainCorrectionEntry(fc, term);
    final I_C_Flatrate_DataEntry correctionEntry =
        entryGridWindowHelper.getGridTabInterface(I_C_Flatrate_DataEntry.class);

    // expecting <PARAM_TRANSITION_TERM_DURATION> times 1 plus <PARAM_BD_UNITS_REPORTED>
    assertThat(
        correctionEntry + " has wrong Qty_Planned",
        correctionEntry.getQty_Planned(),
        comparesEqualTo(
            new BigDecimal(
                    testConfig.getCustomParamInt(ContractsHelper.PARAM_TRANSITION_TERM_DURATION))
                .add(testConfig.getCustomParamBD(PARAM_BD_UNITS_REPORTED))));

    final BigDecimal correctionQty =
        testConfig.getCustomParamBD(PARAM_BD_UNITS_REPORTED).add(new BigDecimal("2"));
    correctionEntry.setQty_Reported(correctionQty);

    helper.completeEntry(entryGridWindowHelper, X_C_Flatrate_DataEntry.DOCSTATUS_Completed);
    invoiceCandHelper.runProcess_UpdateInvoiceCands();

    assertThat(
        correctionEntry + " wrong FlatrateAmtPerUOM",
        correctionEntry.getFlatrateAmtPerUOM(),
        comparesEqualTo(testConfig.getCustomParamBD(PARAM_BD_PRICE_PER_UNIT_CLOSING)));
    assertThat(
        correctionEntry + " wrong FlatrateAmt",
        correctionEntry.getFlatrateAmt(),
        comparesEqualTo(
            correctionQty
                .subtract(correctionEntry.getQty_Planned())
                .multiply(correctionEntry.getFlatrateAmtPerUOM())));

    if (testConfig.getCustomParamBool(PARAM_BOOL_IS_SIMULATION)) {
      assertThat(correctionEntry.getC_Invoice_Candidate_ID(), is(0));
      assertThat(correctionEntry.getC_Invoice_Candidate_Corr_ID(), is(0));

      if (testConfig.getCustomParamBool(FlatFeeScenario.PARAM_BOOL_IS_CORR_AFTER_CLOSING)) {
        assertThat(
            correctionEntry + " has wrong ActualQty",
            correctionEntry.getActualQty(),
            comparesEqualTo(testConfig.getCustomParamBD(PARAM_BD_ACTUAL_QTY)));
        assertThat(
            correctionEntry + " has wrong FlatrateAmtCorr.signum()",
            correctionEntry.getFlatrateAmtCorr().signum(),
            not(is(0)));
      }
    } else {
      assertThat(correctionEntry.getC_Invoice_Candidate_ID(), greaterThan(0));
      final I_C_Invoice_Candidate correctionEntryCand = correctionEntry.getC_Invoice_Candidate();

      assertThat(
          correctionEntryCand + " wrong M_Product_ID",
          correctionEntryCand.getM_Product_ID(),
          is(fc.getM_Product_Correction_ID()));
      assertThat(
          correctionEntryCand + " wrong NetAmtToInvoice",
          correctionEntryCand.getNetAmtToInvoice(),
          comparesEqualTo(correctionEntry.getFlatrateAmt()));

      if (testConfig.getCustomParamBool(FlatFeeScenario.PARAM_BOOL_IS_CORR_AFTER_CLOSING)) {
        assertThat(
            correctionEntry + " has wrong ActualQty",
            correctionEntry.getActualQty(),
            comparesEqualTo(testConfig.getCustomParamBD(PARAM_BD_ACTUAL_QTY)));

        // note: the actual numbers are checked in a unit test
        assertThat(
            correctionEntry + " has wrong FlatrateAmtCorr().signum()",
            correctionEntry.getFlatrateAmtCorr().signum(),
            greaterThan(0));
        assertThat(correctionEntry.getC_Invoice_Candidate_Corr_ID(), greaterThan(0));

        final I_C_Invoice_Candidate correctionEntryCorrCand =
            correctionEntry.getC_Invoice_Candidate_Corr();
        assertThat(correctionEntryCorrCand.getM_Product_ID(), is(fc.getM_Product_Actual_ID()));
        assertThat(
            correctionEntryCorrCand.getNetAmtToInvoice(),
            comparesEqualTo(correctionEntry.getFlatrateAmtCorr()));
      } else {
        assertThat(correctionEntry.getFlatrateAmtCorr().signum(), equalTo(0));
        assertThat(correctionEntry.getC_Invoice_Candidate_Corr_ID(), equalTo(0));
      }
    }
  }