protected function completeInvoiceLinesRecursive(array $invoice)
    {
        $lines = $invoice[Tag::Customer][Tag::Invoice][Tag::Line];

        if ($this->completor->shouldConvertCurrency($invoice)) {
            $lines = $this->convertToEuro($lines, $invoice[Tag::Customer][Tag::Invoice][Meta::CurrencyRate]);
        }
        // @todo: we could combine all completor phase methods of getting the
        //   correct vat rate:
        //     - possible vat rates
        //     - filter by range
        //     - filter by tax class = foreign vat (or not)
        //     - filter by lookup vat
        //   Why? addVatRateUsingLookupData() actually already does so, but will
        //   not work when we do have a lookup vat class but not a lookup vat
        //   rate.
        //   This would allow to combine VatRateSource_Calculated and
        //   VatRateSource_Completor.
        // correctCalculatedVatRates() only uses vatrate, meta-vatrate-min, and
        // meta-vatrate-max and may lead to more (required) data filled in, so
        // should be called before completeLineRequiredData().
        $lines = $this->correctCalculatedVatRates($lines);
        // addVatRateToLookupLines() only uses meta-vat-rate-lookup and may lead
        // to more (required) data filled in, so should be called before
        // completeLineRequiredData().
        $lines = $this->addVatRateUsingLookupData($lines);
        $lines = $this->completeLineRequiredData($lines);
        // Completing the required data may lead to new lines that contain
        // calculated VAT rates and thus can be corrected with
        // correctCalculatedVatRates(): call again.
        $lines = $this->correctCalculatedVatRates($lines);

        $invoice[Tag::Customer][Tag::Invoice][Tag::Line] = $lines;
        return $invoice;
    }