403Webshell
Server IP : 89.108.64.180  /  Your IP : 216.73.217.92
Web Server : Apache/2.4.41 (Ubuntu)
System : Linux 89-108-64-180.cloudvps.regruhosting.ru 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
User : www-root ( 1010)
PHP Version : 8.0.30
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /var/www/www-root/data/www/poseidon-gagra.ru/wp-content/plugins/awebooking/inc/Support/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/www-root/data/www/poseidon-gagra.ru/wp-content/plugins/awebooking/inc/Support//Decimal.php
<?php

namespace AweBooking\Support;

/**
 * This class adapted from pimcore/pimcore distributed under GPLv3 license.
 *
 * @see https://github.com/pimcore/pimcore/blob/v5.0.2/pimcore/lib/Pimcore/Bundle/EcommerceFrameworkBundle/Type/Decimal.php
 */
class Decimal {
	/* Constants */
	const INTEGER_NUMBER_REGEXP = '/^([+\-]?)\d+$/';
	const DECIMAL_NUMBER_REGEXP = '/^([+\-]?)(\d+)\.(\d+)$/';

	/**
	 * The amount.
	 *
	 * @var int
	 */
	protected $amount;

	/**
	 * The scale (precision after comma).
	 *
	 * Actual amount will be amount divided by 10^scale.
	 *
	 * @var int
	 */
	protected $scale;

	/**
	 * The default scale.
	 *
	 * @var int
	 */
	protected static $default_scale = 4;

	/**
	 * Builds a value from an integer.
	 *
	 * The integer amount here must be the final value with
	 * conversion factor already applied.
	 *
	 * @param int $amount The integer amount.
	 * @param int $scale  The scale.
	 */
	protected function __construct( $amount, $scale ) {
		if ( false === filter_var( $amount, FILTER_VALIDATE_INT ) ) {
			trigger_error( 'The amount should be an integer value', E_USER_WARNING ); // @codingStandardsIgnoreLine
		}

		$this->amount = (int) $amount;
		$this->scale  = (int) $scale;
	}

	/**
	 * Sets the global default scale to be used.
	 *
	 * @param int $scale The scale.
	 */
	public static function set_default_scale( $scale ) {
		$scale = (int) $scale;

		static::validate_scale( $scale );

		static::$default_scale = $scale;
	}

	/**
	 * Validates scale not being negative.
	 *
	 * @param  int $scale The scale.
	 * @throws \DomainException
	 */
	protected static function validate_scale( $scale ) {
		if ( $scale < 0 ) {
			throw new \DomainException( 'Scale must be greater or equal than 0' );
		}
	}

	/**
	 * Asserts that an integer value didn't become something else
	 * (after some arithmetic operation).
	 *
	 * @param int $amount The test amount value.
	 *
	 * @throws \OverflowException  If integer overflow occured.
	 * @throws \UnderflowException If integer underflow occured.
	 */
	protected static function validate_integer_bounds( $amount ) {
		if ( $amount > ( PHP_INT_MAX - 1 ) ) {
			throw new \OverflowException( 'The maximum allowed integer (PHP_INT_MAX) was reached' );
		}

		if ( $amount < ( ~PHP_INT_MAX + 1 ) ) {
			throw new \UnderflowException( 'The minimum allowed integer (PHP_INT_MAX) was reached' );
		}
	}

	/**
	 * Try round value to int value if needed.
	 *
	 * @param string|float|int $value        The input value.
	 * @param int|null         $rounding_mode See round() http://php.net/manual/en/function.round.php.
	 * @return int
	 */
	protected static function to_int_value( $value, $rounding_mode = null ) {
		if ( ! is_int( $value ) ) {
			$value = round( $value, 0, is_null( $rounding_mode ) ? PHP_ROUND_HALF_EVEN : $rounding_mode );
			$value = (int) $value;
		}

		return $value;
	}

	/**
	 * Creates a decimal value.
	 *
	 * If an integer is passed, its value will be used without any conversions. Any
	 * other value (float, string) will be converted to int with the given scale. If a Decimal is
	 * passed, it will be converted to the given scale if necessary. Example:
	 *
	 * ```
	 * input: 15
	 * scale: 4
	 * amount: 15 * 10^4 = 150000, scale: 4
	 * ```
	 *
	 * @param  int|float|string|self $amount        The amount.
	 * @param  int|null              $scale         Optional, custom scale.
	 * @param  int|null              $rounding_mode The rounding mode.
	 * @return static
	 *
	 * @throws \InvalidArgumentException
	 */
	public static function create( $amount, $scale = null, $rounding_mode = null ) {
		if ( is_string( $amount ) ) {
			return static::from_string( $amount, $scale, $rounding_mode );
		}

		if ( is_numeric( $amount ) ) {
			return static::from_numeric( $amount, $scale, $rounding_mode );
		}

		if ( $amount instanceof self ) {
			return static::from_decimal( $amount, $scale );
		}

		throw new \InvalidArgumentException( 'Expected (int, float, string, self), but received ' . ( is_object( $amount ) ? get_class( $amount ) : gettype( $amount ) ) );
	}

