Skip to content

Commit

Permalink
feat: support float amount values, and fix debts and gifts amount for…
Browse files Browse the repository at this point in the history
…ms (#3906)
  • Loading branch information
asbiin authored May 20, 2020
1 parent 0fc7a77 commit 5c50cad
Show file tree
Hide file tree
Showing 36 changed files with 731 additions and 199 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

### Enhancements:

* Stores amount as integer-ish values, and fix debts and gifts amount forms
* Use current text from search bar to create a new person
* Always allow to add a new person from search bar
* Use queue to send email verification
Expand Down
2 changes: 1 addition & 1 deletion app/Helpers/InstanceHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static function getPlanInformationFromConfig(string $timePeriod): ?array
}

$currency = Currency::where('iso', strtoupper(config('cashier.currency')))->first();
$amount = MoneyHelper::format(config('monica.paid_plan_'.$timePeriod.'_price') / 100, $currency);
$amount = MoneyHelper::format(config('monica.paid_plan_'.$timePeriod.'_price'), $currency);

return [
'type' => $timePeriod,
Expand Down
106 changes: 94 additions & 12 deletions app/Helpers/MoneyHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,31 @@
use Money\Currencies\ISOCurrencies;
use Illuminate\Support\Facades\Auth;
use Money\Currency as MoneyCurrency;
use Money\Parser\DecimalMoneyParser;
use Money\Formatter\IntlMoneyFormatter;
use Money\Formatter\DecimalMoneyFormatter;

class MoneyHelper
{
/**
* Format a monetary amount with currency symbol.
* The value is formatted using current langage, as per the currency symbol.
*
* If the currency parameter is not passed, then the currency specified in
* the users's settings will be used. If the currency setting is not
* defined, then the amount will be returned without a currency symbol.
*
* @param int|null $amount Amount to format.
* @param Currency $currency Currency of amount.
* @return string Amount formatted with currency symbol.
* @param int|null $amount Amount value in storable format (ex: 100 for 1,00€).
* @param Currency|int|null $currency Currency of amount.
* @return string Formatted amount for display with currency symbol (ex '1,235.87 €').
*/
public static function format($amount, Currency $currency = null)
public static function format($amount, $currency = null): string
{
if (is_null($amount)) {
$amount = 0;
}

if (! $currency && Auth::check()) {
$currency = Auth::user()->currency;
}
$currency = self::getCurrency($currency);

if (! $currency) {
$numberFormatter = new \NumberFormatter(App::getLocale(), \NumberFormatter::DECIMAL);
Expand All @@ -40,14 +41,95 @@ public static function format($amount, Currency $currency = null)
}

$moneyCurrency = new MoneyCurrency($currency->iso);
$currencies = new ISOCurrencies();
$minorUnitAdjustment = pow(10, $currencies->subunitFor($moneyCurrency));
$money = new Money($amount, $moneyCurrency);
$numberFormatter = new \NumberFormatter(App::getLocale(), \NumberFormatter::CURRENCY);
$moneyFormatter = new IntlMoneyFormatter($numberFormatter, new ISOCurrencies());

$money = new Money($amount * $minorUnitAdjustment, $moneyCurrency);
return $moneyFormatter->format($money);
}

$numberFormatter = new \NumberFormatter(App::getLocale(), \NumberFormatter::CURRENCY);
$moneyFormatter = new IntlMoneyFormatter($numberFormatter, $currencies);
/**
* Format a monetary amount, without the currency.
* The value is formatted using current langage.
*
* @param int|null $amount Amount value in storable format (ex: 100 for 1,00€).
* @param Currency|int|null $currency
* @return string Formatted amount for display without currency symbol (ex: '1234.50').
*/
public static function getValue($amount, $currency = null): string
{
$currency = self::getCurrency($currency);

if (! $currency) {
return (string) ($amount / 100);
}

$moneyCurrency = new MoneyCurrency($currency->iso);
$money = new Money($amount ?? 0, $moneyCurrency);
$numberFormatter = new \NumberFormatter(App::getLocale(), \NumberFormatter::PATTERN_DECIMAL);
$moneyFormatter = new IntlMoneyFormatter($numberFormatter, new ISOCurrencies());

return $moneyFormatter->format($money);
}

/**
* Parse a monetary exchange value as storable integer.
* Currency is used to know the precision of this currency.
*
* @param mixed|null $exchange Amount value in exchange format (ex: 1.00).
* @param Currency|int|null $currency
* @return int Amount as storable format (ex: 14500).
*/
public static function parseInput($exchange, $currency): int
{
$currency = self::getCurrency($currency);

if (! $currency) {
return (int) ((float) $exchange * 100);
}

$moneyParser = new DecimalMoneyParser(new ISOCurrencies());
$money = $moneyParser->parse((string) $exchange, $currency->iso);

return (int) $money->getAmount();
}

/**
* Format a monetary value as exchange value.
* Exchange value is the amount to be entered in an input by a user,
* using ordinary format.
*
* @param int|null $amount Amount value in storable format (ex: 100 for 1,00€).
* @param Currency|int|null $currency
* @return string Real value of amount in exchange format (ex: 1.24).
*/
public static function exchangeValue($amount, $currency): string
{
$currency = self::getCurrency($currency);

$moneyCurrency = new MoneyCurrency($currency->iso);
$money = new Money($amount ?? 0, $moneyCurrency);
$moneyFormatter = new DecimalMoneyFormatter(new ISOCurrencies());

return $moneyFormatter->format($money);
}

/**
* Get currency object.
*
* @param Currency|int|null $currency
* @return Currency|null
*/
public static function getCurrency($currency): ?Currency
{
if (is_int($currency)) {
$currency = Currency::find($currency);
}

if (! $currency && Auth::check()) {
$currency = Auth::user()->currency;
}

return $currency;
}
}
4 changes: 2 additions & 2 deletions app/Http/Resources/Debt/Debt.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace App\Http\Resources\Debt;

use App\Helpers\DateHelper;
use App\Helpers\MoneyHelper;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Http\Resources\Contact\ContactShort as ContactShortResource;

Expand All @@ -26,7 +25,8 @@ public function toArray($request)
'in_debt' => $this->in_debt,
'status' => $this->status,
'amount' => $this->amount,
'amount_with_currency' => MoneyHelper::format((int) $this->amount),
'value' => $this->value,
'amount_with_currency' => $this->displayValue,
'reason' => $this->reason,
'account' => [
'id' => $this->account_id,
Expand Down
5 changes: 3 additions & 2 deletions app/Http/Resources/Gift/Gift.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ public function toArray($request)
'name' => $this->name,
'comment' => $this->comment,
'url' => $this->url,
'amount' => $this->value,
'amount_with_currency' => $this->amount,
'amount' => $this->amount,
'value' => $this->value,
'amount_with_currency' => $this->displayValue,
'status' => $this->status,
'date' => DateHelper::getDate($this->date),
'recipient' => new ContactShortResource($this->recipient),
Expand Down
15 changes: 11 additions & 4 deletions app/Models/Contact/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use App\Models\Instance\SpecialDate;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use IlluminateAgnostic\Arr\Support\Arr;
use App\Models\Account\ActivityStatistic;
use App\Models\Relationship\Relationship;
use Illuminate\Database\Eloquent\Builder;
Expand Down Expand Up @@ -1069,6 +1070,7 @@ public function getTagsAsString()

/**
* Is this contact owed money?
*
* @return bool
*/
public function isOwedMoney()
Expand All @@ -1079,16 +1081,21 @@ public function isOwedMoney()
/**
* How much is the debt.
*
* @return int
* @return int amount in storage value
*/
public function totalOutstandingDebtAmount()
public function totalOutstandingDebtAmount(): int
{
return $this
->debts()
->where('status', '=', 'inprogress')
->inProgress()
->getResults()
->filter(function ($d) {
return Arr::has($d->attributes, 'amount');
})
->sum(function ($d) {
return $d->in_debt === 'yes' ? -$d->amount : $d->amount;
$amount = $d->attributes['amount'];

return $d->in_debt === 'yes' ? -$amount : $amount;
});
}

Expand Down
8 changes: 8 additions & 0 deletions app/Models/Contact/Debt.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
namespace App\Models\Contact;

use App\Models\Account\Account;
use App\Traits\AmountFormatter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\ModelBindingHasherWithContact as Model;

/**
Expand All @@ -16,6 +18,8 @@
*/
class Debt extends Model
{
use AmountFormatter;

/**
* The attributes that aren't mass assignable.
*
Expand All @@ -33,6 +37,8 @@ class Debt extends Model

/**
* Get the account record associated with the debt.
*
* @return BelongsTo
*/
public function account()
{
Expand All @@ -41,6 +47,8 @@ public function account()

/**
* Get the contact record associated with the debt.
*
* @return BelongsTo
*/
public function contact()
{
Expand Down
15 changes: 3 additions & 12 deletions app/Models/Contact/Gift.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace App\Models\Contact;

use App\Helpers\MoneyHelper;
use App\Models\Account\Photo;
use App\Models\Account\Account;
use App\Traits\AmountFormatter;
use Illuminate\Database\Eloquent\Builder;
use App\Models\ModelBindingWithContact as Model;
use Illuminate\Database\Eloquent\Relations\HasOne;
Expand All @@ -19,12 +19,13 @@
* @property string $comment
* @property string $url
* @property Contact $is_for
* @property int $value
* @method static Builder offered()
* @method static Builder isIdea()
*/
class Gift extends Model
{
use AmountFormatter;

/**
* The attributes that aren't mass assignable.
*
Expand Down Expand Up @@ -150,14 +151,4 @@ public function getRecipientNameAttribute(): ?string

return null;
}

/**
* Get amount with currency.
*
* @return string
*/
public function getAmountAttribute(): string
{
return $this->value ? MoneyHelper::format($this->value) : '';
}
}
4 changes: 3 additions & 1 deletion app/Services/Account/Settings/ExportAccount.php
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ private function exportDebt(array $data)
'in_debt',
'status',
'amount',
'currency_id',
'reason',
'created_at',
'updated_at',
Expand Down Expand Up @@ -675,7 +676,8 @@ private function exportGift(array $data)
'name',
'comment',
'url',
'value',
'amount',
'currency_id',
'status',
'date',
'created_at',
Expand Down
7 changes: 6 additions & 1 deletion app/Services/Contact/Gift/CreateGift.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Services\BaseService;
use App\Models\Contact\Contact;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;

class CreateGift extends BaseService
{
Expand Down Expand Up @@ -61,11 +62,15 @@ public function execute(array $data): Gift
'status' => $data['status'],
'comment' => $this->nullOrvalue($data, 'comment'),
'url' => $this->nullOrvalue($data, 'url'),
'value' => $this->nullOrvalue($data, 'amount'),
'amount' => $this->nullOrvalue($data, 'amount'),
'date' => $this->nullOrvalue($data, 'date'),
'recipient' => $this->nullOrvalue($data, 'recipient_id'),
];

if (Auth::check()) {
$array['currency_id'] = Auth::user()->currency->id;
}

return Gift::create($array);
}
}
7 changes: 6 additions & 1 deletion app/Services/Contact/Gift/UpdateGift.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Services\BaseService;
use App\Models\Contact\Contact;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;

class UpdateGift extends BaseService
{
Expand Down Expand Up @@ -64,11 +65,15 @@ public function execute(array $data): Gift
'status' => $data['status'],
'comment' => $this->nullOrvalue($data, 'comment'),
'url' => $this->nullOrvalue($data, 'url'),
'value' => $this->nullOrvalue($data, 'amount'),
'amount' => $this->nullOrvalue($data, 'amount'),
'date' => $this->nullOrvalue($data, 'date'),
'recipient' => $this->nullOrvalue($data, 'recipient_id'),
];

if (Auth::check()) {
$array['currency_id'] = Auth::user()->currency->id;
}

return tap($gift)
->update($array);
}
Expand Down
Loading

0 comments on commit 5c50cad

Please sign in to comment.