Created
October 25, 2017 09:21
-
-
Save unglud/3215dd0e5f77ecad135048fd56533e66 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Core\App\Service\Money; | |
use Money\Currencies\ISOCurrencies; | |
use Money\Formatter\DecimalMoneyFormatter; | |
use Money\Parser\DecimalMoneyParser; | |
class Money | |
{ | |
private $entity; | |
private $money; | |
private $override = [ | |
'getAmount', | |
'setAmount', | |
'getAmountNet', | |
'setAmountNet', | |
'getCommissionFee', | |
'getCommissionFeeNet', | |
'getTransactionFee', | |
'getTransactionFeeNet', | |
'getManual', | |
'getManualNet', | |
'getValue', | |
]; | |
/** | |
* Money constructor. | |
* @param int $amount | |
* @param \Money\Money|null $money | |
*/ | |
public function __construct($amount = 0, \Money\Money $money = null) | |
{ | |
if ($money !== null) { | |
$this->money = $money; | |
} else { | |
$this->money = $this->parseFloat($amount); | |
} | |
} | |
/** | |
* Convert any entity object to be able return money object instead floats | |
* @param EntityInterface $entity | |
* @return Money | |
*/ | |
public static function createFromEntity(EntityInterface $entity) | |
{ | |
$money = new self(); | |
$money->setEntity($entity); | |
return $money; | |
} | |
/** | |
* @param $name | |
* @param $arguments | |
* @return bool|mixed | |
* @throws \Exception | |
*/ | |
public function __call($name, $arguments) | |
{ | |
if ($this->entity === null) { | |
throw new \Exception( | |
"You must create Money object from entity (Money::createFromEntity) to use method $name"); | |
} | |
if (current($arguments) instanceof Money) { | |
/** @var Money[] $arguments */ | |
$arguments[0] = $arguments[0]->toString(); | |
} | |
if ($name === 'getAmountNet' && $this->entity instanceof Booking) { | |
return $this->getNet(); | |
} | |
if (!method_exists($this->entity, $name)) { | |
$class = get_class($this->entity); | |
throw new \Exception( | |
"Method $name doesn't exist in class $class"); | |
} | |
$result = call_user_func_array([$this->entity, $name], $arguments); | |
// if it setter | |
if (is_object($result) && get_class($result) === get_class($this->entity)) { | |
return $this; | |
} | |
if ($this->isOverride($name)) { | |
$result = new self($result); | |
} | |
return $result; | |
} | |
/** | |
* @return string | |
*/ | |
public function __toString() | |
{ | |
return $this->toString(true); | |
} | |
/** | |
* @param $addend | |
* @return Money | |
*/ | |
public function add($addend) | |
{ | |
/** @var Money $addend */ | |
return new self(0, $this->money->add($addend->getMoneyObject())); | |
} | |
/** | |
* @param $subtrahend | |
* @return Money | |
*/ | |
public function subtract($subtrahend) | |
{ | |
/** @var Money $subtrahend */ | |
return new self(0, $this->money->subtract($subtrahend->getMoneyObject())); | |
} | |
/** | |
* @return bool | |
*/ | |
public function isNegative() | |
{ | |
return $this->money->isNegative(); | |
} | |
/** | |
* @return bool | |
*/ | |
public function isZero() | |
{ | |
return $this->money->isZero(); | |
} | |
/** | |
* @return mixed | |
*/ | |
public function getEntity() | |
{ | |
return $this->entity; | |
} | |
/** | |
* @param bool $print | |
* @return string | |
*/ | |
public function toString($print = false) | |
{ | |
$currencies = new ISOCurrencies(); | |
$moneyFormatter = new DecimalMoneyFormatter($currencies); | |
$formatted = $moneyFormatter->format($this->money); | |
if ($print) { | |
return number_format((float)$formatted, 2, ',', '.'); | |
} | |
return $formatted; | |
} | |
/** | |
* @return Money | |
*/ | |
public function absolute() | |
{ | |
return new self(0, $this->money->absolute()); | |
} | |
/** | |
* @return Money | |
*/ | |
public function negative() | |
{ | |
return new self(0, $this->money->negative()); | |
} | |
/** | |
* @return int | |
*/ | |
private function toInt() | |
{ | |
return (int)$this->toString(); | |
} | |
/** | |
* @param EntityInterface $entity | |
*/ | |
private function setEntity(EntityInterface $entity) | |
{ | |
$this->entity = $entity; | |
} | |
/** | |
* @param $float | |
* @return \Money\Money | |
*/ | |
private function parseFloat($float) | |
{ | |
$currencies = new ISOCurrencies(); | |
$moneyParser = new DecimalMoneyParser($currencies); | |
$formattedFloat = sprintf("%f", $float); | |
return $moneyParser->parse($formattedFloat, 'EUR'); | |
} | |
/** | |
* @return \Money\Money | |
*/ | |
public function getMoneyObject() | |
{ | |
return $this->money; | |
} | |
/** | |
* @param $name | |
* @return bool | |
*/ | |
private function isOverride($name) | |
{ | |
return in_array($name, $this->override); | |
} | |
/** | |
* @param int $tax | |
* @return Money | |
*/ | |
public function getNet($tax = 0) | |
{ | |
$money = $this->calculateTax($tax); | |
return $money; | |
} | |
/** | |
* @return Money | |
*/ | |
public function getTax() | |
{ | |
$subtract = $this->getAmount()->subtract($this->getNet()); | |
return $subtract; | |
} | |
/** | |
* Allocate percentage | |
* | |
* @param int|float|string $percentage | |
* @return Money | |
*/ | |
public function getPercent($percentage) | |
{ | |
$base = new self(100); | |
$right = new self($percentage); | |
$left = $base->subtract($right); | |
// allocation put reminder of dividing to left side, if we split 3 to 50%, we will get 2 and 1 | |
// for percentages we do not need this, 'cuz reminder happen if percent is >= 50 | |
list($reminder, $cut) = $this->money->allocate([$left->toFloat(), $right->toFloat()]); | |
return new self(0, $cut); | |
} | |
/** | |
* @param array $ratios | |
* @return \Money\Money[] | |
*/ | |
public function allocate(array $ratios) | |
{ | |
return $this->money->allocate($ratios); | |
} | |
/** | |
* @param Money $divisor | |
* @return static | |
*/ | |
public function divide($divisor) | |
{ | |
return new self(0, $this->money->divide($divisor->toInt())); | |
} | |
/** | |
* @param Money $multiplier | |
* @return static | |
*/ | |
public function multiply($multiplier) | |
{ | |
return new self(0, $this->money->multiply($multiplier->toInt())); | |
} | |
/** | |
* @param int $tax | |
* @return Money | |
*/ | |
private function calculateTax($tax = 0) | |
{ | |
$taxrate = $tax; | |
if (!$taxrate && method_exists($this->entity, 'getTaxrate')) { | |
$taxrate = $this->entity->getTaxrate(); | |
} | |
$tax = new self($taxrate + 100); // 19% for example | |
$full = new self(100); | |
if ($this->entity === null) { | |
return new self(0, $this->money->multiply($full->toInt())->divide($tax->toInt())); | |
} | |
return $this->getAmount()->multiply($full)->divide($tax); | |
} | |
/** | |
* @return float | |
*/ | |
private function toFloat() | |
{ | |
return (float)$this->toString(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment