Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
   4  
   5  use PhpOffice\PhpSpreadsheet\Calculation\Exception;
   6  use PhpOffice\PhpSpreadsheet\Calculation\Functions;
   7  use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
   8  
   9  class Depreciation
  10  {
  11      /**
  12       * DB.
  13       *
  14       * Returns the depreciation of an asset for a specified period using the
  15       * fixed-declining balance method.
  16       * This form of depreciation is used if you want to get a higher depreciation value
  17       * at the beginning of the depreciation (as opposed to linear depreciation). The
  18       * depreciation value is reduced with every depreciation period by the depreciation
  19       * already deducted from the initial cost.
  20       *
  21       * Excel Function:
  22       *        DB(cost,salvage,life,period[,month])
  23       *
  24       * @param mixed $cost Initial cost of the asset
  25       * @param mixed $salvage Value at the end of the depreciation.
  26       *                             (Sometimes called the salvage value of the asset)
  27       * @param mixed $life Number of periods over which the asset is depreciated.
  28       *                           (Sometimes called the useful life of the asset)
  29       * @param mixed $period The period for which you want to calculate the
  30       *                          depreciation. Period must use the same units as life.
  31       * @param mixed $month Number of months in the first year. If month is omitted,
  32       *                         it defaults to 12.
  33       *
  34       * @return float|string
  35       */
  36      public static function DB($cost, $salvage, $life, $period, $month = 12)
  37      {
  38          $cost = Functions::flattenSingleValue($cost);
  39          $salvage = Functions::flattenSingleValue($salvage);
  40          $life = Functions::flattenSingleValue($life);
  41          $period = Functions::flattenSingleValue($period);
  42          $month = Functions::flattenSingleValue($month);
  43  
  44          try {
  45              $cost = self::validateCost($cost);
  46              $salvage = self::validateSalvage($salvage);
  47              $life = self::validateLife($life);
  48              $period = self::validatePeriod($period);
  49              $month = self::validateMonth($month);
  50          } catch (Exception $e) {
  51              return $e->getMessage();
  52          }
  53  
  54          if ($cost === 0.0) {
  55              return 0.0;
  56          }
  57  
  58          //    Set Fixed Depreciation Rate
  59          $fixedDepreciationRate = 1 - ($salvage / $cost) ** (1 / $life);
  60          $fixedDepreciationRate = round($fixedDepreciationRate, 3);
  61  
  62          //    Loop through each period calculating the depreciation
  63          // TODO Handle period value between 0 and 1 (e.g. 0.5)
  64          $previousDepreciation = 0;
  65          $depreciation = 0;
  66          for ($per = 1; $per <= $period; ++$per) {
  67              if ($per == 1) {
  68                  $depreciation = $cost * $fixedDepreciationRate * $month / 12;
  69              } elseif ($per == ($life + 1)) {
  70                  $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate * (12 - $month) / 12;
  71              } else {
  72                  $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate;
  73              }
  74              $previousDepreciation += $depreciation;
  75          }
  76  
  77          return $depreciation;
  78      }
  79  
  80      /**
  81       * DDB.
  82       *
  83       * Returns the depreciation of an asset for a specified period using the
  84       * double-declining balance method or some other method you specify.
  85       *
  86       * Excel Function:
  87       *        DDB(cost,salvage,life,period[,factor])
  88       *
  89       * @param mixed $cost Initial cost of the asset
  90       * @param mixed $salvage Value at the end of the depreciation.
  91       *                                (Sometimes called the salvage value of the asset)
  92       * @param mixed $life Number of periods over which the asset is depreciated.
  93       *                                (Sometimes called the useful life of the asset)
  94       * @param mixed $period The period for which you want to calculate the
  95       *                                depreciation. Period must use the same units as life.
  96       * @param mixed $factor The rate at which the balance declines.
  97       *                                If factor is omitted, it is assumed to be 2 (the
  98       *                                double-declining balance method).
  99       *
 100       * @return float|string
 101       */
 102      public static function DDB($cost, $salvage, $life, $period, $factor = 2.0)
 103      {
 104          $cost = Functions::flattenSingleValue($cost);
 105          $salvage = Functions::flattenSingleValue($salvage);
 106          $life = Functions::flattenSingleValue($life);
 107          $period = Functions::flattenSingleValue($period);
 108          $factor = Functions::flattenSingleValue($factor);
 109  
 110          try {
 111              $cost = self::validateCost($cost);
 112              $salvage = self::validateSalvage($salvage);
 113              $life = self::validateLife($life);
 114              $period = self::validatePeriod($period);
 115              $factor = self::validateFactor($factor);
 116          } catch (Exception $e) {
 117              return $e->getMessage();
 118          }
 119  
 120          if ($period > $life) {
 121              return ExcelError::NAN();
 122          }
 123  
 124          // Loop through each period calculating the depreciation
 125          // TODO Handling for fractional $period values
 126          $previousDepreciation = 0;
 127          $depreciation = 0;
 128          for ($per = 1; $per <= $period; ++$per) {
 129              $depreciation = min(
 130                  ($cost - $previousDepreciation) * ($factor / $life),
 131                  ($cost - $salvage - $previousDepreciation)
 132              );
 133              $previousDepreciation += $depreciation;
 134          }
 135  
 136          return $depreciation;
 137      }
 138  
 139      /**
 140       * SLN.
 141       *
 142       * Returns the straight-line depreciation of an asset for one period
 143       *
 144       * @param mixed $cost Initial cost of the asset
 145       * @param mixed $salvage Value at the end of the depreciation
 146       * @param mixed $life Number of periods over which the asset is depreciated
 147       *
 148       * @return float|string Result, or a string containing an error
 149       */
 150      public static function SLN($cost, $salvage, $life)
 151      {
 152          $cost = Functions::flattenSingleValue($cost);
 153          $salvage = Functions::flattenSingleValue($salvage);
 154          $life = Functions::flattenSingleValue($life);
 155  
 156          try {
 157              $cost = self::validateCost($cost, true);
 158              $salvage = self::validateSalvage($salvage, true);
 159              $life = self::validateLife($life, true);
 160          } catch (Exception $e) {
 161              return $e->getMessage();
 162          }
 163  
 164          if ($life === 0.0) {
 165              return ExcelError::DIV0();
 166          }
 167  
 168          return ($cost - $salvage) / $life;
 169      }
 170  
 171      /**
 172       * SYD.
 173       *
 174       * Returns the sum-of-years' digits depreciation of an asset for a specified period.
 175       *
 176       * @param mixed $cost Initial cost of the asset
 177       * @param mixed $salvage Value at the end of the depreciation
 178       * @param mixed $life Number of periods over which the asset is depreciated
 179       * @param mixed $period Period
 180       *
 181       * @return float|string Result, or a string containing an error
 182       */
 183      public static function SYD($cost, $salvage, $life, $period)
 184      {
 185          $cost = Functions::flattenSingleValue($cost);
 186          $salvage = Functions::flattenSingleValue($salvage);
 187          $life = Functions::flattenSingleValue($life);
 188          $period = Functions::flattenSingleValue($period);
 189  
 190          try {
 191              $cost = self::validateCost($cost, true);
 192              $salvage = self::validateSalvage($salvage);
 193              $life = self::validateLife($life);
 194              $period = self::validatePeriod($period);
 195          } catch (Exception $e) {
 196              return $e->getMessage();
 197          }
 198  
 199          if ($period > $life) {
 200              return ExcelError::NAN();
 201          }
 202  
 203          $syd = (($cost - $salvage) * ($life - $period + 1) * 2) / ($life * ($life + 1));
 204  
 205          return $syd;
 206      }
 207  
 208      private static function validateCost($cost, bool $negativeValueAllowed = false): float
 209      {
 210          $cost = FinancialValidations::validateFloat($cost);
 211          if ($cost < 0.0 && $negativeValueAllowed === false) {
 212              throw new Exception(ExcelError::NAN());
 213          }
 214  
 215          return $cost;
 216      }
 217  
 218      private static function validateSalvage($salvage, bool $negativeValueAllowed = false): float
 219      {
 220          $salvage = FinancialValidations::validateFloat($salvage);
 221          if ($salvage < 0.0 && $negativeValueAllowed === false) {
 222              throw new Exception(ExcelError::NAN());
 223          }
 224  
 225          return $salvage;
 226      }
 227  
 228      private static function validateLife($life, bool $negativeValueAllowed = false): float
 229      {
 230          $life = FinancialValidations::validateFloat($life);
 231          if ($life < 0.0 && $negativeValueAllowed === false) {
 232              throw new Exception(ExcelError::NAN());
 233          }
 234  
 235          return $life;
 236      }
 237  
 238      private static function validatePeriod($period, bool $negativeValueAllowed = false): float
 239      {
 240          $period = FinancialValidations::validateFloat($period);
 241          if ($period <= 0.0 && $negativeValueAllowed === false) {
 242              throw new Exception(ExcelError::NAN());
 243          }
 244  
 245          return $period;
 246      }
 247  
 248      private static function validateMonth($month): int
 249      {
 250          $month = FinancialValidations::validateInt($month);
 251          if ($month < 1) {
 252              throw new Exception(ExcelError::NAN());
 253          }
 254  
 255          return $month;
 256      }
 257  
 258      private static function validateFactor($factor): float
 259      {
 260          $factor = FinancialValidations::validateFloat($factor);
 261          if ($factor <= 0.0) {
 262              throw new Exception(ExcelError::NAN());
 263          }
 264  
 265          return $factor;
 266      }
 267  }