Fix a lot of phpstan things

This commit is contained in:
James Cole 2023-11-26 12:10:42 +01:00
parent a6c355c7b8
commit 68f01d932e
No known key found for this signature in database
GPG Key ID: B49A324B7EAD6D80
53 changed files with 214 additions and 120 deletions

View File

@ -125,7 +125,7 @@ class AccountController extends Controller
'native_id' => (string)$default->id,
'native_code' => $default->code,
'native_symbol' => $default->symbol,
'native_decimal_places' => (int)$default->decimal_places,
'native_decimal_places' => $default->decimal_places,
'start' => $start->toAtomString(),
'end' => $end->toAtomString(),
'period' => '1D',

View File

@ -100,12 +100,12 @@ class BalanceController extends Controller
'currency_symbol' => $default->symbol,
'currency_code' => $default->code,
'currency_name' => $default->name,
'currency_decimal_places' => (int)$default->decimal_places,
'currency_decimal_places' => $default->decimal_places,
'native_id' => (string)$defaultCurrencyId,
'native_symbol' => $default->symbol,
'native_code' => $default->code,
'native_name' => $default->name,
'native_decimal_places' => (int)$default->decimal_places,
'native_decimal_places' => $default->decimal_places,
];
@ -131,7 +131,7 @@ class BalanceController extends Controller
'native_id' => (string)$default->id,
'native_code' => $default->code,
'native_symbol' => $default->symbol,
'native_decimal_places' => (int)$default->decimal_places,
'native_decimal_places' => $default->decimal_places,
];
// set the array (in monetary info) with spent/earned in this $period, if it does not exist.

View File

@ -209,7 +209,7 @@ class BudgetController extends Controller
'native_code' => $this->currency->code,
'native_name' => $this->currency->name,
'native_symbol' => $this->currency->symbol,
'native_decimal_places' => (int)$this->currency->decimal_places,
'native_decimal_places' => $this->currency->decimal_places,
'start' => $start->toAtomString(),
'end' => $end->toAtomString(),
'spent' => '0',

View File

@ -114,12 +114,12 @@ class CategoryController extends Controller
'currency_code' => $currency->code,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'native_id' => (string)$default->id,
'native_code' => $default->code,
'native_name' => $default->name,
'native_symbol' => $default->symbol,
'native_decimal_places' => (int)$default->decimal_places,
'native_decimal_places' => $default->decimal_places,
'period' => null,
'start' => $start->toAtomString(),
'end' => $end->toAtomString(),

View File

