Multi account piggy banks.

This commit is contained in:
James Cole 2024-12-14 17:32:03 +01:00
parent fb6c67fa04
commit 6a62f781e9
No known key found for this signature in database
GPG Key ID: B49A324B7EAD6D80
24 changed files with 572 additions and 404 deletions

View File

@ -72,6 +72,7 @@ class UpgradeDatabase extends Command
'firefly-iii:create-group-memberships',
'firefly-iii:upgrade-group-information',
'firefly-iii:upgrade-currency-preferences',
'firefly-iii:upgrade-multi-piggies',
'firefly-iii:correct-database',
];
$args = [];

View File

@ -93,7 +93,7 @@ class UpgradeMultiPiggyBanks extends Command
{
$this->repository->setUser($piggyBank->account->user);
$this->accountRepository->setUser($piggyBank->account->user);
$repetition = $this->repository->getRepetition($piggyBank);
$repetition = $this->repository->getRepetition($piggyBank, true);
$currency = $this->accountRepository->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrencyByUserGroup($piggyBank->account->user->userGroup);
// update piggy bank to have a currency.

View File

@ -42,12 +42,22 @@ class PiggyBankFactory
public User $user {
set(User $value) {
$this->user = $value;
$this->currencyRepository->setUser($value);
$this->accountRepository->setUser($value);
$this->piggyBankRepository->setUser($value);
}
}
private CurrencyRepositoryInterface $currencyRepository;
private AccountRepositoryInterface $accountRepository;
private PiggyBankRepositoryInterface $piggyBankRepository;
public function __construct()
{
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->piggyBankRepository = app(PiggyBankRepositoryInterface::class);
}
/**
* Store a piggy bank or come back with an exception.
*
@ -56,12 +66,7 @@ class PiggyBankFactory
* @return PiggyBank
*/
public function store(array $data): PiggyBank {
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->piggyBankRepository = app(PiggyBankRepositoryInterface::class);
$this->currencyRepository->setUser($this->user);
$this->accountRepository->setUser($this->user);
$this->piggyBankRepository->setUser($this->user);
$piggyBankData =$data;
// unset some fields
@ -202,14 +207,23 @@ class PiggyBankFactory
}
private function linkToAccountIds(PiggyBank $piggyBank, array $accounts): void {
public function linkToAccountIds(PiggyBank $piggyBank, array $accounts): void {
$toBeLinked = [];
/** @var array $info */
foreach($accounts as $info) {
$account = $this->accountRepository->find((int)($info['account_id'] ?? 0));
if(null === $account) {
continue;
}
$piggyBank->accounts()->syncWithoutDetaching([$account->id => ['current_amount' => $info['current_amount'] ?? '0']]);
if(array_key_exists('current_amount',$info)) {
$toBeLinked[$account->id] = ['current_amount' => $info['current_amount']];
//$piggyBank->accounts()->syncWithoutDetaching([$account->id => ['current_amount' => $info['current_amount'] ?? '0']]);
}
if(!array_key_exists('current_amount', $info)) {
$toBeLinked[$account->id] = [];
//$piggyBank->accounts()->syncWithoutDetaching([$account->id]);
}
}
$piggyBank->accounts()->sync($toBeLinked);
}
}

View File

@ -26,12 +26,14 @@ namespace FireflyIII\Http\Controllers\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@ -69,16 +71,26 @@ class AmountController extends Controller
*/
public function add(PiggyBank $piggyBank)
{
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, today(config('app.timezone')));
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
$maxAmount = $leftOnAccount;
if (0 !== bccomp($piggyBank->target_amount, '0')) {
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
$maxAmount = min($leftOnAccount, $leftToSave);
$accounts = [];
$total = '0';
$totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank);
$leftToSave = bcsub($piggyBank->target_amount, $totalSaved);
foreach ($piggyBank->accounts as $account) {
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, today(config('app.timezone'))->endOfDay());
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftToSave : min($leftOnAccount, $leftToSave);
$accounts[] = [
'account' => $account,
'left_on_account' => $leftOnAccount,
'saved_so_far' => $savedSoFar,
'left_to_save' => $leftToSave,
'max_amount' => $maxAmount,
];
$total = bcadd($total, $leftOnAccount);
}
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
$total = (float) $total; // intentional float.
return view('piggy-banks.add', compact('piggyBank', 'maxAmount', 'currency'));
return view('piggy-banks.add', compact('piggyBank', 'accounts', 'total'));
}
/**
@ -90,17 +102,23 @@ class AmountController extends Controller
{
/** @var Carbon $date */
$date = session('end', today(config('app.timezone')));
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $date);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
$maxAmount = $leftOnAccount;
if (0 !== bccomp($piggyBank->target_amount, '0')) {
$accounts = [];
$total = '0';
foreach ($piggyBank->accounts as $account) {
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
$maxAmount = min($leftOnAccount, $leftToSave);
$accounts[] = [
'account' => $account,
'left_on_account' => $leftOnAccount,
'saved_so_far' => $savedSoFar,
'left_to_save' => $leftToSave,
'max_amount' => 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave),
];
$total = bcadd($total, $leftOnAccount);
}
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
return view('piggy-banks.add-mobile', compact('piggyBank', 'maxAmount', 'currency'));
return view('piggy-banks.add-mobile', compact('piggyBank', 'total', 'accounts'));
}
/**
@ -108,32 +126,47 @@ class AmountController extends Controller
*/
public function postAdd(Request $request, PiggyBank $piggyBank): RedirectResponse
{
$amount = $request->get('amount') ?? '0';
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
// if amount is negative, make positive and continue:
$data = $request->all();
$amounts = $data['amount'] ?? [];
$total = '0';
Log::debug('Start with loop.');
/** @var Account $account */
foreach ($piggyBank->accounts as $account) {
$amount = (string) ($amounts[$account->id] ?? '0');
if ('' === $amount || 0 === bccomp($amount, '0')) {
continue;
}
if (-1 === bccomp($amount, '0')) {
$amount = bcmul($amount, '-1');
}
if ($this->piggyRepos->canAddAmount($piggyBank, $amount)) {
$this->piggyRepos->addAmount($piggyBank, $amount);
session()->flash(
'success',
(string)trans(
'firefly.added_amount_to_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name]
)
);
// small check to see if the $amount is not more than the total "left to save" value
$currentAmount = $this->piggyRepos->getCurrentAmount($piggyBank);
$leftToSave = 0 === bccomp($piggyBank->target_amount, '0') ? '0' : bcsub($piggyBank->target_amount, $currentAmount);
if (bccomp($amount, $leftToSave) > 0 && 0 !== bccomp($leftToSave, '0')) {
Log::debug(sprintf('Amount "%s" is more than left to save "%s". Using left to save.', $amount, $leftToSave));
$amount = $leftToSave;
}
$canAddAmount = $this->piggyRepos->canAddAmount($piggyBank, $account, $amount);
if ($canAddAmount) {
$this->piggyRepos->addAmount($piggyBank, $account, $amount);
$total = bcadd($total, $amount);
}
$piggyBank->refresh();
}
if (0 !== bccomp($total, '0')) {
session()->flash('success', (string) trans('firefly.added_amount_to_piggy', ['amount' => app('amount')->formatAnything($piggyBank->transactionCurrency, $total, false), 'name' => $piggyBank->name]));
app('preferences')->mark();
return redirect(route('piggy-banks.index'));
}
app('log')->error('Cannot add '.$amount.' because canAddAmount returned false.');
app('log')->error(sprintf('Cannot add %s because canAddAmount returned false.', $total));
session()->flash(
'error',
(string) trans(
'firefly.cannot_add_amount_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)]
['amount' => app('amount')->formatAnything($piggyBank->transactionCurrency, $total, false), 'name' => e($piggyBank->name)]
)
);
@ -145,32 +178,43 @@ class AmountController extends Controller
*/
public function postRemove(Request $request, PiggyBank $piggyBank): RedirectResponse
{
$amount = $request->get('amount') ?? '0';
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
// if amount is negative, make positive and continue:
$amounts = $request->get('amount') ?? [];
if (!is_array($amounts)) {
$amounts = [];
}
$total = '0';
/** @var Account $account */
foreach ($piggyBank->accounts as $account) {
$amount = (string) ($amounts[$account->id] ?? '0');
if ('' === $amount || 0 === bccomp($amount, '0')) {
continue;
}
if (-1 === bccomp($amount, '0')) {
$amount = bcmul($amount, '-1');
}
if ($this->piggyRepos->canRemoveAmount($piggyBank, $amount)) {
$this->piggyRepos->removeAmount($piggyBank, $amount);
if ($this->piggyRepos->canRemoveAmount($piggyBank, $account, $amount)) {
$this->piggyRepos->removeAmount($piggyBank, $account, $amount);
$total = bcadd($total, $amount);
}
}
if (0 !== bccomp($total, '0')) {
session()->flash(
'success',
(string) trans(
'firefly.removed_amount_from_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name]
['amount' => app('amount')->formatAnything($piggyBank->transactionCurrency, $total, false), 'name' => $piggyBank->name]
)
);
app('preferences')->mark();
return redirect(route('piggy-banks.index'));
}
$amount = (string)$request->get('amount');
session()->flash(
'error',
(string) trans(
'firefly.cannot_remove_from_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)]
['amount' => app('amount')->formatAnything($piggyBank->transactionCurrency, $total, false), 'name' => e($piggyBank->name)]
)
);
@ -184,10 +228,14 @@ class AmountController extends Controller
*/
public function remove(PiggyBank $piggyBank)
{
$repetition = $this->piggyRepos->getRepetition($piggyBank);
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
return view('piggy-banks.remove', compact('piggyBank', 'repetition', 'currency'));
$accounts = [];
foreach ($piggyBank->accounts as $account) {
$accounts[] = [
'account' => $account,
'saved_so_far' => $this->piggyRepos->getCurrentAmount($piggyBank, $account),
];
}
return view('piggy-banks.remove', compact('piggyBank', 'accounts'));
}
/**
@ -197,9 +245,14 @@ class AmountController extends Controller
*/
public function removeMobile(PiggyBank $piggyBank)
{
$repetition = $this->piggyRepos->getRepetition($piggyBank);
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
$accounts = [];
foreach ($piggyBank->accounts as $account) {
$accounts[] = [
'account' => $account,
'saved_so_far' => $this->piggyRepos->getCurrentAmount($piggyBank, $account),
];
}
return view('piggy-banks.remove-mobile', compact('piggyBank', 'repetition', 'currency'));
return view('piggy-banks.remove-mobile', compact('piggyBank', 'accounts'));
}
}

View File

@ -79,22 +79,21 @@ class EditController extends Controller
// Flash some data to fill the form.
$targetDate = $piggyBank->target_date?->format('Y-m-d');
$startDate = $piggyBank->start_date?->format('Y-m-d');
$currency = $this->accountRepository->getAccountCurrency($piggyBank->account);
if (null === $currency) {
$currency = app('amount')->getDefaultCurrency();
}
$preFilled = [
'name' => $piggyBank->name,
'account_id' => $piggyBank->account_id,
'targetamount' => app('steam')->bcround($piggyBank->target_amount, $currency->decimal_places),
'targetdate' => $targetDate,
'startdate' => $startDate,
'target_amount' => app('steam')->bcround($piggyBank->target_amount, $piggyBank->transactionCurrency->decimal_places),
'target_date' => $targetDate,
'start_date' => $startDate,
'accounts' => [],
'object_group' => null !== $piggyBank->objectGroups->first() ? $piggyBank->objectGroups->first()->title : '',
'notes' => null === $note ? '' : $note->text,
];
foreach($piggyBank->accounts as $account) {
$preFilled['accounts'][] = $account->id;
}
if (0 === bccomp($piggyBank->target_amount, '0')) {
$preFilled['targetamount'] = '';
$preFilled['target_amount'] = '';
}
session()->flash('preFilled', $preFilled);

View File

@ -83,6 +83,7 @@ class ShowController extends Controller
$subTitle = $piggyBank->name;
$attachments = $this->piggyRepos->getAttachments($piggyBank);
return view('piggy-banks.show', compact('piggyBank', 'events', 'subTitle', 'piggy', 'attachments'));
}
}

View File

@ -24,6 +24,8 @@ declare(strict_types=1);
namespace FireflyIII\Http\Requests;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
@ -44,15 +46,22 @@ class PiggyBankUpdateRequest extends FormRequest
*/
public function getPiggyBankData(): array
{
return [
$accounts = $this->get('accounts');
$data = [
'name' => $this->convertString('name'),
'startdate' => $this->getCarbonDate('startdate'),
'account_id' => $this->convertInteger('account_id'),
'targetamount' => trim($this->convertString('targetamount')),
'targetdate' => $this->getCarbonDate('targetdate'),
'start_date' => $this->getCarbonDate('start_date'),
'target_amount' => trim($this->convertString('target_amount')),
'target_date' => $this->getCarbonDate('target_date'),
'notes' => $this->stringWithNewlines('notes'),
'object_group_title' => $this->convertString('object_group'),
];
if (!is_array($accounts)) {
$accounts = [];
}
foreach ($accounts as $item) {
$data['accounts'][] = ['account_id' => (int) $item];
}
return $data;
}
/**
@ -65,10 +74,11 @@ class PiggyBankUpdateRequest extends FormRequest
return [
'name' => sprintf('required|min:1|max:255|uniquePiggyBankForUser:%d', $piggy->id),
'account_id' => 'required|belongsToUser:accounts',
'targetamount' => ['nullable', new IsValidPositiveAmount()],
'startdate' => 'date',
'targetdate' => 'date|nullable',
'accounts' => 'required|array',
'accounts.*' => 'required|belongsToUser:accounts',
'target_amount' => ['nullable', new IsValidPositiveAmount()],
'start_date' => 'date',
'target_date' => 'date|nullable',
'order' => 'integer|max:32768|min:1',
'object_group' => 'min:0|max:255',
'notes' => 'min:1|max:32768|nullable',
@ -76,9 +86,49 @@ class PiggyBankUpdateRequest extends FormRequest
}
public function withValidator(Validator $validator): void
{
{ // need to have more than one account.
// accounts need to have the same currency or be multi-currency(?).
$validator->after(
function (Validator $validator): void {
// validate start before end only if both are there.
$data = $validator->getData();
$currency = $this->getCurrencyFromData($data);
if (array_key_exists('accounts', $data) && is_array($data['accounts'])) {
$repository = app(AccountRepositoryInterface::class);
$types = config('firefly.piggy_bank_account_types');
foreach ($data['accounts'] as $value) {
$accountId = (int) $value;
$account = $repository->find($accountId);
if (null !== $account) {
// check currency here.
$accountCurrency = $repository->getAccountCurrency($account);
$isMultiCurrency = $repository->getMetaValue($account, 'is_multi_currency');
if ($accountCurrency->id !== $currency->id && 'true' !== $isMultiCurrency) {
$validator->errors()->add('accounts', trans('validation.invalid_account_currency'));
}
$type = $account->accountType->type;
if (!in_array($type, $types, true)) {
$validator->errors()->add('accounts', trans('validation.invalid_account_type'));
}
}
}
}
}
);
if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray());
}
}
private function getCurrencyFromData(array $data): TransactionCurrency
{
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
return app('amount')->getDefaultCurrency();
}
return $currency;
}
}

View File

@ -32,6 +32,7 @@ use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
@ -159,9 +160,9 @@ class Account extends Model
return $this->morphToMany(ObjectGroup::class, 'object_groupable');
}
public function piggyBanks(): HasMany
public function piggyBanks(): BelongsToMany
{
return $this->hasMany(PiggyBank::class);
return $this->belongsToMany(PiggyBank::class);
}
public function scopeAccountTypeIn(EloquentBuilder $query, array $types): void

View File

@ -27,12 +27,14 @@ namespace FireflyIII\Repositories\PiggyBank;
use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\PiggyBankFactory;
use FireflyIII\Models\Account;
use FireflyIII\Models\Note;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Support\Facades\Log;
/**
* Trait ModifiesPiggyBanks
@ -55,30 +57,42 @@ trait ModifiesPiggyBanks
}
}
public function removeAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool
public function removeAmount(PiggyBank $piggyBank,Account $account, string $amount, ?TransactionJournal $journal = null): bool
{
$repetition = $this->getRepetition($piggyBank);
if (null === $repetition) {
return false;
}
$repetition->current_amount = bcsub($repetition->current_amount, $amount);
$repetition->save();
$currentAmount = $this->getCurrentAmount($piggyBank, $account);
$pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot;
$pivot->current_amount = bcsub($currentAmount, $amount);
$pivot->save();
app('log')->debug('addAmount [a]: Trigger change for negative amount.');
app('log')->debug('removeAmount [a]: Trigger change for negative amount.');
event(new ChangedAmount($piggyBank, bcmul($amount, '-1'), $journal, null));
return true;
}
public function addAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool
public function removeAmountFromAll(PiggyBank $piggyBank, string $amount): void
{
$repetition = $this->getRepetition($piggyBank);
if (null === $repetition) {
return false;
foreach($piggyBank->accounts as $account) {
$current = $account->pivot->current_amount;
// if this account contains more than the amount, remove the amount and return.
if (1 === bccomp($current, $amount)) {
$this->removeAmount($piggyBank, $account, $amount);
return;
}
$currentAmount = $repetition->current_amount ?? '0';
$repetition->current_amount = bcadd($currentAmount, $amount);
$repetition->save();
// if this account contains less than the amount, remove the current amount, update the amount and continue.
if (bccomp($current, $amount) < 1) {
$this->removeAmount($piggyBank, $account, $current);
$amount = bcsub($amount, $current);
}
}
}
public function addAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool
{
$currentAmount = $this->getCurrentAmount($piggyBank, $account);
$pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot;
$pivot->current_amount = bcadd($currentAmount, $amount);
$pivot->save();
app('log')->debug('addAmount [b]: Trigger change for positive amount.');
event(new ChangedAmount($piggyBank, $amount, $journal, null));
@ -86,37 +100,36 @@ trait ModifiesPiggyBanks
return true;
}
public function canAddAmount(PiggyBank $piggyBank, string $amount): bool
public function canAddAmount(PiggyBank $piggyBank, Account $account, string $amount): bool
{
$today = today(config('app.timezone'));
$leftOnAccount = $this->leftOnAccount($piggyBank, $today);
$savedSoFar = $this->getRepetition($piggyBank)->current_amount;
Log::debug('Now in canAddAmount');
$today = today(config('app.timezone'))->endOfDay();
$leftOnAccount = $this->leftOnAccount($piggyBank, $account, $today);
$savedSoFar = $this->getCurrentAmount($piggyBank);
$maxAmount = $leftOnAccount;
$leftToSave = null;
app('log')->debug(sprintf('Left on account: %s on %s', $leftOnAccount, $today->format('Y-m-d H:i:s')));
app('log')->debug(sprintf('Saved so far: %s', $savedSoFar));
if (0 !== bccomp($piggyBank->target_amount, '0')) {
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
$maxAmount = 1 === bccomp($leftOnAccount, $leftToSave) ? $leftToSave : $leftOnAccount;
app('log')->debug(sprintf('Left to save: %s', $leftToSave));
app('log')->debug(sprintf('Maximum amount: %s', $maxAmount));
}
$compare = bccomp($amount, $maxAmount);
$result = $compare <= 0;
app('log')->debug(sprintf('Left on account: %s on %s', $leftOnAccount, $today->format('Y-m-d')));
app('log')->debug(sprintf('Saved so far: %s', $savedSoFar));
app('log')->debug(sprintf('Left to save: %s', $leftToSave));
app('log')->debug(sprintf('Maximum amount: %s', $maxAmount));
app('log')->debug(sprintf('Compare <= 0? %d, so %s', $compare, var_export($result, true)));
app('log')->debug(sprintf('Compare <= 0? %d, so canAddAmount is %s', $compare, var_export($result, true)));
return $result;
}
public function canRemoveAmount(PiggyBank $piggyBank, string $amount): bool
public function canRemoveAmount(PiggyBank $piggyBank, Account $account, string $amount): bool
{
$repetition = $this->getRepetition($piggyBank);
if (null === $repetition) {
return false;
}
$savedSoFar = $repetition->current_amount;
$savedSoFar = $this->getCurrentAmount($piggyBank, $account);
return bccomp($amount, $savedSoFar) <= 0;
}
@ -244,17 +257,24 @@ trait ModifiesPiggyBanks
$this->setOrder($piggyBank, $newOrder);
}
// update the accounts
$factory = new PiggyBankFactory();
$factory->user = $this->user;
$factory->linkToAccountIds($piggyBank, $data['accounts']);
// if the piggy bank is now smaller than the current relevant rep,
// remove money from the rep.
$repetition = $this->getRepetition($piggyBank);
if (null !== $repetition && $repetition->current_amount > $piggyBank->target_amount && 0 !== bccomp($piggyBank->target_amount, '0')) {
$difference = bcsub($piggyBank->target_amount, $repetition->current_amount);
$currentAmount = $this->getCurrentAmount($piggyBank);
if (1 === bccomp($currentAmount, '100') && 0 !== bccomp($piggyBank->target_amount, '0')) {
$difference = bcsub($piggyBank->target_amount, $currentAmount);
// an amount will be removed, create "negative" event:
event(new ChangedAmount($piggyBank, $difference, null, null));
$repetition->current_amount = $piggyBank->target_amount;
$repetition->save();
// question is, from which account(s) to remove the difference?
// solution: just start from the top until there is no more money left to remove.
$this->removeAmountFromAll($piggyBank, app('steam')->positive($difference));
}
// update using name:
@ -295,22 +315,19 @@ trait ModifiesPiggyBanks
if (array_key_exists('name', $data) && '' !== $data['name']) {
$piggyBank->name = $data['name'];
}
if (array_key_exists('account_id', $data) && 0 !== $data['account_id']) {
$piggyBank->account_id = (int)$data['account_id'];
if (array_key_exists('target_amount', $data) && '' !== $data['target_amount']) {
$piggyBank->target_amount = $data['target_amount'];
}
if (array_key_exists('targetamount', $data) && '' !== $data['targetamount']) {
$piggyBank->target_amount = $data['targetamount'];
}
if (array_key_exists('targetamount', $data) && '' === $data['targetamount']) {
if (array_key_exists('target_amount', $data) && '' === $data['target_amount']) {
$piggyBank->target_amount = '0';
}
if (array_key_exists('targetdate', $data) && '' !== $data['targetdate']) {
$piggyBank->target_date = $data['targetdate'];
$piggyBank->target_date_tz = $data['targetdate']?->format('e');
if (array_key_exists('target_date', $data) && '' !== $data['target_date']) {
$piggyBank->target_date = $data['target_date'];
$piggyBank->target_date_tz = $data['target_date']?->format('e');
}
if (array_key_exists('startdate', $data)) {
$piggyBank->start_date = $data['startdate'];
$piggyBank->start_date_tz = $data['targetdate']?->format('e');
if (array_key_exists('start_date', $data)) {
$piggyBank->start_date = $data['start_date'];
$piggyBank->start_date_tz = $data['target_date']?->format('e');
}
$piggyBank->save();

View File

@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\PiggyBankFactory;
use FireflyIII\Models\Account;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Note;
use FireflyIII\Models\PiggyBank;
@ -114,22 +115,28 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
/**
* Get current amount saved in piggy bank.
*/
public function getCurrentAmount(PiggyBank $piggyBank): string
public function getCurrentAmount(PiggyBank $piggyBank, ?Account $account = null): string
{
$sum = '0';
foreach ($piggyBank->accounts as $account) {
$amount = (string) $account->pivot->current_amount;
foreach ($piggyBank->accounts as $current) {
if(null !== $account && $account->id !== $current->id) {
continue;
}
$amount = (string) $current->pivot->current_amount;
$amount = '' === $amount ? '0' : $amount;
$sum = bcadd($sum, $amount);
}
Log::debug(sprintf('Current amount in piggy bank #%d ("%s") is %s', $piggyBank->id, $piggyBank->name, $sum));
return $sum;
}
public function getRepetition(PiggyBank $piggyBank): ?PiggyBankRepetition
public function getRepetition(PiggyBank $piggyBank, bool $overrule = false): ?PiggyBankRepetition
{
if (false === $overrule) {
throw new FireflyException('[b] Piggy bank repetitions are EOL.');
}
Log::warning('Piggy bank repetitions are EOL.');
return $piggyBank->piggyBankRepetitions()->first();
}
@ -286,8 +293,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
'objectGroups',
]
)
->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*'])
;
->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*']);
}
/**
@ -320,21 +326,22 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
/**
* Get for piggy account what is left to put in piggies.
*/
public function leftOnAccount(PiggyBank $piggyBank, Carbon $date): string
public function leftOnAccount(PiggyBank $piggyBank, Account $account, Carbon $date): string
{
$balance = app('steam')->balanceIgnoreVirtual($piggyBank->account, $date);
Log::debug(sprintf('leftOnAccount("%s","%s","%s")', $piggyBank->name, $account->name, $date->format('Y-m-d H:i:s')));
$balance = app('steam')->balanceConvertedIgnoreVirtual($account, $date, $piggyBank->transactionCurrency);
Log::debug(sprintf('Balance is: %s', $balance));
/** @var Collection $piggies */
$piggies = $piggyBank->account->piggyBanks;
$piggies = $account->piggyBanks;
/** @var PiggyBank $current */
foreach ($piggies as $current) {
$repetition = $this->getRepetition($current);
if (null !== $repetition) {
$balance = bcsub($balance, $repetition->current_amount);
$amount = $this->getCurrentAmount($current, $account);
$balance = bcsub($balance, $amount);
Log::debug(sprintf('Piggy bank: #%d with amount %s, balance is now %s', $current->id, $amount, $balance));
}
}
Log::debug(sprintf('Final balance is: %s', $balance));
return $balance;
}
@ -345,8 +352,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
$search->whereLike('piggy_banks.name', sprintf('%%%s%%', $query));
}
$search->orderBy('piggy_banks.order', 'ASC')
->orderBy('piggy_banks.name', 'ASC')
;
->orderBy('piggy_banks.name', 'ASC');
return $search->take($limit)->get();
}

