Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow\Constant;
   4  
   5  use PhpOffice\PhpSpreadsheet\Calculation\Exception;
   6  use PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow\CashFlowValidations;
   7  use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants;
   8  use PhpOffice\PhpSpreadsheet\Calculation\Functions;
   9  
  10  class Periodic
  11  {
  12      /**
  13       * FV.
  14       *
  15       * Returns the Future Value of a cash flow with constant payments and interest rate (annuities).
  16       *
  17       * Excel Function:
  18       *        FV(rate,nper,pmt[,pv[,type]])
  19       *
  20       * @param mixed $rate The interest rate per period
  21       * @param mixed $numberOfPeriods Total number of payment periods in an annuity as an integer
  22       * @param mixed $payment The payment made each period: it cannot change over the
  23       *                            life of the annuity. Typically, pmt contains principal
  24       *                            and interest but no other fees or taxes.
  25       * @param mixed $presentValue present Value, or the lump-sum amount that a series of
  26       *                            future payments is worth right now
  27       * @param mixed $type A number 0 or 1 and indicates when payments are due:
  28       *                      0 or omitted    At the end of the period.
  29       *                      1               At the beginning of the period.
  30       *
  31       * @return float|string
  32       */
  33      public static function futureValue(
  34          $rate,
  35          $numberOfPeriods,
  36          $payment = 0.0,
  37          $presentValue = 0.0,
  38          $type = FinancialConstants::PAYMENT_END_OF_PERIOD
  39      ) {
  40          $rate = Functions::flattenSingleValue($rate);
  41          $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
  42          $payment = ($payment === null) ? 0.0 : Functions::flattenSingleValue($payment);
  43          $presentValue = ($presentValue === null) ? 0.0 : Functions::flattenSingleValue($presentValue);
  44          $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
  45  
  46          try {
  47              $rate = CashFlowValidations::validateRate($rate);
  48              $numberOfPeriods = CashFlowValidations::validateInt($numberOfPeriods);
  49              $payment = CashFlowValidations::validateFloat($payment);
  50              $presentValue = CashFlowValidations::validatePresentValue($presentValue);
  51              $type = CashFlowValidations::validatePeriodType($type);
  52          } catch (Exception $e) {
  53              return $e->getMessage();
  54          }
  55  
  56          return self::calculateFutureValue($rate, $numberOfPeriods, $payment, $presentValue, $type);
  57      }
  58  
  59      /**
  60       * PV.
  61       *
  62       * Returns the Present Value of a cash flow with constant payments and interest rate (annuities).
  63       *
  64       * @param mixed $rate Interest rate per period
  65       * @param mixed $numberOfPeriods Number of periods as an integer
  66       * @param mixed $payment Periodic payment (annuity)
  67       * @param mixed $futureValue Future Value
  68       * @param mixed $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  69       *
  70       * @return float|string Result, or a string containing an error
  71       */
  72      public static function presentValue(
  73          $rate,
  74          $numberOfPeriods,
  75          $payment = 0.0,
  76          $futureValue = 0.0,
  77          $type = FinancialConstants::PAYMENT_END_OF_PERIOD
  78      ) {
  79          $rate = Functions::flattenSingleValue($rate);
  80          $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
  81          $payment = ($payment === null) ? 0.0 : Functions::flattenSingleValue($payment);
  82          $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
  83          $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
  84  
  85          try {
  86              $rate = CashFlowValidations::validateRate($rate);
  87              $numberOfPeriods = CashFlowValidations::validateInt($numberOfPeriods);
  88              $payment = CashFlowValidations::validateFloat($payment);
  89              $futureValue = CashFlowValidations::validateFutureValue($futureValue);
  90              $type = CashFlowValidations::validatePeriodType($type);
  91          } catch (Exception $e) {
  92              return $e->getMessage();
  93          }
  94  
  95          // Validate parameters
  96          if ($numberOfPeriods < 0) {
  97              return Functions::NAN();
  98          }
  99  
 100          return self::calculatePresentValue($rate, $numberOfPeriods, $payment, $futureValue, $type);
 101      }
 102  
 103      /**
 104       * NPER.
 105       *
 106       * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate.
 107       *
 108       * @param mixed $rate Interest rate per period
 109       * @param mixed $payment Periodic payment (annuity)
 110       * @param mixed $presentValue Present Value
 111       * @param mixed $futureValue Future Value
 112       * @param mixed $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
 113       *
 114       * @return float|string Result, or a string containing an error
 115       */
 116      public static function periods(
 117          $rate,
 118          $payment,
 119          $presentValue,
 120          $futureValue = 0.0,
 121          $type = FinancialConstants::PAYMENT_END_OF_PERIOD
 122      ) {
 123          $rate = Functions::flattenSingleValue($rate);
 124          $payment = Functions::flattenSingleValue($payment);
 125          $presentValue = Functions::flattenSingleValue($presentValue);
 126          $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
 127          $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
 128  
 129          try {
 130              $rate = CashFlowValidations::validateRate($rate);
 131              $payment = CashFlowValidations::validateFloat($payment);
 132              $presentValue = CashFlowValidations::validatePresentValue($presentValue);
 133              $futureValue = CashFlowValidations::validateFutureValue($futureValue);
 134              $type = CashFlowValidations::validatePeriodType($type);
 135          } catch (Exception $e) {
 136              return $e->getMessage();
 137          }
 138  
 139          // Validate parameters
 140          if ($payment == 0.0) {
 141              return Functions::NAN();
 142          }
 143  
 144          return self::calculatePeriods($rate, $payment, $presentValue, $futureValue, $type);
 145      }
 146  
 147      private static function calculateFutureValue(
 148          float $rate,
 149          int $numberOfPeriods,
 150          float $payment,
 151          float $presentValue,
 152          int $type
 153      ): float {
 154          if ($rate !== null && $rate != 0) {
 155              return -$presentValue *
 156                  (1 + $rate) ** $numberOfPeriods - $payment * (1 + $rate * $type) * ((1 + $rate) ** $numberOfPeriods - 1)
 157                      / $rate;
 158          }
 159  
 160          return -$presentValue - $payment * $numberOfPeriods;
 161      }
 162  
 163      private static function calculatePresentValue(
 164          float $rate,
 165          int $numberOfPeriods,
 166          float $payment,
 167          float $futureValue,
 168          int $type
 169      ): float {
 170          if ($rate != 0.0) {
 171              return (-$payment * (1 + $rate * $type)
 172                      * (((1 + $rate) ** $numberOfPeriods - 1) / $rate) - $futureValue) / (1 + $rate) ** $numberOfPeriods;
 173          }
 174  
 175          return -$futureValue - $payment * $numberOfPeriods;
 176      }
 177  
 178      /**
 179       * @return float|string
 180       */
 181      private static function calculatePeriods(
 182          float $rate,
 183          float $payment,
 184          float $presentValue,
 185          float $futureValue,
 186          int $type
 187      ) {
 188          if ($rate != 0.0) {
 189              if ($presentValue == 0.0) {
 190                  return Functions::NAN();
 191              }
 192  
 193              return log(($payment * (1 + $rate * $type) / $rate - $futureValue) /
 194                      ($presentValue + $payment * (1 + $rate * $type) / $rate)) / log(1 + $rate);
 195          }
 196  
 197          return (-$presentValue - $futureValue) / $payment;
 198      }
 199  }