diff --git a/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php b/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php index 3241d0f300..a02c864854 100644 --- a/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php @@ -88,7 +88,7 @@ class UpdateRequest extends FormRequest 'notes', ]; - $this->floatFields = [ + $this->floatFields = [ // not really floats, for validation. 'amount', 'foreign_amount', ]; @@ -408,8 +408,7 @@ class UpdateRequest extends FormRequest if (array_key_exists($fieldName, $transaction)) { $value = $transaction[$fieldName]; if (is_float($value)) { - // TODO this effectively limits the max number of decimals in currencies to 14. - $current[$fieldName] = sprintf('%.14f', $value); + $current[$fieldName] = sprintf('%.24f', $value); } if (!is_float($value)) { $current[$fieldName] = (string) $value; diff --git a/app/Api/V1/Requests/User/PreferenceStoreRequest.php b/app/Api/V1/Requests/User/PreferenceStoreRequest.php index 06d3b51822..384c386d25 100644 --- a/app/Api/V1/Requests/User/PreferenceStoreRequest.php +++ b/app/Api/V1/Requests/User/PreferenceStoreRequest.php @@ -47,9 +47,8 @@ class PreferenceStoreRequest extends FormRequest if ('false' === $array['data']) { $array['data'] = false; } - // TODO remove float if (is_numeric($array['data'])) { - $array['data'] = (float) $array['data']; + $array['data'] = (float) $array['data']; // intentional float. } return $array; diff --git a/app/Api/V1/Requests/User/PreferenceUpdateRequest.php b/app/Api/V1/Requests/User/PreferenceUpdateRequest.php index 130ed7b376..d22fd73728 100644 --- a/app/Api/V1/Requests/User/PreferenceUpdateRequest.php +++ b/app/Api/V1/Requests/User/PreferenceUpdateRequest.php @@ -48,9 +48,8 @@ class PreferenceUpdateRequest extends FormRequest if ('false' === $array['data']) { $array['data'] = false; } - // TODO remove float if (is_numeric($array['data'])) { - $array['data'] = (float) $array['data']; + $array['data'] = (float) $array['data']; // intentional float. } return $array; diff --git a/app/Http/Controllers/Report/TagController.php b/app/Http/Controllers/Report/TagController.php index 9fb3828453..5cb8b7f3fe 100644 --- a/app/Http/Controllers/Report/TagController.php +++ b/app/Http/Controllers/Report/TagController.php @@ -543,7 +543,7 @@ class TagController extends Controller $result[] = [ 'description' => $journal['description'], 'transaction_group_id' => $journal['transaction_group_id'], - 'amount_float' => (float) $journal['amount'], + 'amount_float' => (float) $journal['amount'], // intentional float. 'amount' => $journal['amount'], 'date' => $journal['date']->isoFormat($this->monthAndDayFormat), 'date_sort' => $journal['date']->format('Y-m-d'), diff --git a/app/Http/Requests/RecurrenceFormRequest.php b/app/Http/Requests/RecurrenceFormRequest.php index 439dd6e0ca..b607162ca0 100644 --- a/app/Http/Requests/RecurrenceFormRequest.php +++ b/app/Http/Requests/RecurrenceFormRequest.php @@ -100,7 +100,7 @@ class RecurrenceFormRequest extends FormRequest ]; // fill in foreign currency data - if (null !== $this->convertFloat('foreign_amount')) { + if (null !== $this->convertFloat('foreign_amount')) { // intentional float, used because it defaults to null. $return['transactions'][0]['foreign_amount'] = $this->convertString('foreign_amount'); $return['transactions'][0]['foreign_currency_id'] = $this->convertInteger('foreign_currency_id'); } @@ -229,7 +229,7 @@ class RecurrenceFormRequest extends FormRequest $rules['repetitions'] = 'required|numeric|between:0,254'; } // if foreign amount, currency must be different. - if (null !== $this->convertFloat('foreign_amount')) { + if (null !== $this->convertFloat('foreign_amount')) { // intentional float, used because it defaults to null. $rules['foreign_currency_id'] = 'exists:transaction_currencies,id|different:transaction_currency_id'; } diff --git a/app/Support/Amount.php b/app/Support/Amount.php index f02340a4ec..485a9fa94d 100644 --- a/app/Support/Amount.php +++ b/app/Support/Amount.php @@ -70,21 +70,21 @@ class Amount */ public function formatFlat(string $symbol, int $decimalPlaces, string $amount, bool $coloured = null): string { - $locale = app('steam')->getLocale(); - + $locale = app('steam')->getLocale(); + $rounded = app('steam')->bcround($amount, $decimalPlaces); $coloured = $coloured ?? true; $fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY); $fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $symbol); $fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces); $fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces); - $result = $fmt->format((float)app('steam')->bcround($amount, $decimalPlaces)); // intentional float + $result = $fmt->format((float)$rounded); // intentional float if (true === $coloured) { - if (1 === bccomp($amount, '0')) { + if (1 === bccomp($rounded, '0')) { return sprintf('%s', $result); } - if (-1 === bccomp($amount, '0')) { + if (-1 === bccomp($rounded, '0')) { return sprintf('%s', $result); } diff --git a/app/Support/Chart/Category/FrontpageChartGenerator.php b/app/Support/Chart/Category/FrontpageChartGenerator.php index 0a1d86d042..b251399455 100644 --- a/app/Support/Chart/Category/FrontpageChartGenerator.php +++ b/app/Support/Chart/Category/FrontpageChartGenerator.php @@ -151,7 +151,7 @@ class FrontpageChartGenerator $tempData[] = [ 'name' => trans('firefly.no_category'), 'sum' => $currency['sum'], - 'sum_float' => round((float) $currency['sum'], $currency['currency_decimal_places'] ?? 2), + 'sum_float' => round((float) $currency['sum'], $currency['currency_decimal_places'] ?? 2), // intentional float 'currency_id' => (int) $currency['currency_id'], ]; } diff --git a/app/Support/Http/Controllers/ModelInformation.php b/app/Support/Http/Controllers/ModelInformation.php index c186933a76..7581e2b871 100644 --- a/app/Support/Http/Controllers/ModelInformation.php +++ b/app/Support/Http/Controllers/ModelInformation.php @@ -130,8 +130,8 @@ trait ModelInformation $billTriggers = ['currency_is', 'amount_more', 'amount_less', 'description_contains']; $values = [ $bill->transactionCurrency()->first()->name, - round((float) $bill->amount_min, 24), - round((float) $bill->amount_max, 24), + $bill->amount_min, + $bill->amount_max, $bill->name, ]; foreach ($billTriggers as $index => $trigger) { diff --git a/app/Support/Steam.php b/app/Support/Steam.php index 5e2dd76dfb..1958cb78d0 100644 --- a/app/Support/Steam.php +++ b/app/Support/Steam.php @@ -104,13 +104,19 @@ class Steam */ public function bcround(?string $number, int $precision = 0): string { + if(null === $number) { return '0'; } if('' === trim($number)) { return '0'; } - Log::debug(sprintf('Trying bcround("%",%d)', $number, $precision)); + // if the number contains "E", it's in scientific notation, so we need to convert it to a normal number first. + if(false !== stripos($number,'e')) { + $number = sprintf('%.24f',$number); + } + + Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision)); if (str_contains($number, '.')) { if ($number[0] !== '-') { return bcadd($number, '0.'.str_repeat('0', $precision).'5', $precision); @@ -584,8 +590,10 @@ class Steam if ($mantis < 0) { $post += abs((int)$mantis); } + // TODO careless float could break financial math. return number_format((float)$value, $post, '.', ''); } + // TODO careless float could break financial math. return number_format((float)$value, 0, '.', ''); } diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index a6227be244..cc56a4b3f8 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -78,7 +78,7 @@ class AccountTransformer extends AbstractTransformer [$openingBalance, $openingBalanceDate] = $this->getOpeningBalance($account, $accountType); [$interest, $interestPeriod] = $this->getInterest($account, $accountType); - $openingBalance = number_format((float) $openingBalance, $decimalPlaces, '.', ''); + $openingBalance = app('steam')->bcround($openingBalance, $decimalPlaces); $includeNetWorth = '0' !== $this->repository->getMetaValue($account, 'include_net_worth'); $longitude = null; $latitude = null; @@ -109,7 +109,7 @@ class AccountTransformer extends AbstractTransformer 'currency_code' => $currencyCode, 'currency_symbol' => $currencySymbol, 'currency_decimal_places' => $decimalPlaces, - 'current_balance' => number_format((float) app('steam')->balance($account, $date), $decimalPlaces, '.', ''), + 'current_balance' => app('steam')->bcround(app('steam')->balance($account, $date), $decimalPlaces), 'current_balance_date' => $date->toAtomString(), 'notes' => $this->repository->getNoteText($account), 'monthly_payment_date' => $monthlyPaymentDate, @@ -117,7 +117,7 @@ class AccountTransformer extends AbstractTransformer 'account_number' => $this->repository->getMetaValue($account, 'account_number'), 'iban' => '' === $account->iban ? null : $account->iban, 'bic' => $this->repository->getMetaValue($account, 'BIC'), - 'virtual_balance' => number_format((float) $account->virtual_balance, $decimalPlaces, '.', ''), + 'virtual_balance' => app('steam')->bcround($account->virtual_balance, $decimalPlaces), 'opening_balance' => $openingBalance, 'opening_balance_date' => $openingBalanceDate, 'liability_type' => $liabilityType, diff --git a/app/Transformers/AvailableBudgetTransformer.php b/app/Transformers/AvailableBudgetTransformer.php index b9fd050673..62944bab86 100644 --- a/app/Transformers/AvailableBudgetTransformer.php +++ b/app/Transformers/AvailableBudgetTransformer.php @@ -69,7 +69,7 @@ class AvailableBudgetTransformer extends AbstractTransformer 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, 'currency_decimal_places' => (int) $currency->decimal_places, - 'amount' => number_format((float) $availableBudget->amount, $currency->decimal_places, '.', ''), + 'amount' => app('steam')->bcround($availableBudget->amount, $currency->decimal_places), 'start' => $availableBudget->start_date->toAtomString(), 'end' => $availableBudget->end_date->endOfDay()->toAtomString(), 'spent_in_budgets' => [], diff --git a/app/Transformers/BillTransformer.php b/app/Transformers/BillTransformer.php index f469b0c698..54b1d11348 100644 --- a/app/Transformers/BillTransformer.php +++ b/app/Transformers/BillTransformer.php @@ -115,8 +115,8 @@ class BillTransformer extends AbstractTransformer 'currency_symbol' => $currency->symbol, 'currency_decimal_places' => (int) $currency->decimal_places, 'name' => $bill->name, - 'amount_min' => number_format((float) $bill->amount_min, $currency->decimal_places, '.', ''), - 'amount_max' => number_format((float) $bill->amount_max, $currency->decimal_places, '.', ''), + 'amount_min' => app('steam')->bcround($bill->amount_min, $currency->decimal_places), + 'amount_max' => app('steam')->bcround($bill->amount_max, $currency->decimal_places), 'date' => $bill->date->toAtomString(), 'end_date' => $bill->end_date?->toAtomString(), 'extension_date' => $bill->extension_date?->toAtomString(), diff --git a/app/Transformers/BudgetLimitTransformer.php b/app/Transformers/BudgetLimitTransformer.php index d7431a77ff..6850d09487 100644 --- a/app/Transformers/BudgetLimitTransformer.php +++ b/app/Transformers/BudgetLimitTransformer.php @@ -84,7 +84,7 @@ class BudgetLimitTransformer extends AbstractTransformer $currencySymbol = $currency->symbol; $currencyDecimalPlaces = $currency->decimal_places; } - $amount = number_format((float) $amount, $currencyDecimalPlaces, '.', ''); + $amount = app('steam')->bcround($amount, $currencyDecimalPlaces); return [ 'id' => (string) $budgetLimit->id, diff --git a/app/Transformers/BudgetTransformer.php b/app/Transformers/BudgetTransformer.php index 218083d9b2..e4b6f16dfc 100644 --- a/app/Transformers/BudgetTransformer.php +++ b/app/Transformers/BudgetTransformer.php @@ -84,7 +84,7 @@ class BudgetTransformer extends AbstractTransformer $abCurrencyId = (string) $autoBudget->transactionCurrency->id; $abCurrencyCode = $autoBudget->transactionCurrency->code; $abType = $types[$autoBudget->auto_budget_type]; - $abAmount = number_format((float) $autoBudget->amount, $autoBudget->transactionCurrency->decimal_places, '.', ''); + $abAmount = app('steam')->bcround($autoBudget->amount, $autoBudget->transactionCurrency->decimal_places); $abPeriod = $autoBudget->period; } @@ -120,7 +120,7 @@ class BudgetTransformer extends AbstractTransformer { $return = []; foreach ($array as $data) { - $data['sum'] = number_format((float) $data['sum'], (int) $data['currency_decimal_places'], '.', ''); + $data['sum'] = app('steam')->bcround($data['sum'], (int) $data['currency_decimal_places']); $return[] = $data; } diff --git a/app/Transformers/CategoryTransformer.php b/app/Transformers/CategoryTransformer.php index 295b30fa01..81fe257bf8 100644 --- a/app/Transformers/CategoryTransformer.php +++ b/app/Transformers/CategoryTransformer.php @@ -95,7 +95,7 @@ class CategoryTransformer extends AbstractTransformer { $return = []; foreach ($array as $data) { - $data['sum'] = number_format((float) $data['sum'], (int) $data['currency_decimal_places'], '.', ''); + $data['sum'] = app('steam')->bcround($data['sum'], (int) $data['currency_decimal_places']); $return[] = $data; } diff --git a/app/Transformers/PiggyBankEventTransformer.php b/app/Transformers/PiggyBankEventTransformer.php index caa8b52042..5a925c6428 100644 --- a/app/Transformers/PiggyBankEventTransformer.php +++ b/app/Transformers/PiggyBankEventTransformer.php @@ -83,7 +83,7 @@ class PiggyBankEventTransformer extends AbstractTransformer 'id' => (string) $event->id, 'created_at' => $event->created_at->toAtomString(), 'updated_at' => $event->updated_at->toAtomString(), - 'amount' => number_format((float) $event->amount, $currency->decimal_places, '.', ''), + 'amount' => app('steam')->bcround($event->amount, $currency->decimal_places), 'currency_id' => (string) $currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, diff --git a/app/Transformers/PiggyBankTransformer.php b/app/Transformers/PiggyBankTransformer.php index 7a66774b43..aca43a7a69 100644 --- a/app/Transformers/PiggyBankTransformer.php +++ b/app/Transformers/PiggyBankTransformer.php @@ -53,7 +53,7 @@ class PiggyBankTransformer extends AbstractTransformer /** * Transform the piggy bank. * - * @param PiggyBank $piggyBank + * @param PiggyBank $piggyBank * * @return array * @throws \FireflyIII\Exceptions\FireflyException @@ -81,44 +81,44 @@ class PiggyBankTransformer extends AbstractTransformer /** @var ObjectGroup $objectGroup */ $objectGroup = $piggyBank->objectGroups->first(); if (null !== $objectGroup) { - $objectGroupId = (int) $objectGroup->id; - $objectGroupOrder = (int) $objectGroup->order; + $objectGroupId = (int)$objectGroup->id; + $objectGroupOrder = (int)$objectGroup->order; $objectGroupTitle = $objectGroup->title; } // get currently saved amount: $currentAmountStr = $this->piggyRepos->getCurrentAmount($piggyBank); - $currentAmount = number_format((float) $currentAmountStr, $currency->decimal_places, '.', ''); + $currentAmount = app('steam')->bcround($currentAmountStr, $currency->decimal_places); // Amounts, depending on 0.0 state of target amount $percentage = null; $targetAmountString = null; $leftToSaveString = null; $savePerMonth = null; - if (0.000 !== (float) $piggyBank->targetamount) { + if (0 !== bccomp(app('steam')->bcround($currentAmountStr, $currency->decimal_places), '0')) { $leftToSave = bcsub($piggyBank->targetamount, $currentAmountStr); - $targetAmount = (string) $piggyBank->targetamount; + $targetAmount = (string)$piggyBank->targetamount; $targetAmount = 1 === bccomp('0.01', $targetAmount) ? '0.01' : $targetAmount; - $percentage = (int) (0 !== bccomp('0', $currentAmountStr) ? $currentAmountStr / $targetAmount * 100 : 0); - $targetAmountString = number_format((float) $targetAmount, $currency->decimal_places, '.', ''); - $leftToSaveString = number_format((float) $leftToSave, $currency->decimal_places, '.', ''); - $savePerMonth = number_format((float) $this->piggyRepos->getSuggestedMonthlyAmount($piggyBank), $currency->decimal_places, '.', ''); + $percentage = (int)(0 !== bccomp('0', $currentAmountStr) ? $currentAmountStr / $targetAmount * 100 : 0); + $targetAmountString = app('steam')->bcround($targetAmount, $currency->decimal_places); + $leftToSaveString = app('steam')->bcround($leftToSave, $currency->decimal_places); + $savePerMonth = app('steam')->bcround($this->piggyRepos->getSuggestedMonthlyAmount($piggyBank), $currency->decimal_places); } $startDate = $piggyBank->startdate?->toAtomString(); $targetDate = $piggyBank->targetdate?->toAtomString(); return [ - 'id' => (string) $piggyBank->id, + 'id' => (string)$piggyBank->id, 'created_at' => $piggyBank->created_at->toAtomString(), 'updated_at' => $piggyBank->updated_at->toAtomString(), - 'account_id' => (string) $piggyBank->account_id, + 'account_id' => (string)$piggyBank->account_id, 'account_name' => $piggyBank->account->name, 'name' => $piggyBank->name, - 'currency_id' => (string) $currency->id, + 'currency_id' => (string)$currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int) $currency->decimal_places, + 'currency_decimal_places' => (int)$currency->decimal_places, 'target_amount' => $targetAmountString, 'percentage' => $percentage, 'current_amount' => $currentAmount, @@ -126,16 +126,16 @@ class PiggyBankTransformer extends AbstractTransformer 'save_per_month' => $savePerMonth, 'start_date' => $startDate, 'target_date' => $targetDate, - 'order' => (int) $piggyBank->order, + 'order' => (int)$piggyBank->order, 'active' => true, 'notes' => $notes, - 'object_group_id' => $objectGroupId ? (string) $objectGroupId : null, + 'object_group_id' => $objectGroupId ? (string)$objectGroupId : null, 'object_group_order' => $objectGroupOrder, 'object_group_title' => $objectGroupTitle, 'links' => [ [ 'rel' => 'self', - 'uri' => '/piggy_banks/' . $piggyBank->id, + 'uri' => '/piggy_banks/'.$piggyBank->id, ], ], ]; diff --git a/app/Transformers/RecurrenceTransformer.php b/app/Transformers/RecurrenceTransformer.php index 42172ea2e3..be829e8e4e 100644 --- a/app/Transformers/RecurrenceTransformer.php +++ b/app/Transformers/RecurrenceTransformer.php @@ -196,10 +196,10 @@ class RecurrenceTransformer extends AbstractTransformer $destinationType = $destinationAccount->accountType->type; $destinationIban = $destinationAccount->iban; } - $amount = number_format((float) $transaction->amount, $transaction->transactionCurrency->decimal_places, '.', ''); + $amount = app('steam')->bcround($transaction->amount, $transaction->transactionCurrency->decimal_places); $foreignAmount = null; if (null !== $transaction->foreign_currency_id && null !== $transaction->foreign_amount) { - $foreignAmount = number_format((float) $transaction->foreign_amount, $foreignCurrencyDp, '.', ''); + $foreignAmount = app('steam')->bcround($transaction->foreign_amount, $foreignCurrencyDp); } $transactionArray = [ 'currency_id' => (string) $transaction->transaction_currency_id, diff --git a/app/Transformers/TransactionGroupTransformer.php b/app/Transformers/TransactionGroupTransformer.php index 4baa7e8c95..adf222c03a 100644 --- a/app/Transformers/TransactionGroupTransformer.php +++ b/app/Transformers/TransactionGroupTransformer.php @@ -364,7 +364,7 @@ class TransactionGroupTransformer extends AbstractTransformer $bill = $this->getBill($journal->bill); if (null !== $foreignAmount && null !== $foreignCurrency) { - $foreignAmount = number_format((float) $foreignAmount, $foreignCurrency['decimal_places'] ?? 0, '.', ''); + $foreignAmount = app('steam')->bcround($foreignAmount, $foreignCurrency['decimal_places'] ?? 0); } $longitude = null; @@ -394,7 +394,7 @@ class TransactionGroupTransformer extends AbstractTransformer 'foreign_currency_symbol' => $foreignCurrency['symbol'], 'foreign_currency_decimal_places' => $foreignCurrency['decimal_places'], - 'amount' => number_format((float) $amount, $currency->decimal_places, '.', ''), + 'amount' => app('steam')->bcround($amount, $currency->decimal_places), 'foreign_amount' => $foreignAmount, 'description' => $journal->description, @@ -462,7 +462,7 @@ class TransactionGroupTransformer extends AbstractTransformer { $result = $journal->transactions->first( static function (Transaction $transaction) { - return (float) $transaction->amount < 0; + return (float) $transaction->amount < 0; // lame but it works. } ); if (null === $result) { @@ -482,7 +482,7 @@ class TransactionGroupTransformer extends AbstractTransformer { $result = $journal->transactions->first( static function (Transaction $transaction) { - return (float) $transaction->amount > 0; + return (float) $transaction->amount > 0; // lame but it works } ); if (null === $result) {