mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-08-19 01:14:43 -05:00
🤖 Auto commit for release 'develop' on 2026-03-14
This commit is contained in:
@@ -46,7 +46,7 @@ final class DestroyController extends Controller
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->middleware(function ($request, $next) {
|
$this->middleware(function ($request, $next) {
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$this->repository = app(LinkTypeRepositoryInterface::class);
|
$this->repository = app(LinkTypeRepositoryInterface::class);
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ final class StoreController extends Controller
|
|||||||
{
|
{
|
||||||
use TransactionFilter;
|
use TransactionFilter;
|
||||||
|
|
||||||
private JournalRepositoryInterface $journalRepository;
|
private JournalRepositoryInterface $journalRepository;
|
||||||
private LinkTypeRepositoryInterface $repository;
|
private LinkTypeRepositoryInterface $repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,7 +54,7 @@ final class StoreController extends Controller
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->middleware(function ($request, $next) {
|
$this->middleware(function ($request, $next) {
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$this->repository = app(LinkTypeRepositoryInterface::class);
|
$this->repository = app(LinkTypeRepositoryInterface::class);
|
||||||
$this->journalRepository = app(JournalRepositoryInterface::class);
|
$this->journalRepository = app(JournalRepositoryInterface::class);
|
||||||
@@ -76,22 +76,22 @@ final class StoreController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(StoreRequest $request): JsonResponse
|
public function store(StoreRequest $request): JsonResponse
|
||||||
{
|
{
|
||||||
$manager = $this->getManager();
|
$manager = $this->getManager();
|
||||||
$data = $request->getAll();
|
$data = $request->getAll();
|
||||||
$inward = $this->journalRepository->find($data['inward_id'] ?? 0);
|
$inward = $this->journalRepository->find($data['inward_id'] ?? 0);
|
||||||
$outward = $this->journalRepository->find($data['outward_id'] ?? 0);
|
$outward = $this->journalRepository->find($data['outward_id'] ?? 0);
|
||||||
if (!$inward instanceof TransactionJournal || !$outward instanceof TransactionJournal) {
|
if (!$inward instanceof TransactionJournal || !$outward instanceof TransactionJournal) {
|
||||||
throw new FireflyException('200024: Source or destination does not exist.');
|
throw new FireflyException('200024: Source or destination does not exist.');
|
||||||
}
|
}
|
||||||
$data['direction'] = 'inward';
|
$data['direction'] = 'inward';
|
||||||
|
|
||||||
$journalLink = $this->repository->storeLink($data, $inward, $outward);
|
$journalLink = $this->repository->storeLink($data, $inward, $outward);
|
||||||
|
|
||||||
/** @var TransactionLinkTransformer $transformer */
|
/** @var TransactionLinkTransformer $transformer */
|
||||||
$transformer = app(TransactionLinkTransformer::class);
|
$transformer = app(TransactionLinkTransformer::class);
|
||||||
$transformer->setParameters($this->parameters);
|
$transformer->setParameters($this->parameters);
|
||||||
|
|
||||||
$resource = new Item($journalLink, $transformer, 'transaction_links');
|
$resource = new Item($journalLink, $transformer, 'transaction_links');
|
||||||
|
|
||||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ use League\Fractal\Resource\Item;
|
|||||||
*/
|
*/
|
||||||
final class UpdateController extends Controller
|
final class UpdateController extends Controller
|
||||||
{
|
{
|
||||||
private JournalRepositoryInterface $journalRepository;
|
private JournalRepositoryInterface $journalRepository;
|
||||||
private LinkTypeRepositoryInterface $repository;
|
private LinkTypeRepositoryInterface $repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +50,7 @@ final class UpdateController extends Controller
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->middleware(function ($request, $next) {
|
$this->middleware(function ($request, $next) {
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$this->repository = app(LinkTypeRepositoryInterface::class);
|
$this->repository = app(LinkTypeRepositoryInterface::class);
|
||||||
$this->journalRepository = app(JournalRepositoryInterface::class);
|
$this->journalRepository = app(JournalRepositoryInterface::class);
|
||||||
@@ -78,7 +78,7 @@ final class UpdateController extends Controller
|
|||||||
$transformer = app(TransactionLinkTransformer::class);
|
$transformer = app(TransactionLinkTransformer::class);
|
||||||
$transformer->setParameters($this->parameters);
|
$transformer->setParameters($this->parameters);
|
||||||
|
|
||||||
$resource = new Item($journalLink, $transformer, 'transaction_links');
|
$resource = new Item($journalLink, $transformer, 'transaction_links');
|
||||||
|
|
||||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,9 +98,10 @@ class RemovesLinksToDeletedObjects extends Command
|
|||||||
// count and clean up available budgets in currencies with no budget limits.
|
// count and clean up available budgets in currencies with no budget limits.
|
||||||
// this is not entirely the place for it but OK.
|
// this is not entirely the place for it but OK.
|
||||||
/** @var AvailableBudgetRepositoryInterface $repository */
|
/** @var AvailableBudgetRepositoryInterface $repository */
|
||||||
$repository = app(AvailableBudgetRepositoryInterface::class);
|
$repository = app(AvailableBudgetRepositoryInterface::class);
|
||||||
|
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
foreach(User::get() as $user) {
|
foreach (User::get() as $user) {
|
||||||
$repository->setUser($user);
|
$repository->setUser($user);
|
||||||
$repository->cleanup();
|
$repository->cleanup();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,10 @@ class RollbacksSingleMigration extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($res) {
|
if ($res) {
|
||||||
DB::table('migrations')->where('id', (int) $entry->id)->delete();
|
DB::table('migrations')
|
||||||
|
->where('id', (int) $entry->id)
|
||||||
|
->delete()
|
||||||
|
;
|
||||||
$this->friendlyInfo(sprintf('Database migration #%d ("%s") is deleted.', $entry->id, $entry->migration));
|
$this->friendlyInfo(sprintf('Database migration #%d ("%s") is deleted.', $entry->id, $entry->migration));
|
||||||
$this->friendlyLine('');
|
$this->friendlyLine('');
|
||||||
$this->friendlyLine('Try running "php artisan migrate" now.');
|
$this->friendlyLine('Try running "php artisan migrate" now.');
|
||||||
|
|||||||
@@ -107,7 +107,10 @@ class RepairsPostgresSequences extends Command
|
|||||||
$this->friendlyLine(sprintf('Checking the next id sequence for table "%s".', $tableToCheck));
|
$this->friendlyLine(sprintf('Checking the next id sequence for table "%s".', $tableToCheck));
|
||||||
|
|
||||||
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
|
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
|
||||||
$nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
|
$nextId = DB::table($tableToCheck)
|
||||||
|
->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))
|
||||||
|
->first()
|
||||||
|
;
|
||||||
if (null === $nextId) {
|
if (null === $nextId) {
|
||||||
$this->friendlyInfo(sprintf('nextval is NULL for table "%s", go to next table.', $tableToCheck));
|
$this->friendlyInfo(sprintf('nextval is NULL for table "%s", go to next table.', $tableToCheck));
|
||||||
|
|
||||||
@@ -117,7 +120,10 @@ class RepairsPostgresSequences extends Command
|
|||||||
if ($nextId->nextval < $highestId->max) {
|
if ($nextId->nextval < $highestId->max) {
|
||||||
DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max));
|
DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max));
|
||||||
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
|
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
|
||||||
$nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
|
$nextId = DB::table($tableToCheck)
|
||||||
|
->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))
|
||||||
|
->first()
|
||||||
|
;
|
||||||
if ($nextId->nextval > $highestId->max) {
|
if ($nextId->nextval > $highestId->max) {
|
||||||
$this->friendlyInfo(sprintf('Table "%s" autoincrement corrected.', $tableToCheck));
|
$this->friendlyInfo(sprintf('Table "%s" autoincrement corrected.', $tableToCheck));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,7 +205,12 @@ class InterestingMessage
|
|||||||
|
|
||||||
// send message about newly created transaction group.
|
// send message about newly created transaction group.
|
||||||
/** @var null|TransactionGroup $group */
|
/** @var null|TransactionGroup $group */
|
||||||
$group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int) $transactionGroupId);
|
$group = auth()
|
||||||
|
->user()
|
||||||
|
->transactionGroups()
|
||||||
|
->with(['transactionJournals', 'transactionJournals.transactionType'])
|
||||||
|
->find((int) $transactionGroupId)
|
||||||
|
;
|
||||||
|
|
||||||
if (null === $group) {
|
if (null === $group) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class SecureHeaders
|
|||||||
"default-src 'none'",
|
"default-src 'none'",
|
||||||
"object-src 'none'",
|
"object-src 'none'",
|
||||||
sprintf("script-src 'unsafe-eval' 'strict-dynamic' 'nonce-%1s'", $nonce),
|
sprintf("script-src 'unsafe-eval' 'strict-dynamic' 'nonce-%1s'", $nonce),
|
||||||
// sprintf("style-src 'self' 'nonce-%1s' https://10.0.0.15:5173/", $nonce), // safe variant
|
// sprintf("style-src 'self' 'nonce-%1s' https://10.0.0.15:5173/", $nonce), // safe variant
|
||||||
"style-src 'self' 'unsafe-inline' https://10.0.0.15:5173/", // unsafe variant
|
"style-src 'self' 'unsafe-inline' https://10.0.0.15:5173/", // unsafe variant
|
||||||
"base-uri 'self'",
|
"base-uri 'self'",
|
||||||
"form-action 'self'",
|
"form-action 'self'",
|
||||||
|
|||||||
@@ -73,7 +73,11 @@ class Preference extends Model
|
|||||||
|
|
||||||
// try again with ID, but this time don't care about the preferred user_group_id
|
// try again with ID, but this time don't care about the preferred user_group_id
|
||||||
if (null === $preference) {
|
if (null === $preference) {
|
||||||
$preference = $user->preferences()->where('id', (int) $value)->first();
|
$preference = $user
|
||||||
|
->preferences()
|
||||||
|
->where('id', (int) $value)
|
||||||
|
->first()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
if (null !== $preference) {
|
if (null !== $preference) {
|
||||||
/** @var Preference $preference */
|
/** @var Preference $preference */
|
||||||
|
|||||||
@@ -58,19 +58,32 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
|
|||||||
$end = $availableBudget->end_date->format('Y-m-d');
|
$end = $availableBudget->end_date->format('Y-m-d');
|
||||||
$key = sprintf('%s-%s-%s', $availableBudget->transaction_currency_id, $start, $end);
|
$key = sprintf('%s-%s-%s', $availableBudget->transaction_currency_id, $start, $end);
|
||||||
if (array_key_exists($key, $exists)) {
|
if (array_key_exists($key, $exists)) {
|
||||||
Log::debug(sprintf('Found duplicate AB: %s %s, %s-%s. Has been deleted', $availableBudget->transaction_currency_id, $availableBudget->amount, $start, $end));
|
Log::debug(sprintf(
|
||||||
|
'Found duplicate AB: %s %s, %s-%s. Has been deleted',
|
||||||
|
$availableBudget->transaction_currency_id,
|
||||||
|
$availableBudget->amount,
|
||||||
|
$start,
|
||||||
|
$end
|
||||||
|
));
|
||||||
$availableBudget->delete();
|
$availableBudget->delete();
|
||||||
}
|
}
|
||||||
$exists[$key] = true;
|
$exists[$key] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// grab budget limit currencies.
|
// grab budget limit currencies.
|
||||||
$currencies = BudgetLimit
|
$currencies = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
|
||||||
::leftJoin('budgets','budgets.id','=','budget_limits.budget_id')
|
|
||||||
->where('budgets.user_id', $this->user->id)
|
->where('budgets.user_id', $this->user->id)
|
||||||
->distinct()->get(['budget_limits.transaction_currency_id'])->pluck('transaction_currency_id')->toArray();
|
->distinct()
|
||||||
|
->get(['budget_limits.transaction_currency_id'])
|
||||||
|
->pluck('transaction_currency_id')
|
||||||
|
->toArray()
|
||||||
|
;
|
||||||
// delete available budgets without these currencies.
|
// delete available budgets without these currencies.
|
||||||
$this->user->availableBudgets()->whereNotIn('transaction_currency_id', $currencies)->delete();
|
$this->user
|
||||||
|
->availableBudgets()
|
||||||
|
->whereNotIn('transaction_currency_id', $currencies)
|
||||||
|
->delete()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -256,8 +256,14 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
|
|||||||
foreach ($budgets as $budget) {
|
foreach ($budgets as $budget) {
|
||||||
DB::table('budget_transaction')->where('budget_id', $budget->id)->delete();
|
DB::table('budget_transaction')->where('budget_id', $budget->id)->delete();
|
||||||
DB::table('budget_transaction_journal')->where('budget_id', $budget->id)->delete();
|
DB::table('budget_transaction_journal')->where('budget_id', $budget->id)->delete();
|
||||||
RecurrenceTransactionMeta::where('name', 'budget_id')->where('value', (string) $budget->id)->delete();
|
RecurrenceTransactionMeta::where('name', 'budget_id')
|
||||||
RuleAction::where('action_type', 'set_budget')->where('action_value', (string) $budget->id)->delete();
|
->where('value', (string) $budget->id)
|
||||||
|
->delete()
|
||||||
|
;
|
||||||
|
RuleAction::where('action_type', 'set_budget')
|
||||||
|
->where('action_value', (string) $budget->id)
|
||||||
|
->delete()
|
||||||
|
;
|
||||||
$budget->delete();
|
$budget->delete();
|
||||||
}
|
}
|
||||||
Log::channel('audit')->info('Delete all budgets through destroyAll');
|
Log::channel('audit')->info('Delete all budgets through destroyAll');
|
||||||
|
|||||||
@@ -86,7 +86,10 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// is being used in accounts:
|
// is being used in accounts:
|
||||||
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string) $currency->id))->count();
|
$meta = AccountMeta::where('name', 'currency_id')
|
||||||
|
->where('data', json_encode((string) $currency->id))
|
||||||
|
->count()
|
||||||
|
;
|
||||||
if ($meta > 0) {
|
if ($meta > 0) {
|
||||||
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
|
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
|
||||||
|
|
||||||
@@ -94,7 +97,10 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// second search using integer check.
|
// second search using integer check.
|
||||||
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((int) $currency->id))->count();
|
$meta = AccountMeta::where('name', 'currency_id')
|
||||||
|
->where('data', json_encode((int) $currency->id))
|
||||||
|
->count()
|
||||||
|
;
|
||||||
if ($meta > 0) {
|
if ($meta > 0) {
|
||||||
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
|
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
|
||||||
|
|
||||||
|
|||||||
@@ -97,9 +97,10 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
|
|||||||
public function findSpecificLink(LinkType $linkType, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink
|
public function findSpecificLink(LinkType $linkType, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink
|
||||||
{
|
{
|
||||||
return TransactionJournalLink::where('link_type_id', $linkType->id)
|
return TransactionJournalLink::where('link_type_id', $linkType->id)
|
||||||
->where('source_id', $inward->id)
|
->where('source_id', $inward->id)
|
||||||
->where('destination_id', $outward->id)
|
->where('destination_id', $outward->id)
|
||||||
->first();
|
->first()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get(): Collection
|
public function get(): Collection
|
||||||
@@ -116,7 +117,14 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
|
|||||||
$sources = $links->pluck('source_id')->toArray();
|
$sources = $links->pluck('source_id')->toArray();
|
||||||
$destinations = $links->pluck('destination_id')->toArray();
|
$destinations = $links->pluck('destination_id')->toArray();
|
||||||
$joined = array_unique(array_merge($sources, $destinations));
|
$joined = array_unique(array_merge($sources, $destinations));
|
||||||
return $this->user->transactionJournals()->whereIn('id', $joined)->get(['transaction_journals.id'])->pluck('id')->toArray();
|
|
||||||
|
return $this->user
|
||||||
|
->transactionJournals()
|
||||||
|
->whereIn('id', $joined)
|
||||||
|
->get(['transaction_journals.id'])
|
||||||
|
->pluck('id')
|
||||||
|
->toArray()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,12 +133,13 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
|
|||||||
public function getJournalLinks(?LinkType $linkType = null): Collection
|
public function getJournalLinks(?LinkType $linkType = null): Collection
|
||||||
{
|
{
|
||||||
$query = TransactionJournalLink::with(['source', 'destination'])
|
$query = TransactionJournalLink::with(['source', 'destination'])
|
||||||
->leftJoin('transaction_journals as source_journals', 'journal_links.source_id', '=', 'source_journals.id')
|
->leftJoin('transaction_journals as source_journals', 'journal_links.source_id', '=', 'source_journals.id')
|
||||||
->leftJoin('transaction_journals as dest_journals', 'journal_links.destination_id', '=', 'dest_journals.id')
|
->leftJoin('transaction_journals as dest_journals', 'journal_links.destination_id', '=', 'dest_journals.id')
|
||||||
->where('source_journals.user_id', $this->user->id)
|
->where('source_journals.user_id', $this->user->id)
|
||||||
->where('dest_journals.user_id', $this->user->id)
|
->where('dest_journals.user_id', $this->user->id)
|
||||||
->whereNull('source_journals.deleted_at')
|
->whereNull('source_journals.deleted_at')
|
||||||
->whereNull('dest_journals.deleted_at');
|
->whereNull('dest_journals.deleted_at')
|
||||||
|
;
|
||||||
|
|
||||||
if ($linkType instanceof LinkType) {
|
if ($linkType instanceof LinkType) {
|
||||||
$query->where('journal_links.link_type_id', $linkType->id);
|
$query->where('journal_links.link_type_id', $linkType->id);
|
||||||
@@ -158,7 +167,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
|
|||||||
$inward = TransactionJournalLink::whereDestinationId($journal->id)->get();
|
$inward = TransactionJournalLink::whereDestinationId($journal->id)->get();
|
||||||
$merged = $outward->merge($inward);
|
$merged = $outward->merge($inward);
|
||||||
|
|
||||||
return $merged->filter(static fn(TransactionJournalLink $link): bool => null !== $link->source && null !== $link->destination);
|
return $merged->filter(static fn (TransactionJournalLink $link): bool => null !== $link->source && null !== $link->destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(array $data): LinkType
|
public function store(array $data): LinkType
|
||||||
@@ -180,7 +189,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
|
|||||||
*/
|
*/
|
||||||
public function storeLink(array $information, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink
|
public function storeLink(array $information, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink
|
||||||
{
|
{
|
||||||
$linkType = $this->find((int)($information['link_type_id'] ?? 0));
|
$linkType = $this->find((int) ($information['link_type_id'] ?? 0));
|
||||||
|
|
||||||
if (!$linkType instanceof LinkType) {
|
if (!$linkType instanceof LinkType) {
|
||||||
$linkType = $this->findByName($information['link_type_name']);
|
$linkType = $this->findByName($information['link_type_name']);
|
||||||
@@ -196,7 +205,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
|
|||||||
return $existing;
|
return $existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
$link = new TransactionJournalLink();
|
$link = new TransactionJournalLink();
|
||||||
$link->linkType()->associate($linkType);
|
$link->linkType()->associate($linkType);
|
||||||
if ('inward' === $information['direction']) {
|
if ('inward' === $information['direction']) {
|
||||||
Log::debug(sprintf('Link type is inwards ("%s"), so %d is source and %d is destination.', $linkType->inward, $inward->id, $outward->id));
|
Log::debug(sprintf('Link type is inwards ("%s"), so %d is source and %d is destination.', $linkType->inward, $inward->id, $outward->id));
|
||||||
@@ -212,7 +221,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
|
|||||||
$link->save();
|
$link->save();
|
||||||
|
|
||||||
// make note in noteable:
|
// make note in noteable:
|
||||||
$this->setNoteText($link, (string)$information['notes']);
|
$this->setNoteText($link, (string) $information['notes']);
|
||||||
|
|
||||||
return $link;
|
return $link;
|
||||||
}
|
}
|
||||||
@@ -240,13 +249,13 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
|
|||||||
|
|
||||||
public function update(LinkType $linkType, array $data): LinkType
|
public function update(LinkType $linkType, array $data): LinkType
|
||||||
{
|
{
|
||||||
if (array_key_exists('name', $data) && '' !== (string)$data['name']) {
|
if (array_key_exists('name', $data) && '' !== (string) $data['name']) {
|
||||||
$linkType->name = $data['name'];
|
$linkType->name = $data['name'];
|
||||||
}
|
}
|
||||||
if (array_key_exists('inward', $data) && '' !== (string)$data['inward']) {
|
if (array_key_exists('inward', $data) && '' !== (string) $data['inward']) {
|
||||||
$linkType->inward = $data['inward'];
|
$linkType->inward = $data['inward'];
|
||||||
}
|
}
|
||||||
if (array_key_exists('outward', $data) && '' !== (string)$data['outward']) {
|
if (array_key_exists('outward', $data) && '' !== (string) $data['outward']) {
|
||||||
$linkType->outward = $data['outward'];
|
$linkType->outward = $data['outward'];
|
||||||
}
|
}
|
||||||
$linkType->save();
|
$linkType->save();
|
||||||
@@ -273,7 +282,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
|
|||||||
$journalLink->refresh();
|
$journalLink->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
$journalLink->link_type_id = $data['link_type_id'] ?? $journalLink->link_type_id;
|
$journalLink->link_type_id = $data['link_type_id'] ?? $journalLink->link_type_id;
|
||||||
$journalLink->save();
|
$journalLink->save();
|
||||||
if (array_key_exists('notes', $data) && null !== $data['notes']) {
|
if (array_key_exists('notes', $data) && null !== $data['notes']) {
|
||||||
$this->setNoteText($journalLink, $data['notes']);
|
$this->setNoteText($journalLink, $data['notes']);
|
||||||
|
|||||||
@@ -41,7 +41,10 @@ class UserGroupAccount implements BinderInterface
|
|||||||
if (auth()->check()) {
|
if (auth()->check()) {
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
$account = Account::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
|
$account = Account::where('id', (int) $value)
|
||||||
|
->where('user_group_id', $user->user_group_id)
|
||||||
|
->first()
|
||||||
|
;
|
||||||
if (null !== $account) {
|
if (null !== $account) {
|
||||||
return $account;
|
return $account;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,10 @@ class UserGroupBill implements BinderInterface
|
|||||||
if (auth()->check()) {
|
if (auth()->check()) {
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
$currency = Bill::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
|
$currency = Bill::where('id', (int) $value)
|
||||||
|
->where('user_group_id', $user->user_group_id)
|
||||||
|
->first()
|
||||||
|
;
|
||||||
if (null !== $currency) {
|
if (null !== $currency) {
|
||||||
return $currency;
|
return $currency;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ class UserGroupExchangeRate implements BinderInterface
|
|||||||
if (auth()->check()) {
|
if (auth()->check()) {
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
$rate = CurrencyExchangeRate::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
|
$rate = CurrencyExchangeRate::where('id', (int) $value)
|
||||||
|
->where('user_group_id', $user->user_group_id)
|
||||||
|
->first()
|
||||||
|
;
|
||||||
if (null !== $rate) {
|
if (null !== $rate) {
|
||||||
return $rate;
|
return $rate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ class UserGroupTransaction implements BinderInterface
|
|||||||
if (auth()->check()) {
|
if (auth()->check()) {
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
$group = TransactionGroup::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
|
$group = TransactionGroup::where('id', (int) $value)
|
||||||
|
->where('user_group_id', $user->user_group_id)
|
||||||
|
->first()
|
||||||
|
;
|
||||||
if (null !== $group) {
|
if (null !== $group) {
|
||||||
return $group;
|
return $group;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,10 @@ class AppendNotes implements ActionInterface
|
|||||||
public function actOnArray(array $journal): bool
|
public function actOnArray(array $journal): bool
|
||||||
{
|
{
|
||||||
$this->refreshNotes($journal);
|
$this->refreshNotes($journal);
|
||||||
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])->where('noteable_type', TransactionJournal::class)->first(['notes.*']);
|
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])
|
||||||
|
->where('noteable_type', TransactionJournal::class)
|
||||||
|
->first(['notes.*'])
|
||||||
|
;
|
||||||
if (null === $dbNote) {
|
if (null === $dbNote) {
|
||||||
$dbNote = new Note();
|
$dbNote = new Note();
|
||||||
$dbNote->noteable_id = (int) $journal['transaction_journal_id'];
|
$dbNote->noteable_id = (int) $journal['transaction_journal_id'];
|
||||||
|
|||||||
@@ -44,7 +44,10 @@ class PrependNotes implements ActionInterface
|
|||||||
|
|
||||||
public function actOnArray(array $journal): bool
|
public function actOnArray(array $journal): bool
|
||||||
{
|
{
|
||||||
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])->where('noteable_type', TransactionJournal::class)->first(['notes.*']);
|
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])
|
||||||
|
->where('noteable_type', TransactionJournal::class)
|
||||||
|
->first(['notes.*'])
|
||||||
|
;
|
||||||
if (null === $dbNote) {
|
if (null === $dbNote) {
|
||||||
$dbNote = new Note();
|
$dbNote = new Note();
|
||||||
$dbNote->noteable_id = (int) $journal['transaction_journal_id'];
|
$dbNote->noteable_id = (int) $journal['transaction_journal_id'];
|
||||||
|
|||||||
@@ -355,7 +355,11 @@ trait RecurrenceValidation
|
|||||||
}
|
}
|
||||||
if (array_key_exists('id', $transaction)) { // don't matter if $idsMandatory
|
if (array_key_exists('id', $transaction)) { // don't matter if $idsMandatory
|
||||||
Log::debug('Array has ID.');
|
Log::debug('Array has ID.');
|
||||||
$idCount = $recurrence->recurrenceTransactions()->where('recurrences_transactions.id', (int) $transaction['id'])->count();
|
$idCount = $recurrence
|
||||||
|
->recurrenceTransactions()
|
||||||
|
->where('recurrences_transactions.id', (int) $transaction['id'])
|
||||||
|
->count()
|
||||||
|
;
|
||||||
if (0 === $idCount) {
|
if (0 === $idCount) {
|
||||||
Log::debug('ID does not exist or no match. Count another unmatched ID.');
|
Log::debug('ID does not exist or no match. Count another unmatched ID.');
|
||||||
++$unmatchedIds;
|
++$unmatchedIds;
|
||||||
|
|||||||
+4
-4
@@ -17,10 +17,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- #11879
|
- [Discussion 11879](https://github.com/orgs/firefly-iii/discussions/11879) (Searching for accounts should include inactive accounts?) started by @b-ryan
|
||||||
- #11916
|
- [Issue 11916](https://github.com/firefly-iii/firefly-iii/issues/11916) (Balance is not recalculated when multiple transactions are selected and then deleted) reported by @elp3dr0
|
||||||
- #11936
|
- [Discussion 11936](https://github.com/orgs/firefly-iii/discussions/11936) (Links in emails don't link to correct domain) started by @SamLMB
|
||||||
- #11944
|
- [Issue 11944](https://github.com/firefly-iii/firefly-iii/issues/11944) (Stale available_budgets rows prevent disabling a currency after switching default) reported by @k-leveller
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -78,8 +78,8 @@ return [
|
|||||||
'running_balance_column' => (bool)envDefaultWhenEmpty(env('USE_RUNNING_BALANCE'), true), // this is only the default value, is not used.
|
'running_balance_column' => (bool)envDefaultWhenEmpty(env('USE_RUNNING_BALANCE'), true), // this is only the default value, is not used.
|
||||||
// see cer.php for exchange rates feature flag.
|
// see cer.php for exchange rates feature flag.
|
||||||
],
|
],
|
||||||
'version' => 'develop/2026-03-13',
|
'version' => 'develop/2026-03-14',
|
||||||
'build_time' => 1773385699,
|
'build_time' => 1773474042,
|
||||||
'api_version' => '2.1.0', // field is no longer used.
|
'api_version' => '2.1.0', // field is no longer used.
|
||||||
'db_version' => 28, // field is no longer used.
|
'db_version' => 28, // field is no longer used.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user