Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

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