	/**
	 * Creates a value from a raw integer input.
	 *
	 * No value conversions will be done.
	 *
	 * @param  int      $amount The amount.
	 * @param  int|null $scale  Optional, the scale.
	 * @return static
	 */
	public static function from_raw_value( $amount, $scale = null ) {
		$scale = ! is_null( $scale ) ? $scale : static::$default_scale;

		static::validate_scale( $scale );

		return new static( $amount, $scale );
	}

	/**
	 * Creates a value from a string input.
	 *
	 * If possible, the integer will be created with string operations
	 * (e.g. adding zeroes), otherwise it will fall back to from_numeric().
	 *
	 * @param  string|float|int $amount        The amount value.
	 * @param  int|null         $scale         Optional, custom default scale.
	 * @param  int|null         $rounding_mode Rounding mode.
	 *
	 * @return static
	 */
	public static function from_string( $amount, $scale = null, $rounding_mode = null ) {
		$scale = ! is_null( $scale ) ? $scale : static::$default_scale;

		static::validate_scale( $scale );

		$result = null;

		if ( 1 === preg_match( static::INTEGER_NUMBER_REGEXP, $amount, $captures ) ) {
			// No decimals -> add zeroes until we have the expected amount
			// e.g. 1234, scale 4 = 12340000.
			$result = (int) ( $amount . str_repeat( '0', $scale ) );
		} elseif ( 1 === preg_match( static::DECIMAL_NUMBER_REGEXP, $amount, $captures ) ) {
			// Decimal part is lower/equals than scale - add zeroes as needed and concat it with the integer part
			// e.g. 123.45 at scale 4 -> 123 (integer) . 4500 (zero padded decimal part) => 1234500.
			if ( strlen( $captures[3] ) <= $scale ) {
				$fractional_part = str_pad( $captures[3], $scale, '0', STR_PAD_RIGHT );
				$result          = (int) ( $captures[1] . $captures[2] . $fractional_part );
			}
		}

		if ( null !== $result ) {
			static::validate_integer_bounds( $result );

			return new static( $result, $scale );
		}

		// Default to numeric - this will also apply rounding as we
		// fall back to floats here.
		return static::from_numeric( $amount, $scale, $rounding_mode );
	}

	/**
	 * Creates a value from a numeric input.
	 *
	 * The given amount will be converted to int with the given scale.
	 * Please note that this implicitely rounds the amount to the
	 * next integer, so precision depends on the given scale.
	 *
	 * @param  string|float|int $amount        The amount value.
	 * @param  int|null         $scale         Optional, custom default scale.
	 * @param  int|null         $rounding_mode Rounding mode.
	 * @return static
	 *
	 * @throws \InvalidArgumentException
	 */
	public static function from_numeric( $amount, $scale = null, $rounding_mode = null ) {
		if ( ! is_numeric( $amount ) ) {
			throw new \InvalidArgumentException( 'The amount must be a numeric value' );
		}

		$scale = ! is_null( $scale ) ? $scale : static::$default_scale;
		static::validate_scale( $scale );

		$result = $amount * ( 10 ** $scale );
		static::validate_integer_bounds( $result );

		$result = static::to_int_value( $result, $rounding_mode );

		return new static( $result, $scale );
	}

	/**
	 * Creates a value from another price value.
	 *
	 * If the scale matches the given scale, the input value will be returned,
	 * otherwise the scale will be converted and a new object will be returned.
	 * Please note that this will potentially imply precision loss when converting to a lower scale.
	 *
	 * @param  Decimal  $amount The Decimal acount.
	 * @param  int|null $scale  The scale value.
	 * @return static
	 */
	public static function from_decimal( Decimal $amount, $scale = null ) {
		$scale = ! is_null( $scale ) ? $scale : static::$default_scale;

		static::validate_scale( $scale );

		// Object is identical - creating a new object is not necessary.
		if ( $amount->get_scale() === $scale ) {
			return $amount;
		}

		return $amount->with_scale( $scale );
	}