View File

@ -25,6 +25,7 @@ namespace FireflyIII\Repositories\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\TransactionJournal;
@ -37,13 +38,13 @@ use Illuminate\Support\Collection;
*/
interface PiggyBankRepositoryInterface
{
public function addAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool;
public function addAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool;
public function addAmountToRepetition(PiggyBankRepetition $repetition, string $amount, TransactionJournal $journal): void;
public function canAddAmount(PiggyBank $piggyBank, string $amount): bool;
public function canAddAmount(PiggyBank $piggyBank, Account $account, string $amount): bool;
public function canRemoveAmount(PiggyBank $piggyBank, string $amount): bool;
public function canRemoveAmount(PiggyBank $piggyBank, Account $account, string $amount): bool;
/**
* Destroy piggy bank.
@ -68,7 +69,10 @@ interface PiggyBankRepositoryInterface
/**
* Get current amount saved in piggy bank.
*/
public function getCurrentAmount(PiggyBank $piggyBank): string;
public function getCurrentAmount(PiggyBank $piggyBank, ?Account $account = null): string;
/**
* Get current amount saved in piggy bank.
*/
/**
* Get all events.
@ -97,7 +101,7 @@ interface PiggyBankRepositoryInterface
*/
public function getPiggyBanksWithAmount(): Collection;
public function getRepetition(PiggyBank $piggyBank): ?PiggyBankRepetition;
public function getRepetition(PiggyBank $piggyBank, bool $overrule = false): ?PiggyBankRepetition;
/**
* Returns the suggested amount the user should save per month, or "".
@ -107,9 +111,10 @@ interface PiggyBankRepositoryInterface
/**
* Get for piggy account what is left to put in piggies.
*/
public function leftOnAccount(PiggyBank $piggyBank, Carbon $date): string;
public function leftOnAccount(PiggyBank $piggyBank,Account $account, Carbon $date): string;
public function removeAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool;
public function removeAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool;
public function removeAmountFromAll(PiggyBank $piggyBank, string $amount): void;
public function removeObjectGroup(PiggyBank $piggyBank): PiggyBank;

View File

@ -44,7 +44,7 @@ class Steam
*/
public function balanceIgnoreVirtual(Account $account, Carbon $date): string
{
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
throw new FireflyException('Deprecated method balanceIgnoreVirtual.');
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
@ -54,8 +54,7 @@ class Steam
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currencyId)
->get(['transactions.amount'])->toArray()
;
->get(['transactions.amount'])->toArray();
$nativeBalance = $this->sumTransactions($transactions, 'amount');
// get all balances in foreign currency:
@ -64,14 +63,33 @@ class Steam
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.foreign_currency_id', $currencyId)
->where('transactions.transaction_currency_id', '!=', $currencyId)
->get(['transactions.foreign_amount'])->toArray()
;
->get(['transactions.foreign_amount'])->toArray();
$foreignBalance = $this->sumTransactions($transactions, 'foreign_amount');
return bcadd($nativeBalance, $foreignBalance);
}
public function balanceConvertedIgnoreVirtual(Account $account, Carbon $date, TransactionCurrency $currency): string
{
$balance = $this->balanceConverted($account, $date, $currency);
$virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance;
// currency of account
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
$accountCurrency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
if ($accountCurrency->id !== $currency->id && 0 !== bccomp($virtual, '0')) {
// convert amount to given currency.
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$converter = new ExchangeRateConverter();
$virtual = $converter->convert($accountCurrency, $currency, $date, $virtual);
}
return bcsub($balance, $virtual);
}
public function sumTransactions(array $transactions, string $key): string
{
$sum = '0';
@ -140,8 +158,7 @@ class Steam
'transactions.foreign_currency_id',
\DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'),
]
)
;
);
$currentBalance = $startBalance;
@ -187,8 +204,7 @@ class Steam
->orderBy('transaction_journals.date', 'desc')
->orderBy('transaction_journals.order', 'asc')
->orderBy('transaction_journals.description', 'desc')
->orderBy('transactions.amount', 'desc')
;
->orderBy('transactions.amount', 'desc');
if (null !== $currency) {
$query->where('transactions.transaction_currency_id', $currency->id);
$query->limit(1);
@ -241,8 +257,7 @@ class Steam
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currency->id)
->get(['transactions.amount'])->toArray()
;
->get(['transactions.amount'])->toArray();
$nativeBalance = $this->sumTransactions($transactions, 'amount');
// get all balances in foreign currency:
$transactions = $account->transactions()
@ -250,8 +265,7 @@ class Steam
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.foreign_currency_id', $currency->id)
->where('transactions.transaction_currency_id', '!=', $currency->id)
->get(['transactions.foreign_amount'])->toArray()
;
->get(['transactions.foreign_amount'])->toArray();
$foreignBalance = $this->sumTransactions($transactions, 'foreign_amount');
$balance = bcadd($nativeBalance, $foreignBalance);
$virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance;
@ -310,8 +324,7 @@ class Steam
'transactions.foreign_currency_id',
'transactions.foreign_amount',
]
)->toArray()
;
)->toArray();
// loop the set and convert if necessary:
$currentBalance = $startBalance;
@ -425,16 +438,14 @@ class Steam
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currency->id)
->whereNull('transactions.foreign_currency_id')
->get(['transaction_journals.date', 'transactions.amount'])->toArray()
;
->get(['transaction_journals.date', 'transactions.amount'])->toArray();
Log::debug(sprintf('%d transaction(s) in set #1', count($new[0])));
$existing[] = $account->transactions() // 2
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $native->id)
->whereNull('transactions.foreign_currency_id')
->get(['transactions.amount'])->toArray()
;
->get(['transactions.amount'])->toArray();
Log::debug(sprintf('%d transaction(s) in set #2', count($existing[0])));
$new[] = $account->transactions() // 3
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
@ -442,16 +453,14 @@ class Steam
->where('transactions.transaction_currency_id', '!=', $currency->id)
->where('transactions.transaction_currency_id', '!=', $native->id)
->whereNull('transactions.foreign_currency_id')
->get(['transaction_journals.date', 'transactions.amount'])->toArray()
;
->get(['transaction_journals.date', 'transactions.amount'])->toArray();
Log::debug(sprintf('%d transactions in set #3', count($new[1])));
$existing[] = $account->transactions() // 4
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.foreign_currency_id', $native->id)
->whereNotNull('transactions.foreign_amount')
->get(['transactions.foreign_amount'])->toArray()
;
->get(['transactions.foreign_amount'])->toArray();
Log::debug(sprintf('%d transactions in set #4', count($existing[1])));
$new[] = $account->transactions()// 5
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
@ -459,8 +468,7 @@ class Steam
->where('transactions.transaction_currency_id', $currency->id)
->where('transactions.foreign_currency_id', '!=', $native->id)
->whereNotNull('transactions.foreign_amount')
->get(['transaction_journals.date', 'transactions.amount'])->toArray()
;
->get(['transaction_journals.date', 'transactions.amount'])->toArray();
Log::debug(sprintf('%d transactions in set #5', count($new[2])));
$new[] = $account->transactions()// 6
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
@ -468,8 +476,7 @@ class Steam
->where('transactions.transaction_currency_id', '!=', $currency->id)
->where('transactions.foreign_currency_id', '!=', $native->id)
->whereNotNull('transactions.foreign_amount')
->get(['transaction_journals.date', 'transactions.amount'])->toArray()
;
->get(['transaction_journals.date', 'transactions.amount'])->toArray();
Log::debug(sprintf('%d transactions in set #6', count($new[3])));
// process both sets of transactions. Of course, no need to convert set "existing".
@ -644,8 +651,7 @@ class Steam
$query = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->groupBy('transactions.transaction_currency_id')
;
->groupBy('transactions.transaction_currency_id');
$balances = $query->get(['transactions.transaction_currency_id', \DB::raw('SUM(transactions.amount) as sum_for_currency')]); // @phpstan-ignore-line
$return = [];

