protected function resolveOutstandingDate(SaleInterface $sale)
    {
        if (!$sale instanceof InvoiceSubjectInterface) {
            return null;
        }
        if (!$sale instanceof ShipmentSubjectInterface) {
            return null;
        }

        if (null === $term = $sale->getPaymentTerm()) {
            return null;
        }

        if (!$this->saleHasOutstandingPayments($sale)) {
            return null;
        }

        $from = null;
        switch ($term->getTrigger()) {
            case PaymentTermTriggers::TRIGGER_SHIPPED:
                $from = $sale->getShippedAt();
                break;

            case PaymentTermTriggers::TRIGGER_FULLY_SHIPPED:
                if ($sale->getShipmentState() === ShipmentStates::STATE_COMPLETED) {
                    $from = $sale->getShippedAt(true);
                }
                break;

            case PaymentTermTriggers::TRIGGER_INVOICED:
                $from = $sale->getInvoicedAt();
                break;

            case PaymentTermTriggers::TRIGGER_FULLY_INVOICED:
                if ($sale->getInvoiceState() === InvoiceStates::STATE_COMPLETED) {
                    $from = $sale->getInvoicedAt(true);
                }
                break;
        }

        if (null === $from) {
            return null;
        }

        // Calculate outstanding date
        $date = clone $from;
        $date->setTime(23, 59, 59);
        $date->modify(sprintf('+%s days', $term->getDays()));
        if ($term->getEndOfMonth()) {
            $date->modify('last day of this month');
        }

        return $date;
    }