	/**
	 * Create a zero value object.
	 *
	 * @param  int|null $scale Optional, custom default scale.
	 * @return static
	 */
	public static function zero( $scale = null ) {
		return static::from_raw_value( 0, $scale );
	}

	/**
	 * Returns the used scale factor.
	 *
	 * @return int
	 */
	public function get_scale() {
		return $this->scale;
	}

	/**
	 * Returns the internal representation value.
	 *
	 * WARNING: use this with caution as the represented value depends on the scale!
	 *
	 * @return int
	 */
	public function as_raw_value() {
		return $this->amount;
	}

	/**
	 * Returns a numeric representation.
	 *
	 * @return int|float
	 */
	public function as_numeric() {
		return $this->amount / ( 10 ** $this->scale );
	}

	/**
	 * Returns a string representation.
	 *
	 * Digits default to the scale. If $digits is passed, the string will be
	 * truncated to the given amount of digits without any rounding.
	 *
	 * @param  int|null $digits The number of digits.
	 * @return string
	 */
	public function as_string( $digits = null ) {
		$signum = $this->amount < 0 ? '-' : '';

		$string = (string) abs( $this->amount );
		$amount = null;

		if ( 0 === $this->scale ) {
			$amount = $string;
		} elseif ( strlen( $string ) <= $this->scale ) {
			$fractional_part = str_pad( $string, $this->scale, '0', STR_PAD_LEFT );
			$amount          = '0.' . $fractional_part;
		} else {
			$fractional_offset = strlen( $string ) - $this->scale;
			$integer_part      = substr( $string, 0, $fractional_offset );
			$fractional_part   = substr( $string, $fractional_offset );
			$amount            = $integer_part . '.' . $fractional_part;
		}

		if ( null !== $digits ) {
			$amount = $this->truncate_decimal_string( $amount, $digits );
		}

		return $signum . $amount;
	}

	/**
	 * Converts decimal string to the given amount of digits.
	 *
	 * No rounding is done here - additional digits are just truncated.
	 *
	 * @param  string $amount The string amount.
	 * @param  int    $digits The number of digits.
	 * @return string
	 */
	protected function truncate_decimal_string( $amount, $digits ) {
		$integer_part    = $amount;
		$fractional_part = '0';

		if ( false !== strpos( $amount, '.' ) ) {
			list( $integer_part, $fractional_part ) = explode( '.', $amount );
		}

		if ( 0 === $digits ) {
			return $integer_part;
		}

		if ( strlen( $fractional_part ) > $digits ) {
			$fractional_part = substr( $fractional_part, 0, $digits );
		} elseif ( strlen( $fractional_part ) < $digits ) {
			$fractional_part = str_pad( $fractional_part, $digits, '0', STR_PAD_RIGHT );
		}

		return $integer_part . '.' . $fractional_part;
	}

	/**
	 * Builds a value with the given scale.
	 *
	 * @param  int      $scale         The scale value.
	 * @param  int|null $rounding_mode The rounding mode.
	 * @return static
	 */
	public function with_scale( $scale, $rounding_mode = null ) {
		static::validate_scale( $scale );

		// No need to create a new object as output would be identical.
		if ( $scale === $this->scale ) {
			return $this;
		}

		$diff = $scale - $this->scale;

		$result = $this->amount * ( 10 ** $diff );
		static::validate_integer_bounds( $result );

		$result = static::to_int_value( $result, $rounding_mode );

		return new static( $result, $scale );
	}

	/**
	 * Checks if value is equal to other value.
	 *
	 * @param  Decimal $other Other Decimal value.
	 * @return bool
	 */
	public function equals( Decimal $other ) {
		return $other->scale === $this->scale && $other->amount === $this->amount;
	}

	/**
	 * Checks if value is not equal to other value.
	 *
	 * @param  Decimal $other Other Decimal value.
	 * @return bool
	 */
	public function not_equals( Decimal $other ) {
		return ! $this->equals( $other );
	}

	/**
	 * Compares a value to another one.
	 *
	 * @param  Decimal $other Other Decimal value.
	 * @return int (0, 1, -1)
	 */
	public function compare( Decimal $other ) {
		$this->assert_same_scale( $other, 'Can\'t compare values with different scales. Please convert both values to the same scale.' );

		if ( $this->amount === $other->amount ) {
			return 0;
		}

		return ( $this->amount > $other->amount ) ? 1 : -1;
	}

	/**
	 * Compares this > other.
	 *
	 * @param  Decimal $other Other Decimal value.
	 * @return bool
	 */
	public function greater_than( Decimal $other ) {
		return $this->compare( $other ) === 1;
	}