View File

@ -26,6 +26,7 @@ namespace FireflyIII\TransactionRules\Actions;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\Transaction;
@ -81,6 +82,7 @@ class UpdatePiggybank implements ActionInterface
if ($source->account_id === $piggyBank->account_id) {
app('log')->debug('Piggy bank account is linked to source, so remove amount from piggy bank.');
throw new FireflyException('Reference the correct account here.');
$this->removeAmount($piggyBank, $journal, $journalObj, $destination->amount);
event(
@ -161,6 +163,7 @@ class UpdatePiggybank implements ActionInterface
}
// make sure we can remove amount:
throw new FireflyException('Reference the correct account here.');
if (false === $repository->canRemoveAmount($piggyBank, $amount)) {
app('log')->warning(sprintf('Cannot remove %s from piggy bank.', $amount));
event(new RuleActionFailedOnArray($this->action, $array, trans('rules.cannot_remove_from_piggy', ['amount' => $amount, 'name' => $piggyBank->name])));
@ -169,6 +172,7 @@ class UpdatePiggybank implements ActionInterface
}
app('log')->debug(sprintf('Will now remove %s from piggy bank.', $amount));
throw new FireflyException('Reference the correct account here.');
$repository->removeAmount($piggyBank, $amount, $journal);
}
@ -199,6 +203,7 @@ class UpdatePiggybank implements ActionInterface
}
// make sure we can add amount:
throw new FireflyException('Reference the correct account here.');
if (false === $repository->canAddAmount($piggyBank, $amount)) {
app('log')->warning(sprintf('Cannot add %s to piggy bank.', $amount));
event(new RuleActionFailedOnArray($this->action, $array, trans('rules.cannot_add_to_piggy', ['amount' => $amount, 'name' => $piggyBank->name])));

View File

@ -78,7 +78,7 @@ class PiggyBankTransformer extends AbstractTransformer
// get currently saved amount:
$currency = $piggyBank->transactionCurrency;
$currentAmount = app('steam')->bcround($this->piggyRepos->getCurrentAmount($piggyBank), $currency->decimal_places);
$currentAmount = $this->piggyRepos->getCurrentAmount($piggyBank);
// Amounts, depending on 0.0 state of target amount
$percentage = null;

View File

@ -106,6 +106,10 @@ class User extends Authenticatable
return $this->hasMany(Account::class);
}
public function piggyBanks() {
throw new FireflyException('Method no longer supported.');
}
/**
* Link to attachments
*/

