From 77ea246fc314323d5742c88a464bf55343172b6d Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 12 Aug 2019 16:59:23 +0200 Subject: [PATCH] New files for future release. --- .../Category/WholePeriodChartGenerator.php | 166 ++++++++++++++ config/ide-helper.php | 208 ++++++++++++++++++ 2 files changed, 374 insertions(+) create mode 100644 app/Support/Chart/Category/WholePeriodChartGenerator.php create mode 100644 config/ide-helper.php diff --git a/app/Support/Chart/Category/WholePeriodChartGenerator.php b/app/Support/Chart/Category/WholePeriodChartGenerator.php new file mode 100644 index 0000000000..fed2283eea --- /dev/null +++ b/app/Support/Chart/Category/WholePeriodChartGenerator.php @@ -0,0 +1,166 @@ +. + */ + +namespace FireflyIII\Support\Chart\Category; + +use Carbon\Carbon; +use FireflyIII\Models\AccountType; +use FireflyIII\Models\Category; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Category\CategoryRepositoryInterface; + +/** + * Class WholePeriodChartGenerator + */ +class WholePeriodChartGenerator +{ + /** + * @param Category $category + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function generate(Category $category, Carbon $start, Carbon $end): array + { + /** @var CategoryRepositoryInterface $repository */ + $repository = app(CategoryRepositoryInterface::class); + + /** @var AccountRepositoryInterface $accountRepository */ + $accountRepository = app(AccountRepositoryInterface::class); + + $types = [AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]; + $accounts = $accountRepository->getAccountsByType($types); + $step = $this->calculateStep($start, $end); + $chartData = []; + $spent = []; + $earned = []; + + /** @var Carbon $current */ + $current = clone $start; + + while ($current <= $end) { + $key = $current->format('Y-m-d'); + $currentEnd = app('navigation')->endOfPeriod($current, $step); + $spent[$key] = $repository->spentInPeriod($category, $accounts, $current, $currentEnd); + $earned[$key] = $repository->earnedInPeriod($category, $accounts, $current, $currentEnd); + $current = app('navigation')->addPeriod($current, $step, 0); + } + $currencies = $this->extractCurrencies($spent) + $this->extractCurrencies($earned); + + // generate chart data (for each currency) + /** @var array $currency */ + foreach ($currencies as $currency) { + $code = $currency['currency_code']; + $name = $currency['currency_name']; + $chartData[sprintf('spent-in-%s', $code)] = [ + 'label' => (string)trans('firefly.box_spent_in_currency', ['currency' => $name]), + 'entries' => [], + 'type' => 'bar', + 'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red + ]; + + $chartData[sprintf('earned-in-%s', $code)] = [ + 'label' => (string)trans('firefly.box_earned_in_currency', ['currency' => $name]), + 'entries' => [], + 'type' => 'bar', + 'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green + ]; + } + + /** @var Carbon $current */ + $current = clone $start; + + while ($current <= $end) { + $key = $current->format('Y-m-d'); + $label = app('navigation')->periodShow($current, $step); + + /** @var array $currency */ + foreach ($currencies as $currency) { + $code = $currency['currency_code']; + $spentInfoKey = sprintf('spent-in-%s', $code); + $earnedInfoKey = sprintf('earned-in-%s', $code); + $spentAmount = $spent[$key][$code]['spent'] ?? '0'; + $earnedAmount = $earned[$key][$code]['earned'] ?? '0'; + $chartData[$spentInfoKey]['entries'][$label] = round($spentAmount, $currency['currency_decimal_places']); + $chartData[$earnedInfoKey]['entries'][$label] = round($earnedAmount, $currency['currency_decimal_places']); + } + $current = app('navigation')->addPeriod($current, $step, 0); + } + return $chartData; + } + + /** + * TODO is a duplicate function. + * + * @param Carbon $start + * @param Carbon $end + * + * @return string + */ + protected function calculateStep(Carbon $start, Carbon $end): string + { + + $step = '1D'; + $months = $start->diffInMonths($end); + if ($months > 3) { + $step = '1W'; // @codeCoverageIgnore + } + if ($months > 24) { + $step = '1M'; // @codeCoverageIgnore + } + if ($months > 100) { + $step = '1Y'; // @codeCoverageIgnore + } + + return $step; + } + + /** + * Loop array of spent/earned info, and extract which currencies are present. + * Key is the currency ID. + * + * @param array $array + * + * @return array + */ + private function extractCurrencies(array $array): array + { + $return = []; + foreach ($array as $info) { + foreach ($info as $block) { + $currencyId = $block['currency_id']; + if (!isset($return[$currencyId])) { + $return[$currencyId] = [ + 'currency_id' => $block['currency_id'], + 'currency_code' => $block['currency_code'], + 'currency_name' => $block['currency_name'], + 'currency_symbol' => $block['currency_symbol'], + 'currency_decimal_places' => $block['currency_decimal_places'], + ]; + } + } + } + + return $return; + } + +} \ No newline at end of file diff --git a/config/ide-helper.php b/config/ide-helper.php new file mode 100644 index 0000000000..9eb1e27063 --- /dev/null +++ b/config/ide-helper.php @@ -0,0 +1,208 @@ + '_ide_helper', + 'format' => 'php', + + 'meta_filename' => '.phpstorm.meta.php', + + /* + |-------------------------------------------------------------------------- + | Fluent helpers + |-------------------------------------------------------------------------- + | + | Set to true to generate commonly used Fluent methods + | + */ + + 'include_fluent' => true, + + /* + |-------------------------------------------------------------------------- + | Write Model Magic methods + |-------------------------------------------------------------------------- + | + | Set to false to disable write magic methods of model + | + */ + + 'write_model_magic_where' => true, + + /* + |-------------------------------------------------------------------------- + | Write Eloquent Model Mixins + |-------------------------------------------------------------------------- + | + | This will add the necessary DocBlock mixins to the model class + | contained in the Laravel Framework. This helps the IDE with + | auto-completion. + | + | Please be aware that this setting changes a file within the /vendor directory. + | + */ + + 'write_eloquent_model_mixins' => false, + + /* + |-------------------------------------------------------------------------- + | Helper files to include + |-------------------------------------------------------------------------- + | + | Include helper files. By default not included, but can be toggled with the + | -- helpers (-H) option. Extra helper files can be included. + | + */ + + 'include_helpers' => false, + + 'helper_files' => array( + base_path().'/vendor/laravel/framework/src/Illuminate/Support/helpers.php', + ), + + /* + |-------------------------------------------------------------------------- + | Model locations to include + |-------------------------------------------------------------------------- + | + | Define in which directories the ide-helper:models command should look + | for models. + | + */ + + 'model_locations' => array( + 'app', + ), + + + /* + |-------------------------------------------------------------------------- + | Extra classes + |-------------------------------------------------------------------------- + | + | These implementations are not really extended, but called with magic functions + | + */ + + 'extra' => array( + 'Eloquent' => array('Illuminate\Database\Eloquent\Builder', 'Illuminate\Database\Query\Builder'), + 'Session' => array('Illuminate\Session\Store'), + ), + + 'magic' => array( + 'Log' => array( + 'debug' => 'Monolog\Logger::addDebug', + 'info' => 'Monolog\Logger::addInfo', + 'notice' => 'Monolog\Logger::addNotice', + 'warning' => 'Monolog\Logger::addWarning', + 'error' => 'Monolog\Logger::addError', + 'critical' => 'Monolog\Logger::addCritical', + 'alert' => 'Monolog\Logger::addAlert', + 'emergency' => 'Monolog\Logger::addEmergency', + ) + ), + + /* + |-------------------------------------------------------------------------- + | Interface implementations + |-------------------------------------------------------------------------- + | + | These interfaces will be replaced with the implementing class. Some interfaces + | are detected by the helpers, others can be listed below. + | + */ + + 'interfaces' => array( + + ), + + /* + |-------------------------------------------------------------------------- + | Support for custom DB types + |-------------------------------------------------------------------------- + | + | This setting allow you to map any custom database type (that you may have + | created using CREATE TYPE statement or imported using database plugin + | / extension to a Doctrine type. + | + | Each key in this array is a name of the Doctrine2 DBAL Platform. Currently valid names are: + | 'postgresql', 'db2', 'drizzle', 'mysql', 'oracle', 'sqlanywhere', 'sqlite', 'mssql' + | + | This name is returned by getName() method of the specific Doctrine/DBAL/Platforms/AbstractPlatform descendant + | + | The value of the array is an array of type mappings. Key is the name of the custom type, + | (for example, "jsonb" from Postgres 9.4) and the value is the name of the corresponding Doctrine2 type (in + | our case it is 'json_array'. Doctrine types are listed here: + | http://doctrine-dbal.readthedocs.org/en/latest/reference/types.html + | + | So to support jsonb in your models when working with Postgres, just add the following entry to the array below: + | + | "postgresql" => array( + | "jsonb" => "json_array", + | ), + | + */ + 'custom_db_types' => array( + + ), + + /* + |-------------------------------------------------------------------------- + | Support for camel cased models + |-------------------------------------------------------------------------- + | + | There are some Laravel packages (such as Eloquence) that allow for accessing + | Eloquent model properties via camel case, instead of snake case. + | + | Enabling this option will support these packages by saving all model + | properties as camel case, instead of snake case. + | + | For example, normally you would see this: + | + | * @property \Illuminate\Support\Carbon $created_at + | * @property \Illuminate\Support\Carbon $updated_at + | + | With this enabled, the properties will be this: + | + | * @property \Illuminate\Support\Carbon $createdAt + | * @property \Illuminate\Support\Carbon $updatedAt + | + | Note, it is currently an all-or-nothing option. + | + */ + 'model_camel_case_properties' => false, + + /* + |-------------------------------------------------------------------------- + | Property Casts + |-------------------------------------------------------------------------- + | + | Cast the given "real type" to the given "type". + | + */ + 'type_overrides' => array( + 'integer' => 'int', + 'boolean' => 'bool', + ), + + /* + |-------------------------------------------------------------------------- + | Include DocBlocks from classes + |-------------------------------------------------------------------------- + | + | Include DocBlocks from classes to allow additional code inspection for + | magic methods and properties. + | + */ + 'include_class_docblocks' => false, + +);