	/**
	 * Compares this >= other.
	 *
	 * @param  Decimal $other Other Decimal value.
	 * @return bool
	 */
	public function greater_than_or_equal( Decimal $other ) {
		return $this->compare( $other ) >= 0;
	}

	/**
	 * Compares this < other.
	 *
	 * @param  Decimal $other Other Decimal value.
	 * @return bool
	 */
	public function less_than( Decimal $other ) {
		return $this->compare( $other ) === -1;
	}

	/**
	 * Compares this <= other.
	 *
	 * @param  Decimal $other Other Decimal value.
	 * @return bool
	 */
	public function less_than_or_equal( Decimal $other ) {
		return $this->compare( $other ) <= 0;
	}

	/**
	 * Checks if amount is zero.
	 *
	 * @return bool
	 */
	public function is_zero() {
		return 0 === $this->amount;
	}

	/**
	 * Checks if amount is positive. Not: zero is NOT handled as positive.
	 *
	 * @return bool
	 */
	public function is_positive() {
		return $this->amount > 0;
	}

	/**
	 * Checks if amount is negative.
	 *
	 * @return bool
	 */
	public function is_negative() {
		return $this->amount < 0;
	}

	/**
	 * Returns the absolute amount.
	 *
	 * @return static
	 */
	public function abs() {
		if ( $this->amount < 0 ) {
			return new static( (int) abs( $this->amount ), $this->scale );
		}

		return $this;
	}

	/**
	 * Adds another price amount.
	 *
	 * @param  Decimal|int|float|string $other Other value.
	 * @return static
	 */
	public function add( $other ) {
		if ( ! $other instanceof self ) {
			$other = static::from_numeric( $other, $this->scale );
		}

		$this->assert_same_scale( $other );

		$result = $this->amount + $other->amount;
		static::validate_integer_bounds( $result );

		return new static( $result, $this->scale );
	}

	/**
	 * Subtracts another price amount.
	 *
	 * @param  Decimal|int|float|string $other Other value.
	 * @return static
	 */
	public function subtract( $other ) {
		if ( ! $other instanceof self ) {
			$other = static::from_numeric( $other, $this->scale );
		}

		$this->assert_same_scale( $other );

		$result = $this->amount - $other->amount;
		static::validate_integer_bounds( $result );

		return new static( $result, $this->scale );
	}

	/**
	 * Subtracts another price amount.
	 *
	 * @param  Decimal|int|float|string $other Other value.
	 * @return static
	 */
	public function sub( $other ) {
		return $this->subtract( $other );
	}

	/**
	 * Multiplies by the given factor.
	 *
	 * This does NOT have to be a price amount, but can be
	 * a simple scalar factor (e.g. 2) as multiplying prices is rarely needed.
	 * However, if a Decimal is passed, its float representation will be used for calculations.
	 *
	 * @param  int|float|Decimal $other         The other value.
	 * @param  int|null          $rounding_mode The rounding mode.
	 * @return static
	 */
	public function multiply( $other, $rounding_mode = null ) {
		$operand = $this->get_scalar_operand( $other );

		$result = $this->amount * $operand;
		static::validate_integer_bounds( $result );

		$result = static::to_int_value( $result, $rounding_mode );

		return new static( $result, $this->scale );
	}

	/**
	 * Multiplies by the given factor.
	 *
	 * @param  int|float|Decimal $other         The other value.
	 * @param  int|null          $rounding_mode The rounding mode.
	 * @return static
	 */
	public function mul( $other, $rounding_mode = null ) {
		return $this->multiply( $other, $rounding_mode );
	}

	/**
	 * Divides by the given divisor.
	 *
	 * This does NOT have to be a price amount, but can be
	 * a simple scalar factor (e.g. 2) as dividing prices is rarely needed.
	 * However, if a Decimal is passed, its float representation will be used for calculations.
	 *
	 * @param  int|float|Decimal $other         The other value.
	 * @param  int|null          $rounding_mode The rounding mode.
	 * @return static
	 *
	 * @throws \LogicException
	 */
	public function divide( $other, $rounding_mode = null ) {
		$operand = $this->get_scalar_operand( $other );
		$epsilon = 10 ** ( - 1 * $this->scale );

		if ( abs( 0 - $operand ) < $epsilon ) {
			throw new \LogicException( 'Division by zero is not allowed' );
		}

		$result = $this->amount / $operand;
		static::validate_integer_bounds( $result );

		$result = static::to_int_value( $result, $rounding_mode );

		return new static( $result, $this->scale );
	}