View File

@ -28,8 +28,8 @@ return [
'slack' => ['enabled' => true, 'ui_configurable' => 1],
'ntfy' => ['enabled' => true, 'ui_configurable' => 1],
'pushover' => ['enabled' => true, 'ui_configurable' => 1],
'gotify' => ['enabled' => false, 'ui_configurable' => 0],
'pushbullet' => ['enabled' => false, 'ui_configurable' => 0],
// 'gotify' => ['enabled' => false, 'ui_configurable' => 0],
// 'pushbullet' => ['enabled' => false, 'ui_configurable' => 0],
],
'notifications' => [
'user' => [

View File

@ -25,9 +25,9 @@
<td style="text-align: right;">
{% if event.amount < 0 %}
<span class="text-danger money-negative">{{ trans('firefly.removed_amount', {amount: formatAmountByAccount(event.piggyBank.account, event.amount, false)})|raw }}</span>
<span class="text-danger money-negative">{{ trans('firefly.removed_amount', {amount: formatAmountBySymbol(event.amount,event.piggyBank.transactionCurrency.symbol, false)})|raw }}</span>
{% else %}
<span class="text-success money-positive">{{ trans('firefly.added_amount', {amount: formatAmountByAccount(event.piggyBank.account, event.amount, false)})|raw }}</span>
<span class="text-success money-positive">{{ trans('firefly.added_amount', {amount: formatAmountBySymbol(event.amount, event.piggyBank.transactionCurrency.symbol, false)})|raw }}</span>
{% endif %}
</td>
</tr>

View File

@ -14,16 +14,16 @@
<h3 class="box-title">{{ trans('firefly.add_money_to_piggy', {name: piggyBank.name}) }}</h3>
</div>
<div class="box-body">
{% if maxAmount > 0 %}
<p>
{{ 'max_amount_add'|_ }}: {{ formatAmountByCurrency(currency,maxAmount) }}.
</p>
{% if total > 0 %}
{% for account in accounts %}
<strong>{{ account.account.name }} ({{ 'max_amount_add'|_ }}: {{ formatAmountByCurrency(piggyBank.transactionCurrency, account.max_amount) }})</strong>
<div class="input-group">
<div class="input-group-addon">{{ currency.symbol|raw }}</div>
<input step="any" class="form-control" id="amount" autocomplete="off" name="amount" max="{{ maxAmount|round(2) }}"
type="number"/>
<div class="input-group-addon">{{ piggyBank.transactionCurrency.symbol|raw }}</div>
<input step="any" min="0" class="form-control" id="amount_{{ account.account.id }}" autocomplete="off" name="amount[{{ account.account.id }}]" max="{{ account.max_amount|round(piggyBank.transactionCurrency.decimal_places) }}" type="number"/>
</div>
{% endfor %}
<p>
&nbsp;
</p>

View File

@ -5,19 +5,17 @@
</button>
<h4 class="modal-title">{{ trans('firefly.add_money_to_piggy_title', {name: piggyBank.name}) }}</h4>
</div>
{% if maxAmount > 0 %}
{% if total > 0 %}
<form style="display: inline;" id="add" action="{{ route('piggy-banks.add', piggyBank.id) }}" method="POST">
<div class="modal-body">
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
<p>
{{ 'max_amount_add'|_ }}: {{ formatAmountByCurrency(currency,maxAmount) }}.
</p>
{% for account in accounts %}
<strong>{{ account.account.name }} ({{ 'max_amount_add'|_ }}: {{ formatAmountByCurrency(piggyBank.transactionCurrency, account.max_amount) }})</strong>
<div class="input-group">
<div class="input-group-addon">{{ currency.symbol|raw }}</div>
<input step="any" class="form-control" id="amount" autocomplete="off" name="amount" max="{{ maxAmount|round(currency.decimal_places) }}" type="number"/>
<div class="input-group-addon">{{ piggyBank.transactionCurrency.symbol|raw }}</div>
<input step="any" min="0" class="form-control" id="amount_{{ account.account.id }}" autocomplete="off" name="amount[{{ account.account.id }}]" max="{{ account.max_amount|round(piggyBank.transactionCurrency.decimal_places) }}" type="number"/>
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'close'|_ }}</button>