@ -376,7 +376,7 @@ class BasicController extends Controller
'currency_id' => (string)$default->id,
'currency_code' => $default->code,
'currency_symbol' => $default->symbol,
'currency_decimal_places' => (int)$default->decimal_places,
'currency_decimal_places' => $default->decimal_places,
];
$nativePerDay = [
'key' => 'left-per-day-to-spend-in-native',
@ -384,7 +384,7 @@ class BasicController extends Controller
'currency_id' => (string)$default->id,
'currency_code' => $default->code,
'currency_symbol' => $default->symbol,
'currency_decimal_places' => (int)$default->decimal_places,
'currency_decimal_places' => $default->decimal_places,
];
/**

View File

@ -61,7 +61,7 @@ class DeleteEmptyJournals extends Command
{
$set = Transaction::whereNull('deleted_at')
->groupBy('transactions.transaction_journal_id')
->get([DB::raw('COUNT(transactions.transaction_journal_id) as the_count'), 'transaction_journal_id']);
->get([DB::raw('COUNT(transactions.transaction_journal_id) as the_count'), 'transaction_journal_id']); // @phpstan-ignore-line
$total = 0;
/** @var Transaction $row */
foreach ($set as $row) {

View File

@ -51,7 +51,7 @@ class FixGroupAccounts extends Command
{
$groups = [];
$res = TransactionJournal::groupBy('transaction_group_id')
->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')]);
->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')]);// @phpstan-ignore-line
/** @var TransactionJournal $journal */
foreach ($res as $journal) {
if ((int)$journal->the_count > 1) {

View File

@ -51,7 +51,7 @@ class ExportData extends Command
protected $description = 'Command to export data from Firefly III.';
protected $signature = 'firefly-iii:export-data
protected $signature = 'firefly-iii:export-data
{--user=1 : The user ID that the export should run for.}
{--token= : The user\'s access token.}
{--start= : First transaction to export. Defaults to your very first transaction. Only applies to transaction export.}
@ -190,7 +190,12 @@ class ExportData extends Command
{
$date = today(config('app.timezone'))->subYear();
$error = false;
if (null !== $this->option($field)) {
if (!in_array($field, ['start', 'end'], true)) {
throw new FireflyException(sprintf('Invalid field "%s" given, can only be "start" or "end".', $field));
}
if (is_string($this->option($field))) {
try {
$date = Carbon::createFromFormat('!Y-m-d', $this->option($field));
} catch (InvalidArgumentException $e) {
@ -198,6 +203,10 @@ class ExportData extends Command
$this->friendlyError(sprintf('%s date "%s" must be formatted YYYY-MM-DD. Field will be ignored.', $field, $this->option('start')));
$error = true;
}
if (false === $date) {
$this->friendlyError(sprintf('%s date "%s" must be formatted YYYY-MM-DD.', $field, $this->option('start')));
throw new FireflyException(sprintf('%s date "%s" must be formatted YYYY-MM-DD.', $field, $this->option('start')));
}
}
if (null === $this->option($field)) {
app('log')->info(sprintf('No date given in field "%s"', $field));
@ -208,12 +217,15 @@ class ExportData extends Command
$journal = $this->journalRepository->firstNull();
$date = null === $journal ? today(config('app.timezone'))->subYear() : $journal->date;
$date->startOfDay();
return $date;
}
if (true === $error && 'end' === $field) {
// field can only be 'end' at this point, so no need to include it in the check.
if (true === $error) {
$date = today(config('app.timezone'));
$date->endOfDay();
return $date;
}
if ('end' === $field) {
$date->endOfDay();
}

View File

@ -79,6 +79,7 @@ class CreateDatabase extends Command
// only continue when no error.
// with PDO, try to list DB's (
/** @var array $stmt */
$stmt = $pdo->query('SHOW DATABASES;');
// slightly more complex but less error-prone.
foreach ($stmt as $row) {

View File

@ -253,13 +253,14 @@ class ForceDecimalSize extends Command
}
/** @var Account $account */
foreach ($result as $account) {
/** @var string $field */
foreach ($fields as $field) {
$value = $account->$field;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = 10** (int)$currency->decimal_places;
$pow = 10** $currency->decimal_places;
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->friendlyInfo(sprintf('Account #%d has %s with value "%s", this has been corrected to "%s".', $account->id, $field, $value, $correct));
Account::find($account->id)->update([$field => $correct]);
@ -286,6 +287,7 @@ class ForceDecimalSize extends Command
/** @var Builder $query */
$query = $class::where('transaction_currency_id', $currency->id)->where(
static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression) {
/** @var string $field */
foreach ($fields as $field) {
$q->orWhere(
DB::raw(sprintf('CAST(%s AS %s)', $field, $cast)), // @phpstan-ignore-line
@ -304,13 +306,14 @@ class ForceDecimalSize extends Command
}
/** @var Model $item */
foreach ($result as $item) {
/** @var string $field */
foreach ($fields as $field) {
$value = $item->$field;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = 10** (int)$currency->decimal_places;
$pow = 10** $currency->decimal_places;
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->friendlyWarning(sprintf('%s #%d has %s with value "%s", this has been corrected to "%s".', $table, $item->id, $field, $value, $correct));
$class::find($item->id)->update([$field => $correct]);
@ -356,13 +359,14 @@ class ForceDecimalSize extends Command
}
/** @var PiggyBankEvent $item */
foreach ($result as $item) {
/** @var string $field */
foreach ($fields as $field) {
$value = $item->$field;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = 10** (int)$currency->decimal_places;
$pow = 10** $currency->decimal_places;
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->friendlyWarning(
sprintf('Piggy bank event #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct)
@ -410,13 +414,14 @@ class ForceDecimalSize extends Command
}
/** @var PiggyBankRepetition $item */
foreach ($result as $item) {
/** @var string $field */
foreach ($fields as $field) {
$value = $item->$field;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = 10** (int)$currency->decimal_places;
$pow = 10** $currency->decimal_places;
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->friendlyWarning(
sprintf('Piggy bank repetition #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct)
@ -463,13 +468,14 @@ class ForceDecimalSize extends Command
}
/** @var PiggyBank $item */
foreach ($result as $item) {
/** @var string $field */
foreach ($fields as $field) {
$value = $item->$field;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = 10** (int)$currency->decimal_places;
$pow = 10** $currency->decimal_places;
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->friendlyWarning(sprintf('Piggy bank #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct));
PiggyBank::find($item->id)->update([$field => $correct]);
@ -506,7 +512,7 @@ class ForceDecimalSize extends Command
continue;
}
// fix $field by rounding it down correctly.
$pow = (float)10** (int)$currency->decimal_places;
$pow = (float)10** $currency->decimal_places;
$correct = bcdiv((string)round((float)$value * $pow), (string)$pow, 12);
$this->friendlyWarning(sprintf('Transaction #%d has amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct));
Transaction::find($item->id)->update(['amount' => $correct]);
@ -533,7 +539,7 @@ class ForceDecimalSize extends Command
continue;
}
// fix $field by rounding it down correctly.
$pow = (float)10** (int)$currency->decimal_places;
$pow = (float)10** $currency->decimal_places;
$correct = bcdiv((string)round((float)$value * $pow), (string)$pow, 12);
$this->friendlyWarning(
sprintf('Transaction #%d has foreign amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct)

View File

@ -67,11 +67,13 @@ class ScanAttachments extends Command
$decryptedContent = $encryptedContent;
}
$tempFileName = tempnam(sys_get_temp_dir(), 'FireflyIII');
if(false === $tempFileName) {
app('log')->error(sprintf('Could not create temporary file for attachment #%d', $attachment->id));
exit(1);
}
file_put_contents($tempFileName, $decryptedContent);
$md5 = md5_file($tempFileName);
$mime = mime_content_type($tempFileName);
$attachment->md5 = $md5;
$attachment->mime = $mime;
$attachment->md5 = (string) md5_file($tempFileName);
$attachment->mime = (string) mime_content_type($tempFileName);
$attachment->save();
$this->friendlyInfo(sprintf('Fixed attachment #%d', $attachment->id));
}

View File

@ -61,14 +61,15 @@ class UpgradeFireflyInstructions extends Command
*/
private function updateInstructions(): void
{
/** @var string $version */
$version = config('firefly.version');
$version = (string) config('firefly.version');
/** @var array $config */
$config = config('upgrade.text.upgrade');
$text = '';
/** @var string $compare */
foreach (array_keys($config) as $compare) {
// if string starts with:
if (str_starts_with($version, $compare)) {
$text = $config[$compare];
$text = (string) $config[$compare];
}
}
@ -78,7 +79,7 @@ class UpgradeFireflyInstructions extends Command
$this->showLine();
$this->boxed('');
if (null === $text || '' === $text) {
if ('' === $text) {
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s', $version));
$this->boxedInfo('There are no extra upgrade instructions.');
$this->boxed('Firefly III should be ready for use.');
@ -174,14 +175,15 @@ class UpgradeFireflyInstructions extends Command
*/
private function installInstructions(): void
{
/** @var string $version */
$version = config('firefly.version');
$version = (string) config('firefly.version');
/** @var array $config */
$config = config('upgrade.text.install');
$text = '';
/** @var string $compare */
foreach (array_keys($config) as $compare) {
// if string starts with:
if (str_starts_with($version, $compare)) {
$text = $config[$compare];
$text = (string) $config[$compare];
}
}
$this->newLine();
@ -189,7 +191,7 @@ class UpgradeFireflyInstructions extends Command
$this->newLine();
$this->showLine();
$this->boxed('');
if (null === $text || '' === $text) {
if ('' === $text) {
$this->boxed(sprintf('Thank you for installing Firefly III, v%s!', $version));
$this->boxedInfo('There are no extra installation instructions.');
$this->boxed('Firefly III should be ready for use.');

View File

@ -37,6 +37,7 @@ use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class ApplyRules
@ -296,6 +297,10 @@ class ApplyRules extends Command
if (null !== $endString && '' !== $endString) {
$inputEnd = Carbon::createFromFormat('Y-m-d', $endString);
}
if(false === $inputEnd || false === $inputStart) {
Log::error('Could not parse start or end date in verifyInputDate().');
return;
}
if ($inputStart > $inputEnd) {
[$inputEnd, $inputStart] = [$inputStart, $inputEnd];

View File

@ -120,11 +120,11 @@ class FixPostgresSequences extends Command
continue;
}
if ($nextId->nextval < $highestId->max) {
if ($nextId->nextval < $highestId->max) { // @phpstan-ignore-line
DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max));
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->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) { // @phpstan-ignore-line
$this->friendlyInfo(sprintf('Table "%s" autoincrement corrected.', $tableToCheck));
}
if ($nextId->nextval <= $highestId->max) {

View File

@ -48,7 +48,7 @@ class MigrateToRules extends Command
protected $description = 'Migrate bills to rules.';
protected $signature = 'firefly-iii:bills-to-rules {--F|force : Force the execution of this command.}';
protected $signature = 'firefly-iii:bills-to-rules {--F|force : Force the execution of this command.}';
private BillRepositoryInterface $billRepository;
private int $count;
private RuleGroupRepositoryInterface $ruleGroupRepository;
@ -138,14 +138,15 @@ class MigrateToRules extends Command
/** @var Preference $lang */
$lang = app('preferences')->getForUser($user, 'language', 'en_US');
$groupTitle = (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data);
$language = null !== $lang->data && !is_array($lang->data) ? (string)$lang->data : 'en_US';
$groupTitle = (string)trans('firefly.rulegroup_for_bills_title', [], $language);
$ruleGroup = $this->ruleGroupRepository->findByTitle($groupTitle);
if (null === $ruleGroup) {
$ruleGroup = $this->ruleGroupRepository->store(
[
'title' => (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data),
'description' => (string)trans('firefly.rulegroup_for_bills_description', [], $lang->data),
'title' => (string)trans('firefly.rulegroup_for_bills_title', [], $language),
'description' => (string)trans('firefly.rulegroup_for_bills_description', [], $language),
'active' => true,
]
);
@ -168,6 +169,7 @@ class MigrateToRules extends Command
if ('MIGRATED_TO_RULES' === $bill->match) {
return;
}
$languageString = null !== $language->data && !is_array($language->data) ? (string)$language->data : 'en_US';
// get match thing:
$match = implode(' ', explode(',', $bill->match));
@ -176,8 +178,8 @@ class MigrateToRules extends Command
'active' => true,
'strict' => false,
'stop_processing' => false, // field is no longer used.
'title' => (string)trans('firefly.rule_for_bill_title', ['name' => $bill->name], $language->data),
'description' => (string)trans('firefly.rule_for_bill_description', ['name' => $bill->name], $language->data),
'title' => (string)trans('firefly.rule_for_bill_title', ['name' => $bill->name], $languageString),
'description' => (string)trans('firefly.rule_for_bill_description', ['name' => $bill->name], $languageString),
'trigger' => 'store-journal',
'triggers' => [
[

View File

@ -150,7 +150,7 @@ class UpgradeCurrencyPreferences extends Command
{
$preference = Preference::where('user_id', $user->id)->where('name', 'currencyPreference')->first(['id', 'user_id', 'name', 'data', 'updated_at', 'created_at']);
if (null !== $preference) {
if (null !== $preference->data && !is_array($preference->data)) {
return (string)$preference->data;
}
return 'EUR';

View File

@ -143,10 +143,11 @@ class GracefulNotFoundHandler extends ExceptionHandler
$user = auth()->user();
$route = $request->route();
$param = $route->parameter('account');
$accountId = 0;
if ($param instanceof Account) {
$accountId = $param->id;
}
if (!($param instanceof Account)) {
if (!($param instanceof Account) && !is_object($param)) {
$accountId = (int)$param;
}
/** @var Account|null $account */
@ -176,7 +177,8 @@ class GracefulNotFoundHandler extends ExceptionHandler
/** @var User $user */
$user = auth()->user();
$route = $request->route();
$groupId = (int)$route->parameter('transactionGroup');
$param = $route->parameter('transactionGroup');
$groupId = !is_object($param) ? (int)$param : 0;
/** @var TransactionGroup|null $group */
$group = $user->transactionGroups()->withTrashed()->find($groupId);
@ -215,7 +217,8 @@ class GracefulNotFoundHandler extends ExceptionHandler
/** @var User $user */
$user = auth()->user();
$route = $request->route();
$attachmentId = (int)$route->parameter('attachment');
$param = $route->parameter('attachment');
$attachmentId = is_object($param) ? 0 : (int)$param;
/** @var Attachment|null $attachment */
$attachment = $user->attachments()->withTrashed()->find($attachmentId);
if (null === $attachment) {

View File

@ -474,7 +474,7 @@ class TransactionJournalFactory
private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency
{
app('log')->debug('Now in getCurrency()');
/** @var Preference|null $preference */
/** @var TransactionCurrency|null $preference */
$preference = $this->accountRepository->getAccountCurrency($account);
if (null === $preference && null === $currency) {
// return user's default:

View File

@ -92,6 +92,11 @@ class BudgetLimitHandler
app('log')->error($e->getMessage());
$viewRange = '1M';
}
// safety catch
if(null === $viewRange || is_array($viewRange)){
$viewRange = '1M';
}
$viewRange = (string)$viewRange;
$start = app('navigation')->startOfPeriod($budgetLimit->start_date, $viewRange);
$end = app('navigation')->startOfPeriod($budgetLimit->end_date, $viewRange);

View File

@ -197,6 +197,9 @@ class UserEventHandler
}
$list = app('preferences')->getForUser($user, 'login_ip_history', [])->data;
if(!is_array($list)) {
$list = [];
}
/** @var array $entry */
foreach ($list as $index => $entry) {
@ -415,7 +418,7 @@ class UserEventHandler
}
// clean up old entries (6 months)
$carbon = Carbon::createFromFormat('Y-m-d H:i:s', $preference[$index]['time']);
if ($carbon->diffInMonths(today()) > 6) {
if (false !== $carbon && $carbon->diffInMonths(today()) > 6) {
app('log')->debug(sprintf('Entry for %s is very old, remove it.', $row['ip']));
unset($preference[$index]);
}

View File

@ -155,13 +155,18 @@ class AttachmentHelper implements AttachmentHelperInterface
$path = stream_get_meta_data($resource)['uri'];
Log::debug(sprintf('Path is %s', $path));
$result = fwrite($resource, $content);
if(false === $result) {
if (false === $result) {
Log::error('Could not write temp file.');
return false;
}
Log::debug(sprintf('Wrote %d bytes to temp file.', $result));
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $path);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if (false === $finfo) {
Log::error('Could not open finfo.');
fclose($resource);
return false;
}
$mime = (string) finfo_file($finfo, $path);
$allowedMime = config('firefly.allowedMimes');
if (!in_array($mime, $allowedMime, true)) {
Log::error(sprintf('Mime type %s is not allowed for API file upload.', $mime));
@ -177,7 +182,7 @@ class AttachmentHelper implements AttachmentHelperInterface
$this->uploadDisk->put($file, $content);
// update attachment.
$attachment->md5 = md5_file($path);
$attachment->md5 = (string) md5_file($path);
$attachment->mime = $mime;
$attachment->size = strlen($content);
$attachment->uploaded = true;
@ -246,7 +251,7 @@ class AttachmentHelper implements AttachmentHelperInterface
$attachment = new Attachment(); // create Attachment object.
$attachment->user()->associate($user);
$attachment->attachable()->associate($model);
$attachment->md5 = md5_file($file->getRealPath());
$attachment->md5 = (string) md5_file($file->getRealPath());
$attachment->filename = $file->getClientOriginalName();
$attachment->mime = $file->getMimeType();
$attachment->size = $file->getSize();
@ -261,7 +266,7 @@ class AttachmentHelper implements AttachmentHelperInterface
throw new FireflyException('Cannot upload empty or non-existent file.');
}
$content = $fileObject->fread($file->getSize());
$content = (string) $fileObject->fread($file->getSize());
Log::debug(sprintf('Full file length is %d and upload size is %d.', strlen($content), $file->getSize()));
// store it without encryption.

View File

@ -226,7 +226,7 @@ trait MetaCollection
*/
public function excludeInternalReference(string $internalReference): GroupCollectorInterface
{
$internalReference = json_encode($internalReference);
$internalReference = (string) json_encode($internalReference);
$internalReference = str_replace('\\', '\\\\', trim($internalReference, '"'));
$this->joinMetaDataTables();
@ -253,7 +253,7 @@ trait MetaCollection
*/
public function externalIdContains(string $externalId): GroupCollectorInterface
{
$externalId = json_encode($externalId);
$externalId = (string) json_encode($externalId);
$externalId = str_replace('\\', '\\\\', trim($externalId, '"'));
$this->joinMetaDataTables();
@ -268,7 +268,7 @@ trait MetaCollection
*/
public function externalIdDoesNotContain(string $externalId): GroupCollectorInterface
{
$externalId = json_encode($externalId);
$externalId = (string) json_encode($externalId);
$externalId = str_replace('\\', '\\\\', trim($externalId, '"'));
$this->joinMetaDataTables();
@ -283,7 +283,7 @@ trait MetaCollection
*/
public function externalIdDoesNotEnd(string $externalId): GroupCollectorInterface
{
$externalId = json_encode($externalId);
$externalId = (string) json_encode($externalId);
$externalId = str_replace('\\', '\\\\', trim($externalId, '"'));
$this->joinMetaDataTables();
@ -298,7 +298,7 @@ trait MetaCollection
*/
public function externalIdDoesNotStart(string $externalId): GroupCollectorInterface
{
$externalId = json_encode($externalId);
$externalId = (string) json_encode($externalId);
$externalId = str_replace('\\', '\\\\', trim($externalId, '"'));
$this->joinMetaDataTables();
@ -313,7 +313,7 @@ trait MetaCollection
*/
public function externalIdEnds(string $externalId): GroupCollectorInterface
{
$externalId = json_encode($externalId);
$externalId = (string) json_encode($externalId);
$externalId = str_replace('\\', '\\\\', trim($externalId, '"'));
$this->joinMetaDataTables();
@ -328,7 +328,7 @@ trait MetaCollection
*/
public function externalIdStarts(string $externalId): GroupCollectorInterface
{
$externalId = json_encode($externalId);
$externalId = (string) json_encode($externalId);
$externalId = str_replace('\\', '\\\\', trim($externalId, '"'));
$this->joinMetaDataTables();
@ -346,7 +346,7 @@ trait MetaCollection
public function externalUrlContains(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = (string) json_encode($url);
$url = str_replace('\\', '\\\\', trim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $url));
@ -362,7 +362,7 @@ trait MetaCollection
public function externalUrlDoesNotContain(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = (string) json_encode($url);
$url = str_replace('\\', '\\\\', trim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s%%', $url));
@ -378,7 +378,7 @@ trait MetaCollection
public function externalUrlDoesNotEnd(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = (string) json_encode($url);
$url = str_replace('\\', '\\\\', ltrim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s', $url));
@ -394,7 +394,7 @@ trait MetaCollection
public function externalUrlDoesNotStart(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = (string) json_encode($url);
$url = str_replace('\\', '\\\\', rtrim($url, '"'));
//var_dump($url);
@ -412,7 +412,7 @@ trait MetaCollection
public function externalUrlEnds(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = (string) json_encode($url);
$url = str_replace('\\', '\\\\', ltrim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s', $url));
@ -428,7 +428,7 @@ trait MetaCollection
public function externalUrlStarts(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = (string) json_encode($url);
$url = str_replace('\\', '\\\\', rtrim($url, '"'));
//var_dump($url);
@ -487,7 +487,7 @@ trait MetaCollection
*/
public function internalReferenceContains(string $internalReference): GroupCollectorInterface
{
$internalReference = json_encode($internalReference);
$internalReference = (string) json_encode($internalReference);
$internalReference = str_replace('\\', '\\\\', trim($internalReference, '"'));
//var_dump($internalReference);
//exit;
@ -504,7 +504,7 @@ trait MetaCollection
*/
public function internalReferenceDoesNotContain(string $internalReference): GroupCollectorInterface
{
$internalReference = json_encode($internalReference);
$internalReference = (string) json_encode($internalReference);
$internalReference = str_replace('\\', '\\\\', trim($internalReference, '"'));
$this->joinMetaDataTables();
@ -519,7 +519,7 @@ trait MetaCollection
*/
public function internalReferenceDoesNotEnd(string $internalReference): GroupCollectorInterface
{
$internalReference = json_encode($internalReference);
$internalReference = (string) json_encode($internalReference);
$internalReference = str_replace('\\', '\\\\', trim($internalReference, '"'));
$this->joinMetaDataTables();
@ -534,7 +534,7 @@ trait MetaCollection
*/
public function internalReferenceDoesNotStart(string $internalReference): GroupCollectorInterface
{
$internalReference = json_encode($internalReference);
$internalReference = (string) json_encode($internalReference);
$internalReference = str_replace('\\', '\\\\', trim($internalReference, '"'));
$this->joinMetaDataTables();
@ -549,7 +549,7 @@ trait MetaCollection
*/
public function internalReferenceEnds(string $internalReference): GroupCollectorInterface
{
$internalReference = json_encode($internalReference);
$internalReference = (string) json_encode($internalReference);
$internalReference = str_replace('\\', '\\\\', trim($internalReference, '"'));
$this->joinMetaDataTables();
@ -564,7 +564,7 @@ trait MetaCollection
*/
public function internalReferenceStarts(string $internalReference): GroupCollectorInterface
{
$internalReference = json_encode($internalReference);
$internalReference = (string) json_encode($internalReference);
$internalReference = str_replace('\\', '\\\\', trim($internalReference, '"'));
$this->joinMetaDataTables();
@ -836,7 +836,7 @@ trait MetaCollection
*/
public function setInternalReference(string $internalReference): GroupCollectorInterface
{
$internalReference = json_encode($internalReference);
$internalReference = (string) json_encode($internalReference);
$internalReference = str_replace('\\', '\\\\', trim($internalReference, '"'));
$this->joinMetaDataTables();

View File

@ -80,6 +80,10 @@ class FiscalHelper implements FiscalHelperInterface
$startDate = clone $date;
if (true === $this->useCustomFiscalYear) {
$prefStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data;
if(is_array($prefStartStr)) {
$prefStartStr = '01-01';
}
$prefStartStr = (string) $prefStartStr;
[$mth, $day] = explode('-', $prefStartStr);
$startDate->day((int)$day)->month((int)$mth);

View File

@ -89,12 +89,12 @@ class NetWorth implements NetWorthInterface
'currency_code' => $default->code,
'currency_name' => $default->name,
'currency_symbol' => $default->symbol,
'currency_decimal_places' => (int)$default->decimal_places,
'currency_decimal_places' => $default->decimal_places,
'native_id' => $default->id,
'native_code' => $default->code,
'native_name' => $default->name,
'native_symbol' => $default->symbol,
'native_decimal_places' => (int)$default->decimal_places,
'native_decimal_places' => $default->decimal_places,
],
];
$balances = app('steam')->balancesByAccountsConverted($accounts, $date);
@ -125,12 +125,12 @@ class NetWorth implements NetWorthInterface
'currency_code' => $currency->code,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'native_id' => $default->id,
'native_code' => $default->code,
'native_name' => $default->name,
'native_symbol' => $default->symbol,
'native_decimal_places' => (int)$default->decimal_places,
'native_decimal_places' => $default->decimal_places,
];
$netWorth[$currencyId]['balance'] = bcadd($balance, $netWorth[$currencyId]['balance']);

View File

@ -152,6 +152,9 @@ class CreateController extends Controller
// update preferences if necessary:
$frontPage = app('preferences')->get('frontPageAccounts', [])->data;
if(!is_array($frontPage)) {
$frontPage = [];
}
if (AccountType::ASSET === $account->accountType->type) {
$frontPage[] = $account->id;
app('preferences')->set('frontPageAccounts', $frontPage);

View File

@ -195,7 +195,7 @@ class EditController extends Controller
$request->session()->flash('success', (string)trans('firefly.updated_account', ['name' => $account->name]));
// store new attachment(s):
/** @var array|null $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($account, $files);

View File

@ -207,14 +207,14 @@ class ReconcileController extends Controller
* @param Carbon $end
* @param string $difference
*
* @return RedirectResponse|Redirector|string
* @return string
* @throws DuplicateTransactionException
* @throws JsonException
*/
private function createReconciliation(Account $account, Carbon $start, Carbon $end, string $difference)
private function createReconciliation(Account $account, Carbon $start, Carbon $end, string $difference): string
{
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account);
return 'not-editable';
}
$reconciliation = $this->accountRepos->getReconciliation($account);

View File

@ -170,6 +170,9 @@ class TwoFactorController extends Controller
private function isBackupCode(string $mfaCode): bool
{
$list = app('preferences')->get('mfa_recovery', [])->data;
if(!is_array($list)) {
$list = [];
}
if (in_array($mfaCode, $list, true)) {
return true;
}
@ -185,6 +188,9 @@ class TwoFactorController extends Controller
private function removeFromBackupCodes(string $mfaCode): void
{
$list = app('preferences')->get('mfa_recovery', [])->data;
if(!is_array($list)) {
$list = [];
}
$newList = array_values(array_diff($list, [$mfaCode]));
app('preferences')->set('mfa_recovery', $newList);
}

View File

@ -138,6 +138,11 @@ class BudgetLimitController extends Controller
}
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
if (false === $start || false === $end) {
return response()->json([]);
}
$amount = (string)$request->get('amount');
$start->startOfDay();
$end->startOfDay();

View File

@ -125,6 +125,7 @@ class CreateController extends Controller
app('preferences')->mark();
// store attachment(s):
/** @var array|null $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($budget, $files);

View File

@ -101,7 +101,11 @@ class EditController extends Controller
'auto_budget_currency_id' => $hasOldInput ? (int)$request->old('auto_budget_currency_id') : $currency->id,
];
if (null !== $autoBudget) {
$amount = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount;
$amount = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount;
if (is_array($amount)) {
$amount = '0';
}
$amount = (string)$amount;
$preFilled['auto_budget_amount'] = app('steam')->bcround($amount, $autoBudget->transactionCurrency->decimal_places);
}
@ -135,6 +139,7 @@ class EditController extends Controller
$redirect = redirect($this->getPreviousUrl('budgets.edit.url'));
// store new attachment(s):
/** @var array|null $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($budget, $files);

View File

@ -98,6 +98,7 @@ class CreateController extends Controller
app('preferences')->mark();
// store attachment(s):
/** @var array|null $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($category, $files);

View File

@ -105,6 +105,7 @@ class EditController extends Controller
app('preferences')->mark();
// store new attachment(s):
/** @var array|null $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($category, $files);

View File

@ -335,13 +335,14 @@ class AccountController extends Controller
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
$defaultSet = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])->pluck('id')->toArray();
app('log')->debug('Default set is ', $defaultSet);
$frontPage = app('preferences')->get('frontPageAccounts', $defaultSet);
app('log')->debug('Frontpage preference set is ', $frontPage->data);
if (0 === count($frontPage->data)) {
$frontPage = app('preferences')->get('frontPageAccounts', $defaultSet);
$frontPageArray = !is_array($frontPage->data) ? [] : $frontPage->data;
app('log')->debug('Frontpage preference set is ', $frontPageArray);
if (0 === count($frontPageArray)) {
app('preferences')->set('frontPageAccounts', $defaultSet);
app('log')->debug('frontpage set is empty!');
}
$accounts = $repository->getAccountsById($frontPage->data);
$accounts = $repository->getAccountsById($frontPageArray);
return response()->json($this->accountBalanceChart($accounts, $start, $end));
}

View File

@ -74,8 +74,8 @@ abstract class Controller extends BaseController
app('view')->share('logoutUrl', $logoutUrl);
// upload size
$maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = app('steam')->phpBytes(ini_get('post_max_size'));
$maxFileSize = app('steam')->phpBytes((string)ini_get('upload_max_filesize'));
$maxPostSize = app('steam')->phpBytes((string)ini_get('post_max_size'));
$uploadSize = min($maxFileSize, $maxPostSize);
app('view')->share('uploadSize', $uploadSize);

View File

@ -141,7 +141,7 @@ class DebugController extends Controller
}
if ('' !== $logContent) {
// last few lines
$logContent = 'Truncated from this point <----|' . substr($logContent, -16384);
$logContent = 'Truncated from this point <----|' . substr((string)$logContent, -16384);
}
return view('debug', compact('table', 'now', 'logContent'));
@ -166,8 +166,8 @@ class DebugController extends Controller
*/
private function getSystemInformation(): array
{
$maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = app('steam')->phpBytes(ini_get('post_max_size'));
$maxFileSize = app('steam')->phpBytes((string)ini_get('upload_max_filesize'));
$maxPostSize = app('steam')->phpBytes((string)ini_get('post_max_size'));
$drivers = DB::availableDrivers();
$currentDriver = DB::getDriverName();
return [
@ -199,7 +199,7 @@ class DebugController extends Controller
];
try {
if (file_exists('/var/www/counter-main.txt')) {
$return['build'] = trim(file_get_contents('/var/www/counter-main.txt'));
$return['build'] = trim((string)file_get_contents('/var/www/counter-main.txt'));
}
} catch (Exception $e) { // @phpstan-ignore-line
app('log')->debug('Could not check build counter, but thats ok.');
@ -207,7 +207,7 @@ class DebugController extends Controller
}
try {
if (file_exists('/var/www/build-date-main.txt')) {
$return['build_date'] = trim(file_get_contents('/var/www/build-date-main.txt'));
$return['build_date'] = trim((string)file_get_contents('/var/www/build-date-main.txt'));
}
} catch (Exception $e) { // @phpstan-ignore-line
app('log')->debug('Could not check build date, but thats ok.');
@ -236,7 +236,7 @@ class DebugController extends Controller
if ($lastTime > 0) {
$carbon = Carbon::createFromTimestamp($lastTime);
$lastCronjob = $carbon->format('Y-m-d H:i:s');
$lastCronjobAgo = $carbon->locale('en')->diffForHumans();
$lastCronjobAgo = $carbon->locale('en')->diffForHumans(); // @phpstan-ignore-line
}
return [
@ -279,7 +279,7 @@ class DebugController extends Controller
$result = setlocale(LC_ALL, $code);
$localeAttempts[$code] = $result === $code;
}
setlocale(LC_ALL, $original);
setlocale(LC_ALL, (string) $original);
return [
'user_id' => auth()->user()->id,

View File

@ -25,7 +25,9 @@ namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@ -33,7 +35,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
/**
* FireflyIII\Models\TransactionCurrency
*
@ -47,7 +49,7 @@ use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
* @property string $code
* @property string $name
* @property string $symbol
* @property int|string $decimal_places
* @property int $decimal_places
* @property-read Collection|BudgetLimit[] $budgetLimits
* @property-read int|null $budget_limits_count
* @property-read Collection|TransactionJournal[] $transactionJournals
@ -82,7 +84,7 @@ class TransactionCurrency extends Model
public ?bool $userDefault;
public ?bool $userEnabled;
protected $casts
protected $casts
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
@ -170,4 +172,14 @@ class TransactionCurrency extends Model
{
return $this->belongsToMany(User::class)->withTimestamps()->withPivot('user_default');
}
/**
* @return Attribute
*/
protected function decimalPlaces(): Attribute
{
return Attribute::make(
get: static fn($value) => (int)$value,
);
}
}

View File

@ -88,12 +88,12 @@ class BillRepository implements BillRepositoryInterface
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'native_id' => (string)$default->id,
'native_name' => $default->name,
'native_symbol' => $default->symbol,
'native_code' => $default->code,
'native_decimal_places' => (int)$default->decimal_places,
'native_decimal_places' => $default->decimal_places,
'sum' => '0',
'native_sum' => '0',
];
@ -162,12 +162,12 @@ class BillRepository implements BillRepositoryInterface
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'native_id' => (string)$default->id,
'native_name' => $default->name,
'native_symbol' => $default->symbol,
'native_code' => $default->code,
'native_decimal_places' => (int)$default->decimal_places,
'native_decimal_places' => $default->decimal_places,
'sum' => '0',
'native_sum' => '0',
];

View File

@ -64,7 +64,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
'native_code' => $default->code,
'native_symbol' => $default->symbol,
'native_name' => $default->name,
'native_decimal_places' => (int)$default->decimal_places,
'native_decimal_places' => $default->decimal_places,
'amount' => '0',
'native_amount' => '0',
];

View File

@ -200,7 +200,7 @@ class TransactionGroupTwig extends AbstractExtension
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($currency->symbol, (int)$currency->decimal_places, $amount, $colored);
$result = app('amount')->formatFlat($currency->symbol, $currency->decimal_places, $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info money-transfer">%s</span>', $result);
}
@ -243,7 +243,7 @@ class TransactionGroupTwig extends AbstractExtension
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($currency->symbol, (int)$currency->decimal_places, $amount, $colored);
$result = app('amount')->formatFlat($currency->symbol, $currency->decimal_places, $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info money-transfer">%s</span>', $result);
}

View File

@ -68,7 +68,7 @@ class AvailableBudgetTransformer extends AbstractTransformer
'currency_id' => (string)$currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'amount' => app('steam')->bcround($availableBudget->amount, $currency->decimal_places),
'start' => $availableBudget->start_date->toAtomString(),
'end' => $availableBudget->end_date->endOfDay()->toAtomString(),

View File

@ -128,7 +128,7 @@ class BillTransformer extends AbstractTransformer
'currency_id' => (string)$bill->transaction_currency_id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'name' => $bill->name,
'amount_min' => app('steam')->bcround($bill->amount_min, $currency->decimal_places),
'amount_max' => app('steam')->bcround($bill->amount_max, $currency->decimal_places),

View File

@ -48,7 +48,7 @@ class CurrencyTransformer extends AbstractTransformer
'name' => $currency->name,
'code' => $currency->code,
'symbol' => $currency->symbol,
'decimal_places' => (int)$currency->decimal_places,
'decimal_places' => $currency->decimal_places,
'links' => [
[
'rel' => 'self',

View File

@ -85,7 +85,7 @@ class PiggyBankEventTransformer extends AbstractTransformer
'currency_id' => (string)$currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'transaction_journal_id' => null !== $journalId ? (string)$journalId : null,
'transaction_group_id' => null !== $groupId ? (string)$groupId : null,
'links' => [

View File

@ -112,7 +112,7 @@ class PiggyBankTransformer extends AbstractTransformer
'currency_id' => (string)$currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'target_amount' => $targetAmount,
'percentage' => $percentage,
'current_amount' => $currentAmount,

View File

@ -415,7 +415,7 @@ class TransactionGroupTransformer extends AbstractTransformer
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'foreign_currency_id' => $foreignCurrency['id'],
'foreign_currency_code' => $foreignCurrency['code'],
@ -592,7 +592,7 @@ class TransactionGroupTransformer extends AbstractTransformer
$array['id'] = $currency->id;
$array['code'] = $currency->code;
$array['symbol'] = $currency->symbol;
$array['decimal_places'] = (int)$currency->decimal_places;
$array['decimal_places'] = $currency->decimal_places;
return $array;
}

View File

@ -144,7 +144,7 @@ class AccountTransformer extends AbstractTransformer
'currency_id' => (string)$currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'native_currency_id' => (string)$this->default->id,
'native_currency_code' => $this->default->code,

View File

@ -207,7 +207,7 @@ class BillTransformer extends AbstractTransformer
'currency_code' => $currency->code,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'native_currency_id' => $this->default->id,
'native_currency_code' => $this->default->code,
'native_currency_name' => $this->default->name,

View File

@ -56,7 +56,7 @@ class CurrencyTransformer extends AbstractTransformer
'name' => $currency->name,
'code' => $currency->code,
'symbol' => $currency->symbol,
'decimal_places' => (int)$currency->decimal_places,
'decimal_places' => $currency->decimal_places,
'links' => [
[
'rel' => 'self',

View File

@ -208,7 +208,7 @@ class PiggyBankTransformer extends AbstractTransformer
'currency_id' => (string)$currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places,
'currency_decimal_places' => $currency->decimal_places,
'native_currency_id' => (string)$this->default->id,
'native_currency_code' => $this->default->code,
'native_currency_symbol' => $this->default->symbol,

View File

@ -14,6 +14,7 @@
stopOnFailure="true">
<php>
<env name="APP_ENV" value="testing"/>
<env name="APP_LOG_ENV" value="notice"/>
<ini name="xdebug.mode" value="coverage"/>
</php>
<testsuites>

View File

@ -46,8 +46,9 @@
<tr>
<td>{{ 'next_expected_match'|_ }}</td>
<td>
{% if object.data.next_expected_match|length > 0 %}
{{ formatDate(object.data.next_expected_match, monthAndDayFormat) }}
{% if object.data.pay_dates|length > 0 %}
{{ formatDate(object.data.pay_dates[0], monthAndDayFormat) }}
{% else %}
{{ 'unknown'|_ }}
{% endif %}

View File

@ -45,7 +45,14 @@ class BillDateCalculatorTest extends TestCase
// Carbon $earliest, Carbon $latest, Carbon $billStart, string $period, int $skip, ?Carbon $lastPaid
return [
// basic monthly bill.
'1M' => ['earliest' => Carbon::parse('2023-11-01'), 'latest' => Carbon::parse('2023-11-30'), 'billStart' => Carbon::parse('2023-01-01'), 'period' => 'monthly', 'skip' => 0, 'lastPaid' => null, 'expected' => ['2023-11-01']],
'1Ma' => ['earliest' => Carbon::parse('2023-11-01'), 'latest' => Carbon::parse('2023-11-30'), 'billStart' => Carbon::parse('2023-01-01'), 'period' => 'monthly', 'skip' => 0, 'lastPaid' => null, 'expected' => ['2023-11-01']],
// already paid on the first, expect it next month.
'1Mb' => ['earliest' => Carbon::parse('2023-11-01'), 'latest' => Carbon::parse('2023-11-30'), 'billStart' => Carbon::parse('2023-01-01'), 'period' => 'monthly', 'skip' => 0, 'lastPaid' => Carbon::parse('2023-11-01'), 'expected' => ['2023-12-01']],
// already paid on the 12th, expect it next month.
'1Mc' => ['earliest' => Carbon::parse('2023-11-01'), 'latest' => Carbon::parse('2023-11-30'), 'billStart' => Carbon::parse('2023-01-01'), 'period' => 'monthly', 'skip' => 0, 'lastPaid' => Carbon::parse('2023-11-12'), 'expected' => ['2023-12-01']],
// yearly not due this month. Should jump to next year.
'1Ya' => ['earliest' => Carbon::parse('2023-11-01'), 'latest' => Carbon::parse('2023-11-30'), 'billStart' => Carbon::parse('2021-05-01'), 'period' => 'yearly', 'skip' => 0, 'lastPaid' => Carbon::parse('2023-05-02'), 'expected' => ['2024-05-01']],
];
}