	/**
	 * Divides by the given divisor.
	 *
	 * @param  int|float|Decimal $other         The other value.
	 * @param  int|null          $rounding_mode The rounding mode.
	 * @return static
	 *
	 * @throws \LogicException
	 */
	public function div( $other, $rounding_mode = null ) {
		return $this->divide( $other, $rounding_mode );
	}

	/**
	 * Returns the additive inverse of a value (e.g. 5 returns -5, -5 returns 5).
	 *
	 * @example Decimal::create(5)->to_additive_inverse() = -5
	 * @example Decimal::create(-5)->to_additive_inverse() = 5
	 *
	 * @return static
	 */
	public function to_additive_inverse() {
		return $this->mul( -1 );
	}

	/**
	 * Calculate a percentage amount.
	 *
	 * @example Decimal::create(100)->to_percentage(30) = 30
	 * @example Decimal::create(50)->to_percentage(50) = 25
	 *
	 * @param  int|float $percentage    The percentage value.
	 * @param  int|null  $rounding_mode The rounding mode.
	 * @return static
	 */
	public function to_percentage( $percentage, $rounding_mode = null ) {
		$percentage = $this->get_scalar_operand( $percentage );

		return $this->mul( $percentage / 100, $rounding_mode );
	}

	/**
	 * Calculate a discounted amount.
	 *
	 * @example Decimal::create(100)->discount(15) = 85
	 *
	 * @param  int|float $discount      The discount (percent) value.
	 * @param  int|null  $rounding_mode The rounding mode.
	 * @return static
	 */
	public function discount( $discount, $rounding_mode = null ) {
		$discount = $this->get_scalar_operand( $discount );

		return $this->sub(
			$this->to_percentage( $discount, $rounding_mode )
		);
	}

	/**
	 * Calculate a surcharge amount.
	 *
	 * @example Decimal::create(100)->surcharge(15) = 115
	 *
	 * @param  int|float $surcharge     The surcharge (percent) value.
	 * @param  int|null  $rounding_mode The rounding mode.
	 * @return static
	 */
	public function surcharge( $surcharge, $rounding_mode = null ) {
		$surcharge = $this->get_scalar_operand( $surcharge );

		return $this->add(
			$this->to_percentage( $surcharge, $rounding_mode )
		);
	}

	/**
	 * Get the relative percentage to another value.
	 *
	 * @example Decimal::create(100)->percentage_of(Decimal::create(50)) = 200
	 * @example Decimal::create(50)->percentage_of(Decimal::create(100)) = 50
	 *
	 * @param  Decimal $other Other Decimal value.
	 * @return int|float
	 */
	public function percentage_of( Decimal $other ) {
		$this->assert_same_scale( $other );

		if ( $this->equals( $other ) ) {
			return 100;
		}

		return ( $this->as_raw_value() * 100 ) / $other->as_raw_value();
	}

	/**
	 * Get the discount percentage starting from a discounted price
	 *
	 * @example Decimal::create(30)->discount_percentage_of(Decimal::create(100)) = 70
	 *
	 * @param  Decimal $other Other Decimal value.
	 * @return int|float
	 */
	public function discount_percentage_of( Decimal $other ) {
		$this->assert_same_scale( $other );

		if ( $this->equals( $other ) ) {
			return 0;
		}

		return 100 - $this->percentage_of( $other );
	}

	/**
	 * Transforms operand into a numeric value used for calculations.
	 *
	 * @param  int|float|Decimal $operand The operand.
	 * @return float
	 *
	 * @throws \InvalidArgumentException
	 */
	protected function get_scalar_operand( $operand ) {
		if ( is_numeric( $operand ) ) {
			return $operand;
		}

		if ( $operand instanceof static ) {
			return $operand->as_numeric();
		}

		throw new \InvalidArgumentException( sprintf(
			'Value "%s" with type "%s" is no valid operand',
			is_scalar( $operand ) ? $operand : (string) $operand,
			is_object( $operand ) ? get_class( $operand ) : gettype( $operand )
		));
	}

	/**
	 * Assert two Decimal has same scale.
	 *
	 * @param  Decimal     $other   Other Decimal.
	 * @param  string|null $message Custom exception message.
	 * @return void
	 *
	 * @throws \DomainException
	 */
	protected function assert_same_scale( Decimal $other, $message = null ) {
		if ( $other->scale !== $this->scale ) {
			$message = $message ?: 'Can\'t operate on amounts with different scales. Please convert both amounts to the same scale before proceeding.';
			throw new \DomainException( $message );
		}
	}

	/**
	 * Default string representation
	 *
	 * @return string
	 */
	public function __toString() {
		return $this->as_string();
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit