diff --git a/app/Support/Export/ExportDataGenerator.php b/app/Support/Export/ExportDataGenerator.php index 6c6dc13ca9..162200cd52 100644 --- a/app/Support/Export/ExportDataGenerator.php +++ b/app/Support/Export/ExportDataGenerator.php @@ -25,6 +25,8 @@ declare(strict_types=1); namespace FireflyIII\Support\Export; use Carbon\Carbon; +use FireflyIII\Enums\AccountTypeEnum; +use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Models\Account; @@ -50,6 +52,8 @@ use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface; use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface; +use FireflyIII\Support\Facades\Amount; +use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\User; use Illuminate\Support\Collection; @@ -82,8 +86,8 @@ class ExportDataGenerator public function __construct() { - $this->accounts = new Collection(); - $this->start = today(config('app.timezone')); + $this->accounts = new Collection(); + $this->start = today(config('app.timezone')); $this->start->subYear(); $this->end = today(config('app.timezone')); $this->exportTransactions = false; @@ -141,7 +145,7 @@ class ExportDataGenerator */ private function exportAccounts(): string { - $header = [ + $header = [ 'user_id', 'account_id', 'created_at', @@ -162,7 +166,7 @@ class ExportDataGenerator ]; /** @var AccountRepositoryInterface $repository */ - $repository = app(AccountRepositoryInterface::class); + $repository = app(AccountRepositoryInterface::class); $repository->setUser($this->user); $allAccounts = $repository->getAccountsByType([]); $records = []; @@ -192,7 +196,7 @@ class ExportDataGenerator } // load the CSV document from a string - $csv = Writer::createFromString(); + $csv = Writer::createFromString(); // insert the header try { @@ -230,8 +234,8 @@ class ExportDataGenerator /** @var BillRepositoryInterface $repository */ $repository = app(BillRepositoryInterface::class); $repository->setUser($this->user); - $bills = $repository->getBills(); - $header = [ + $bills = $repository->getBills(); + $header = [ 'user_id', 'bill_id', 'created_at', @@ -245,7 +249,7 @@ class ExportDataGenerator 'skip', 'active', ]; - $records = []; + $records = []; /** @var Bill $bill */ foreach ($bills as $bill) { @@ -266,7 +270,7 @@ class ExportDataGenerator } // load the CSV document from a string - $csv = Writer::createFromString(); + $csv = Writer::createFromString(); // insert the header try { @@ -296,7 +300,7 @@ class ExportDataGenerator */ private function exportBudgets(): string { - $header = [ + $header = [ 'user_id', 'budget_id', 'name', @@ -310,9 +314,9 @@ class ExportDataGenerator $budgetRepos = app(BudgetRepositoryInterface::class); $budgetRepos->setUser($this->user); - $limitRepos = app(BudgetLimitRepositoryInterface::class); - $budgets = $budgetRepos->getBudgets(); - $records = []; + $limitRepos = app(BudgetLimitRepositoryInterface::class); + $budgets = $budgetRepos->getBudgets(); + $records = []; /** @var Budget $budget */ foreach ($budgets as $budget) { @@ -335,7 +339,7 @@ class ExportDataGenerator } // load the CSV document from a string - $csv = Writer::createFromString(); + $csv = Writer::createFromString(); // insert the header try { @@ -365,10 +369,10 @@ class ExportDataGenerator */ private function exportCategories(): string { - $header = ['user_id', 'category_id', 'created_at', 'updated_at', 'name']; + $header = ['user_id', 'category_id', 'created_at', 'updated_at', 'name']; /** @var CategoryRepositoryInterface $catRepos */ - $catRepos = app(CategoryRepositoryInterface::class); + $catRepos = app(CategoryRepositoryInterface::class); $catRepos->setUser($this->user); $records = []; @@ -386,7 +390,7 @@ class ExportDataGenerator } // load the CSV document from a string - $csv = Writer::createFromString(); + $csv = Writer::createFromString(); // insert the header try { @@ -417,14 +421,14 @@ class ExportDataGenerator private function exportPiggies(): string { /** @var PiggyBankRepositoryInterface $piggyRepos */ - $piggyRepos = app(PiggyBankRepositoryInterface::class); + $piggyRepos = app(PiggyBankRepositoryInterface::class); $piggyRepos->setUser($this->user); /** @var AccountRepositoryInterface $accountRepos */ $accountRepos = app(AccountRepositoryInterface::class); $accountRepos->setUser($this->user); - $header = [ + $header = [ 'user_id', 'piggy_bank_id', 'created_at', @@ -440,8 +444,8 @@ class ExportDataGenerator 'order', 'active', ]; - $records = []; - $piggies = $piggyRepos->getPiggyBanks(); + $records = []; + $piggies = $piggyRepos->getPiggyBanks(); /** @var PiggyBank $piggy */ foreach ($piggies as $piggy) { @@ -466,7 +470,7 @@ class ExportDataGenerator } // load the CSV document from a string - $csv = Writer::createFromString(); + $csv = Writer::createFromString(); // insert the header try { @@ -499,7 +503,7 @@ class ExportDataGenerator /** @var RecurringRepositoryInterface $recurringRepos */ $recurringRepos = app(RecurringRepositoryInterface::class); $recurringRepos->setUser($this->user); - $header = [ + $header = [ // recurrence: 'user_id', 'recurrence_id', 'row_contains', 'created_at', 'updated_at', 'type', 'title', 'description', 'first_date', 'repeat_until', 'latest_date', 'repetitions', 'apply_rules', 'active', @@ -508,8 +512,8 @@ class ExportDataGenerator // transactions + meta: 'currency_code', 'foreign_currency_code', 'source_name', 'source_type', 'destination_name', 'destination_type', 'amount', 'foreign_amount', 'category', 'budget', 'piggy_bank', 'tags', ]; - $records = []; - $recurrences = $recurringRepos->getAll(); + $records = []; + $recurrences = $recurringRepos->getAll(); /** @var Recurrence $recurrence */ foreach ($recurrences as $recurrence) { @@ -542,7 +546,7 @@ class ExportDataGenerator $piggyBankId = $recurringRepos->getPiggyBank($transaction); $tags = $recurringRepos->getTags($transaction); - $records[] = [ + $records[] = [ // recurrence $this->user->id, $recurrence->id, @@ -558,7 +562,7 @@ class ExportDataGenerator } } // load the CSV document from a string - $csv = Writer::createFromString(); + $csv = Writer::createFromString(); // insert the header try { @@ -595,8 +599,8 @@ class ExportDataGenerator 'action_type', 'action_value', 'action_order', 'action_active', 'action_stop_processing']; $ruleRepos = app(RuleRepositoryInterface::class); $ruleRepos->setUser($this->user); - $rules = $ruleRepos->getAll(); - $records = []; + $rules = $ruleRepos->getAll(); + $records = []; /** @var Rule $rule */ foreach ($rules as $rule) { @@ -635,7 +639,7 @@ class ExportDataGenerator } // load the CSV document from a string - $csv = Writer::createFromString(); + $csv = Writer::createFromString(); // insert the header try { @@ -665,12 +669,12 @@ class ExportDataGenerator */ private function exportTags(): string { - $header = ['user_id', 'tag_id', 'created_at', 'updated_at', 'tag', 'date', 'description', 'latitude', 'longitude', 'zoom_level']; + $header = ['user_id', 'tag_id', 'created_at', 'updated_at', 'tag', 'date', 'description', 'latitude', 'longitude', 'zoom_level']; $tagRepos = app(TagRepositoryInterface::class); $tagRepos->setUser($this->user); - $tags = $tagRepos->get(); - $records = []; + $tags = $tagRepos->get(); + $records = []; /** @var Tag $tag */ foreach ($tags as $tag) { @@ -689,7 +693,7 @@ class ExportDataGenerator } // load the CSV document from a string - $csv = Writer::createFromString(); + $csv = Writer::createFromString(); // insert the header try { @@ -728,33 +732,57 @@ class ExportDataGenerator private function exportTransactions(): string { // TODO better place for keys? - $header = ['user_id', 'group_id', 'journal_id', 'created_at', 'updated_at', 'group_title', 'type', 'amount', 'foreign_amount', 'currency_code', 'foreign_currency_code', 'description', 'date', 'source_name', 'source_iban', 'source_type', 'destination_name', 'destination_iban', 'destination_type', 'reconciled', 'category', 'budget', 'bill', 'tags', 'notes']; + $header = ['user_id', 'group_id', 'journal_id', 'created_at', 'updated_at', 'group_title', 'type', 'currency_code', 'amount', 'foreign_currency_code', 'foreign_amount', 'native_currency_code', 'native_amount', 'native_foreign_amount', 'description', 'date', 'source_name', 'source_iban', 'source_type', 'destination_name', 'destination_iban', 'destination_type', 'reconciled', 'category', 'budget', 'bill', 'tags', 'notes']; $metaFields = config('firefly.journal_meta_fields'); $header = array_merge($header, $metaFields); + $default = Amount::getDefaultCurrency(); - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setUser($this->user); - $collector->setRange($this->start, $this->end)->withAccountInformation()->withCategoryInformation()->withBillInformation() - ->withBudgetInformation()->withTagInformation()->withNotes() - ; + $collector->setRange($this->start, $this->end)->withAccountInformation()->withCategoryInformation()->withBillInformation()->withBudgetInformation()->withTagInformation()->withNotes(); if (0 !== $this->accounts->count()) { $collector->setAccounts($this->accounts); } - $journals = $collector->getExtractedJournals(); + $journals = $collector->getExtractedJournals(); // get repository for meta data: $repository = app(TransactionGroupRepositoryInterface::class); $repository->setUser($this->user); - $records = []; + $records = []; /** @var array $journal */ foreach ($journals as $journal) { - $metaData = $repository->getMetaFields($journal['transaction_journal_id'], $metaFields); + $metaData = $repository->getMetaFields($journal['transaction_journal_id'], $metaFields); + $amount = Steam::bcround(Steam::negative($journal['amount']), $journal['currency_decimal_places']); + $foreignAmount = null === $journal['foreign_amount'] ? null : Steam::bcround(Steam::negative($journal['foreign_amount']), $journal['foreign_currency_decimal_places']); + $nativeAmount = null === $journal['native_amount'] ? null : Steam::bcround(Steam::negative($journal['native_amount'], $default->decimal_places)); + $nativeForeignAmount = null === $journal['native_foreign_amount'] ? null : Steam::bcround(Steam::negative($journal['native_foreign_amount'], $default->decimal_places)); + + if (TransactionTypeEnum::WITHDRAWAL->value !== $journal['transaction_type_type']) { + $amount = Steam::bcround(Steam::positive($journal['amount']), $journal['currency_decimal_places']); + $foreignAmount = null === $journal['foreign_amount'] ? null : Steam::bcround(Steam::positive($journal['foreign_amount']), $journal['foreign_currency_decimal_places']); + $nativeAmount = null === $journal['native_amount'] ? null : Steam::bcround(Steam::positive($journal['native_amount'], $default->decimal_places)); + $nativeForeignAmount = null === $journal['native_foreign_amount'] ? null : Steam::bcround(Steam::positive($journal['native_foreign_amount'], $default->decimal_places)); + } + + // opening balance depends on source account type. + if (TransactionTypeEnum::OPENING_BALANCE->value === $journal['transaction_type_type'] && AccountTypeEnum::ASSET->value === $journal['source_account_type']) { + $amount = Steam::bcround(Steam::negative($journal['amount']), $journal['currency_decimal_places']); + $foreignAmount = null === $journal['foreign_amount'] ? null : Steam::bcround(Steam::negative($journal['foreign_amount']), $journal['foreign_currency_decimal_places']); + $nativeAmount = null === $journal['native_amount'] ? null : Steam::bcround(Steam::negative($journal['native_amount'], $default->decimal_places)); + $nativeForeignAmount = null === $journal['native_foreign_amount'] ? null : Steam::bcround(Steam::negative($journal['native_foreign_amount'], $default->decimal_places)); + } + $records[] = [ - $journal['user_id'], $journal['transaction_group_id'], $journal['transaction_journal_id'], $journal['created_at']->toAtomString(), $journal['updated_at']->toAtomString(), $journal['transaction_group_title'], $journal['transaction_type_type'], $journal['amount'], $journal['foreign_amount'], $journal['currency_code'], $journal['foreign_currency_code'], $journal['description'], $journal['date']->toAtomString(), $journal['source_account_name'], $journal['source_account_iban'], $journal['source_account_type'], $journal['destination_account_name'], $journal['destination_account_iban'], $journal['destination_account_type'], $journal['reconciled'], $journal['category_name'], $journal['budget_name'], $journal['bill_name'], + $journal['user_id'], $journal['transaction_group_id'], $journal['transaction_journal_id'], $journal['created_at']->toAtomString(), $journal['updated_at']->toAtomString(), $journal['transaction_group_title'], $journal['transaction_type_type'], + // amounts and currencies + $journal['currency_code'], $amount, $journal['foreign_currency_code'], $foreignAmount, $default->code, $nativeAmount, $nativeForeignAmount, + + // more fields + $journal['description'], $journal['date']->toAtomString(), $journal['source_account_name'], $journal['source_account_iban'], $journal['source_account_type'], $journal['destination_account_name'], $journal['destination_account_iban'], $journal['destination_account_type'], $journal['reconciled'], $journal['category_name'], $journal['budget_name'], $journal['bill_name'], $this->mergeTags($journal['tags']), $this->clearStringKeepNewlines($journal['notes']), @@ -773,7 +801,7 @@ class ExportDataGenerator } // load the CSV document from a string - $csv = Writer::createFromString(); + $csv = Writer::createFromString(); // insert the header try {