View File

@ -22,8 +22,9 @@
<div class="box-body">
{{ ExpandedForm.text('name') }}
{{ AccountForm.assetAccountList('account_id', null, {label: 'saveOnAccount'|_ }) }}
{{ ExpandedForm.amountNoCurrency('targetamount') }}
{{ ExpandedForm.amountNoCurrency('target_amount') }}
{{ CurrencyForm.currencyList('transaction_currency_id', null, {helpText:'piggy_default_currency'|_}) }}
{{ AccountForm.assetLiabilityMultiAccountList('accounts', preFilled.accounts, {label: 'saveOnAccounts'|_, helpText: 'piggy_account_currency_match'|_ }) }}
</div>
</div>

View File

@ -14,15 +14,17 @@
</div>
<div class="box-body">
{% for account in accounts %}
<p>
{{ 'max_amount_remove'|_ }}: {{ formatAmountByCurrency(currency, repetition.currentamount) }}.
{{ account.account.name }}: {{ 'max_amount_remove'|_ }}: {{ formatAmountByCurrency(piggyBank.transactionCurrency, account.saved_so_far) }}.
</p>
<div class="input-group">
<div class="input-group-addon">{{ currency.symbol|raw }}</div>
<input step="any" class="form-control" id="amount" autocomplete="off" name="amount" max="{{ repetition.currentamount }}"
type="number"/>
<div class="input-group-addon">{{ piggyBank.transactionCurrency.symbol|raw }}</div>
<input step="any" class="form-control" id="amount_{{ account.account.id }}" autocomplete="off" name="amount[{{ account.account.id }}]" max="{{ account.saved_so_far }}"
type="number">
</div>
{% endfor %}
<p>
&nbsp;
</p>

View File

@ -10,15 +10,16 @@
</div>
<div class="modal-body">
{% for account in accounts %}
<p>
{{ 'max_amount_remove'|_ }}: {{ formatAmountByCurrency(currency, repetition.currentamount) }}.
{{ account.account.name }}: {{ 'max_amount_remove'|_ }}: {{ formatAmountByCurrency(piggyBank.transactionCurrency, account.saved_so_far) }}.
</p>
<div class="input-group">
<div class="input-group-addon">{{ currency.symbol|raw }}</div>
<input step="any" class="form-control" id="amount" autocomplete="off" name="amount" max="{{ repetition.currentamount }}"
<div class="input-group-addon">{{ piggyBank.transactionCurrency.symbol|raw }}</div>
<input step="any" class="form-control" id="amount_{{ account.account.id }}" autocomplete="off" name="amount[{{ account.account.id }}]" max="{{ account.saved_so_far }}"
type="number">
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'close'|_ }}</button>

View File

@ -33,8 +33,12 @@
<div class="box-body no-padding">
<table class="table table-responsive table-hover" id="piggyDetails">
<tr>
<td style="width:40%;">{{ 'account'|_ }}</td>
<td><a href="{{ route('accounts.show', piggyBank.account_id) }}">{{ piggyBank.account.name }}</a></td>
<td style="width:40%;">{{ 'saveOnAccounts'|_ }}</td>
<td>
{% for account in piggy.accounts %}
<a href="{{ route('accounts.show', account.id) }}">{{ account.name }}</a><br>
{% endfor %}
</td>
</tr>
{% if piggy.object_group_title %}
<tr>