Алгоритм вычисления проблемного периода сумм при просчете комиссии

Есть функция перевода, допустим золота(валюта), за перевод берется комиссия:
до 150,00 золота - 5 золота
свыше 150,00 - 8 золота + 1% от суммы
если перевод срочный, то ко всем комиссиям + 10 золота
уведомление дополнительно 4,20 золота
Задача: нужно написать некий функционал который позволит отправлять сумму и оплачивать комиссию за счет получателя, т.е. нужно отправить 200 золота, надо взять такую сумму, прибавив к которой комиссию, должно получится ровно 200 золота.

class Calculator {
    var $CDB;
    var $Amount;
    var $Category;    // 1,2 - простая категория, 5 - срочная
    var $Category2; // категория уведомлений
    var $Amountcop;
    var $comHrn; //фиксированная комиссия
    var $comPer; //процентная комиссия
    var $comDop; //дополнительная плата за уведомление

    public function __construct($CDB, $Amount, $Category, $Category2) {
        $this->CDB = $CDB;
        $this->Amount = $Amount;
        $this->Category = $Category;
        $this->Category2 = $Category2;
        $this->Amountcop = $this->Amount*100-500;
        $this->comPer = 1+$this->CDB->take("select Процент from Тариф where Категория=$this->Category and ($this->Amountcop>RangeLow and $this->Amountcop<=RangeHi)");
        $this->comDop = $this->CDB->take("select Золото from Тариф where Категория=$this->Category2 and ($this->Amountcop>RangeLow and $this->Amountcop<=RangeHi)")+0.70;
    }

    public function calc() {
        if ($this->Category==5) {
            $this->Amount=$this->Amount-10;
        }
        if ($this->Category2!='') {
            $this->Amount=$this->Amount-$this->comDop;
        }
        if ($this->Amount<=155) {
            $res=$this->Amount-5;
        }
        if ($this->Amount>155) {
            $res=round(($this->Amount-8)/$this->comPer, 2);
            if ($res<150) {
                $res=false;
            }
        }
        return $res;
    }

    public function error($j) {
        if ($this->Category==5) {
            $j=$j-10;
        }
        if ($this->Category2!='') {
            $j=$j-$this->comDop;
        }
        $res=round(($j-8)/$this->comPer, 2);
        return $res;
    }
}


index.php
$ore = new Calculator($CDB, $Amount, $vars[Category], $vars[Category2]);

if ($_POST['pay']=='Клиент') {
    $x=$ore->calc();
    echo $x;
    if($x==false) {
        $j = 155;
        do {
            $j++;
            echo $j;
            $y = $ore->error($j);
        } while ($y<150);
        $_SESSION['errorMsg'] = "Невозможно расcчитать сумму \"с учетом оплаты за пересылку\" в границах от 155.01-$j золота. Укажите другую сумму.";
        header("Location: index.php?error=incorrect");
    }


Проблема в том, что на стыках тарифов возникают некие периоды, которые невозможно так просчитать. Давайте возьмем 168,00 золота и срочную отправку, в метод calc() попадает сумма, класс уже знает что перевод срочный, условие if ($this->Category==5) срабатывает и отнимается 10 золота(=158,00 золота), теперь смотрим условия больше или меньше-равно 155 золота, 158>155, поэтому срабатывает условие большего тарифа(8зол + 1%)
($this->Amount>155) {
            $res=round(($this->Amount-8)/$this->comPer, 2);

после этой операции остается сумма 148.51 и срабатывает следующее условие
if ($res<150) {
                $res=false;
            }

обьясню почему false, дальше программа будет вычислять из суммы комиссию по "прямому" методу, тоесть возьмет число 148.51 увидит что оно меньше 150 золота, и тупо прибавит к нему 5 гривен(=153,51), а нам нужна сумма 168,00.
Вопрос: как организовать выдачу ошибки, т.е. просчет этого самого "черного" периода, и возвращать пользователя на предыдущий этап ввода суммы, сейчас сделано тупым циклом добавления 1 золота и просчета, пока не удовлетворит условиям.
  • Вопрос задан
  • 2597 просмотров
Пригласить эксперта
Ответы на вопрос 3
GeneMoss
@GeneMoss
void
Не до конца улавливаю суть Вашей проблемы. Комиссия, которую Вы описали, рассчитывается как-нибудь так:
/* Тут был код, потерявший актуальность */

P.S.: И избавьтесь хотябы от магических чисел, ибо я так и не понял, что такое 155.
Ответ написан
AMar4enko
@AMar4enko
Вы серьезно?
Это же простейшая пропорция
200 золота = 101%
x золота = 100%

x = (200 * 100) / 101
Сначала отнимаете от суммы платежа все фиксированные комиссии, потом высчитываете по этой пропорции. Какие к чертям периоды?
Ответ написан
GeneMoss
@GeneMoss
void
Так?
class Payment
{
	protected $isUrgent = true; // является ли платеж срочным
	protected $amount = 0;
	
	public function __construct($amount)
	{
		$this->amount = $amount;
	}
	
	public function getAmount()
	{
		return $this->amount;
	}
	
	// Высчитать включенную в сумму комиссию
	public function calculateIncludedCommission()
	{
		$comission = $this->calculateIncludedCommissionForBigSum();
		if (150 > $this->getAmount() - $comission) {
			$comission = $this->calculateIncludedCommissionForSmallSum();
		}
		return $comission;
	}
	
	// Высчитать включенную в сумму комиссию для больших сумм
	protected function calculateIncludedCommissionForBigSum()
	{
		$comission = 0;
		if ( $this->isUrgent ) {
			$comission += 10;
		}
		$comission += 8;
		$percent = 0.01;
		$baseSum = round(($this->amount - $comission) / (1 + $percent), 2);
		$comission = $this->amount - $baseSum;
		return $comission;
	}

	// Высчитать включенную в сумму комиссию для малых сумм
	protected function calculateIncludedCommissionForSmallSum()
	{
		$comission = 0;
		if ( $this->isUrgent ) {
			$comission += 10;
		}
		$comission += 5;
		return $comission;
	}
}
//////////////////

$payment = new Payment(200);

$comission = $payment->calculateIncludedCommission();
$sum = $payment->getAmount() - $comission;

echo 'Платеж: ', $payment->getAmount(), PHP_EOL;
echo 'Сумма к зачислению: ', $sum, PHP_EOL;
echo 'Комиссия: ', $comission, PHP_EOL;
echo PHP_EOL;


Данный код принимает сумму 200 и вернет:
Платеж: 200
Сумма к зачислению: 180.2
Комиссия: 19.8

P.S.: Названия методов можно придумать и короче. =)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы