All kinds of new stuff: finished most of the importing routines, extended the database (single table inheritance) and expanded some other stuff.

This commit is contained in:
James Cole
2014-07-05 19:44:26 +02:00
parent a0c0dc288d
commit 188105492c
26 changed files with 430 additions and 587 deletions

View File

@@ -11,6 +11,9 @@ class HomeController extends BaseController {
public function index()
{
$count = $this->accounts->count();
// build the home screen:
return View::make('index')->with('count',$count);
}
}

View File

@@ -19,6 +19,7 @@ class MigrationController extends BaseController
public function postIndex()
{
// @codeCoverageIgnoreStart
if (Input::hasFile('exportFile')) {
// get content:
@@ -31,487 +32,10 @@ class MigrationController extends BaseController
return View::make('error')->with('message', 'Invalid JSON content.');
}
$this->migration->migrate();
return 'busy!';
}
// then, start migrating!
//
//
// // map old and new id's.
// $map = [
// 'accounts' => [],
// 'beneficiaries' => [],
// ];
//
// // get the account types we need
// $beneficiaryAT = AccountType::where('description', 'Beneficiary account')->first();
//
// // save all accounts:
// foreach ($JSON->accounts as $entry) {
// // create account:
// if ($entry->openingbalance == 0) {
// $account = $this->accounts->store(['name' => $entry->name]);
// } else {
// $account = $this->accounts->storeWithInitialBalance(
// ['name' => $entry->name],
// new Carbon($entry->openingbalancedate),
// floatval($entry->openingbalance)
// );
// }
// $map['accounts'][$entry->id] = $account->id;
// }
// unset($entry);
//
// // save all components:
// foreach ($JSON->components as $entry) {
// switch ($entry->type->type) {
// case 'beneficiary':
// // create new account for beneficiary:
// $account = $this->accounts->store(['name' => $entry->name]);
// $map['beneficiaries'][$entry->id] = $account;
// break;
// case 'category':
// // create new component for category:
//// $account = $this->accounts->store(['name' => $entry->name]);
//// $map['beneficiaries'][$entry->id] = $account;
// break;
// }
// }
// unset($JSON->accounts);
//
//
// var_dump($JSON);
// var_dump($map);
//
// exit;
// }
//
return View::make('error')->with('message', 'No file found.');
}
/*
public function index()
{
// check if database connection is present.
$configValue = Config::get('database.connections.old-firefly');
if (is_null($configValue)) {
return View::make('migrate.index');
}
// try to connect to it:
$error = '';
try {
DB::connection('old-firefly')->select('SELECT * from `users`;');
} catch (PDOException $e) {
$error = $e->getMessage();
return View::make('migrate.index')->with('error', $error);
}
return Redirect::route('migrate.upload');
}
public function selectUser()
{
$oldUsers = [];
try {
$oldUsers = DB::connection('old-firefly')->select('SELECT * from `users`;');
} catch (PDOException $e) {
$error = $e->getMessage();
return View::make('migrate.index')->with('error', $error);
}
return View::make('migrate.select-user')->with('oldUsers', $oldUsers);
}
public function postSelectUser()
{
$userID = Input::get('user');
$count = DB::connection('old-firefly')->table('users')->where('id', $userID)->count();
if ($count == 1) {
return Redirect::route('migrate.migrate', $userID);
return Redirect::route('index');
} else {
return View::make('error')->with('message', 'No such user!');
return View::make('error')->with('message', 'No file selected');
}
// @codeCoverageIgnoreEnd
}
public function migrate($userID)
{
// import the data.
$user = Auth::user();
$previousUser = DB::connection('old-firefly')->table('users')->where('id', $userID)->first();
// current user already migrated?
if ($user->migrated) {
return View::make('error')->with('message', 'This user has already been migrated.');
}
// a map to keep the connections intact:
$map = [
'accounts' => [],
'beneficiaries' => [],
'categories' => [],
'budgets' => [],
];
// messages to show in result screen:
$messages = [];
// grab account types:
$defaultAT = AccountType::where('description', 'Default account')->first();
$initialBalanceAT = AccountType::where('description', 'Initial balance account')->first();
$beneficiaryAT = AccountType::where('description', 'Beneficiary account')->first();
// grab transaction types:
$initialBalanceTT = TransactionType::where('type', 'Opening balance')->first();
$depositTT = TransactionType::where('type', 'Deposit')->first();
$withdrawalTT = TransactionType::where('type', 'Withdrawal')->first();
$transferTT = TransactionType::where('type', 'Transfer')->first();
// grab currency:
$currency = TransactionCurrency::where('code', 'EUR')->first();
// grab component types:
$categoryType = ComponentType::where('type', 'category')->first();
$budgetType = ComponentType::where('type', 'budget')->first();
// create a special cash account for this user:
$cashAccount = new Account;
$cashAccount->name = 'Cash account';
$cashAccount->active = true;
$cashAccount->accountType()->associate($beneficiaryAT);
$cashAccount->user()->associate($user);
$cashAccount->save();
$messages[] = 'Created "cash" account.';
// get the old accounts:
$accounts = DB::connection('old-firefly')->table('accounts')->where('user_id', $previousUser->id)->get();
foreach ($accounts as $account) {
// already had one?
$existing = Account::where('name', $account->name)->where('account_type_id', $defaultAT->id)->where(
'user_id', $previousUser->id
)->first();
if (!is_null($existing)) {
$map['accounts'][$account->id] = $existing;
$messages[] = 'Skipped creating account ' . $account->name . ' because it already exists.';
continue;
}
unset($existing);
// create account:
$current = new Account;
$current->name = $account->name;
$current->active = true;
$current->accountType()->associate($defaultAT);
$current->user()->associate($user);
$current->save();
// map and information
$map['accounts'][$account->id] = $current;
$messages[] = 'Account "' . $current->name . '" recreated.';
// recreate opening balance, if relevant:
if (floatval($account->openingbalance) != 0) {
// now create another account, and create the first transfer indicating
$initial = new Account;
$initial->name = $account->name . ' initial balance';
$initial->accountType()->associate($initialBalanceAT);
$initial->active = 1;
$initial->user()->associate($user);
$initial->save();
// create a journal, and two transfers:
$journal = new TransactionJournal;
$journal->transactionType()->associate($initialBalanceTT);
$journal->transactionCurrency()->associate($currency);
$journal->description = $account->name . ' opening balance';
$journal->date = $account->openingbalancedate;
$journal->save();
// coming from a virtual account is:
$credit = new Transaction;
$credit->account()->associate($current);
$credit->transactionJournal()->associate($journal);
$credit->description = null;
$credit->amount = $account->openingbalance;
$credit->save();
// transfer into this new account
$debet = new Transaction;
$debet->account()->associate($initial);
$debet->transactionJournal()->associate($journal);
$debet->description = null;
$debet->amount = $account->openingbalance * -1;
$debet->save();
$messages[]
= 'Saved initial balance for ' . $current->name . ' (' . mf($account->openingbalance, true) . ')';
unset($initial, $journal, $credit, $debet);
}
unset($current);
}
// save all old components
$components = DB::connection('old-firefly')->table('components')->leftJoin(
'types', 'types.id', '=', 'components.type_id'
)->where('user_id', $previousUser->id)->get(['components.*', 'types.type']);
foreach ($components as $component) {
$id = $component->id;
switch ($component->type) {
case 'beneficiary':
if (!isset($map['beneficiaries'][$id])) {
// if it exists, skip:
$existing = Account::where('name', $component->name)->where('user_id', $user->id)->where(
'account_type_id', $beneficiaryAT->id
)->first();
if (!is_null($existing)) {
$map['beneficiaries'][$id] = $existing;
$messages[]
= 'Skipped creating beneficiary "' . $component->name . '" because it already exists.';
unset($existing);
continue;
}
// new account for this beneficiary
$beneficiary = new Account;
$beneficiary->name = $component->name;
$beneficiary->accountType()->associate($beneficiaryAT);
$beneficiary->user()->associate($user);
$beneficiary->active = 1;
$beneficiary->save();
$map['beneficiaries'][$id] = $beneficiary;
$messages[] = 'Recreated beneficiary "' . $beneficiary->name . '".';
unset($beneficiary);
}
break;
case 'category':
// if it exists, skip:
$existing = Component::where('name', $component->name)->where('user_id', $user->id)->where(
'component_type_id', $categoryType->id
)->first();
if (!is_null($existing)) {
$map['categories'][$id] = $existing;
$messages[] = 'Skipped creating category "' . $component->name . '" because it already exists.';
unset($existing);
continue;
}
// new component for this category:
$category = new Component;
$category->componentType()->associate($categoryType);
$category->name = $component->name;
$category->user()->associate($user);
$category->save();
$map['categories'][$id] = $category;
$messages[] = 'Recreated category "' . $category->name . '".';
unset($category);
break;
case 'budget':
// if it exists, skip:
$existing = Component::where('name', $component->name)->where('user_id', $user->id)->where(
'component_type_id', $budgetType->id
)->first();
if (!is_null($existing)) {
$map['budgets'][$id] = $existing;
$messages[] = 'Skipped creating budget "' . $component->name . '" because it already exists.';
unset($existing);
continue;
}
// new component for this budget:
$budget = new Component;
$budget->componentType()->associate($budgetType);
$budget->user()->associate($user);
$budget->name = $component->name;
$budget->save();
$map['budgets'][$id] = $budget;
$messages[] = 'Recreated budget "' . $budget->name . '".';
unset($budget);
break;
}
}
// grab all old transactions:
$transactions = DB::connection('old-firefly')->table('transactions')->where('user_id', $user->id)->orderBy(
'date'
)
->get();
foreach ($transactions as $transaction) {
$accountID = $transaction->account_id;
// grab the components for this transaction
$components = DB::connection('old-firefly')->table('component_transaction')
->leftJoin('components', 'components.id', '=', 'component_transaction.component_id')
->leftJoin('types', 'types.id', '=', 'components.type_id')
->where('transaction_id', $transaction->id)
->get(['components.id', 'types.type']);
$beneficiary = null;
$budget = null;
$category = null;
// loop components, get the right id's:
foreach ($components as $component) {
$id = $component->id;
switch ($component->type) {
case 'beneficiary':
$beneficiary = $map['beneficiaries'][$id];
break;
case 'budget':
$budget = $map['budgets'][$id];
break;
case 'category':
$category = $map['categories'][$id];
break;
}
}
// get a fall back for empty beneficiaries:
if (is_null($beneficiary)) {
$beneficiary = $cashAccount;
}
// create the transaction journal:
$journal = new TransactionJournal;
if ($transaction->amount < 0) {
$journal->transactionType()->associate($withdrawalTT);
} else {
$journal->transactionType()->associate($depositTT);
}
$journal->transactionCurrency()->associate($currency);
$journal->description = $transaction->description;
$journal->date = $transaction->date;
$journal->save();
// create two transactions:
if ($transaction->amount < 0) {
// credit the beneficiary
$credit = new Transaction;
$credit->account()->associate($beneficiary);
$credit->transactionJournal()->associate($journal);
$credit->description = null;
$credit->amount = floatval($transaction->amount) * -1;
$credit->save();
// add budget / category:
if (!is_null($budget)) {
$credit->components()->attach($budget);
}
if (!is_null($category)) {
$credit->components()->attach($category);
}
// debet ourselves:
$debet = new Transaction;
$debet->account()->associate($map['accounts'][$accountID]);
$debet->transactionJournal()->associate($journal);
$debet->description = null;
$debet->amount = floatval($transaction->amount);
$debet->save();
if (!is_null($budget)) {
$debet->components()->attach($budget);
}
if (!is_null($category)) {
$debet->components()->attach($category);
}
$messages[]
= 'Recreated expense "' . $transaction->description . '" (' . mf($transaction->amount, true) . ')';
} else {
$credit = new Transaction;
$credit->account()->associate($map['accounts'][$accountID]);
$credit->transactionJournal()->associate($journal);
$credit->description = null;
$credit->amount = floatval($transaction->amount);
$credit->save();
if (!is_null($budget)) {
$credit->components()->attach($budget);
}
if (!is_null($category)) {
$credit->components()->attach($category);
}
// from whoever!
$debet = new Transaction;
$debet->account()->associate($beneficiary);
$debet->transactionJournal()->associate($journal);
$debet->description = null;
$debet->amount = floatval($transaction->amount) * -1;
$debet->save();
if (!is_null($budget)) {
$debet->components()->attach($budget);
}
if (!is_null($category)) {
$debet->components()->attach($category);
}
$messages[]
= 'Recreated income "' . $transaction->description . '" (' . mf($transaction->amount, true) . ')';
}
}
unset($transaction);
// recreate the transfers:
$transfers = DB::connection('old-firefly')->table('transfers')->where('user_id', $user->id)->get();
foreach ($transfers as $transfer) {
// if it exists already, we don't need to recreate it:
$existingJournal = TransactionJournal::where('description', $transfer->description)->where(
'date', $transfer->date
)->where('transaction_type_id', $transferTT->id)->first();
if (!is_null($existingJournal)) {
// grab transaction from journal to make sure:
$firstTransaction = $existingJournal->transactions()->first();
if ($firstTransaction->amount == $transfer->amount
|| $firstTransaction->amount == $transfer->amount * -1
) {
// probably the same:
$messages[] = 'Skipped transfer "' . $transfer->description . '" because it already exists.';
unset($existingJournal, $firstTransaction);
continue;
}
}
$fromID = $transfer->accountfrom_id;
$toID = $transfer->accountto_id;
// create a journak:
$journal = new TransactionJournal;
$journal->transactionType()->associate($transferTT);
$journal->transactionCurrency()->associate($currency);
$journal->description = $transfer->description;
$journal->date = $transfer->date;
$journal->save();
// from account (debet) to another account (credit)
$debet = new Transaction;
$debet->account()->associate($map['accounts'][$fromID]);
$debet->transactionJournal()->associate($journal);
$debet->description = null;
$debet->amount = floatval($transfer->amount * -1);
$debet->save();
// to another account!
$credit = new Transaction;
$credit->account()->associate($map['accounts'][$toID]);
$credit->transactionJournal()->associate($journal);
$credit->description = null;
$credit->amount = floatval($transfer->amount);
$credit->save();
$messages[] = 'Recreated transfer "' . $transfer->description . '" (' . mf($transfer->amount) . ')';
}
$user->migrated = true;
$user->save();
return View::make('migrate.result')->with('messages', $messages);
}
*/
}

View File

@@ -26,6 +26,17 @@ class UserController extends BaseController
*/
public function login()
{
// $user = User::find(1);
// Auth::login($user);
// /** @var Firefly\Helper\Migration\MigrationHelperInterface $migration */
// $migration = App::make('Firefly\Helper\Migration\MigrationHelperInterface');
// $file = '/Library/WebServer/Documents/projects/firefly-iii/app/storage/firefly-export-2014-07-03.json';
// $migration->loadFile($file);
// if($migration->validFile()) {
// $migration->migrate();
// }
return View::make('user.login');
}

View File

@@ -18,18 +18,13 @@ class CreateComponentsTable extends Migration {
$table->timestamps();
$table->string('name',50);
$table->integer('user_id')->unsigned();
$table->integer('component_type_id')->unsigned();
$table->string('class',20);
// connect components to users
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
// connect components to component types
$table->foreign('component_type_id')
->references('id')->on('component_types')
->onDelete('cascade');
});
});
}
/**

View File

@@ -0,0 +1,46 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePiggybanksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'piggybanks', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('account_id')->unsigned();
$table->date('targetdate')->nullable();
$table->string('name', 500);
$table->decimal('amount', 10, 2);
$table->decimal('target', 10, 2)->nullable();
$table->integer('order')->unsigned();
// connect account to piggybank.
$table->foreign('account_id')
->references('id')->on('accounts')
->onDelete('cascade');
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('piggybanks');
}
}

View File

@@ -3,7 +3,7 @@
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateComponentTypesTable extends Migration {
class CreateRecurringTransactionsTable extends Migration {
/**
* Run the migrations.
@@ -12,11 +12,10 @@ class CreateComponentTypesTable extends Migration {
*/
public function up()
{
Schema::create('component_types', function(Blueprint $table)
Schema::create('recurringtransactions', function(Blueprint $table)
{
$table->increments('id');
$table->timestamps();
$table->string('type',50);
});
}
@@ -27,7 +26,7 @@ class CreateComponentTypesTable extends Migration {
*/
public function down()
{
Schema::drop('component_types');
Schema::drop('recurringtransactions');
}
}

View File

@@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateComponentTransactionJournalTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('component_transaction_journal', function(Blueprint $table)
{
$table->increments('id');
$table->integer('component_id')->unsigned();
$table->integer('transaction_journal_id')->unsigned();
// link components with component_id
$table->foreign('component_id')
->references('id')->on('components')
->onDelete('cascade');
// link transaction journals with transaction_journal_id
$table->foreign('transaction_journal_id')
->references('id')->on('transaction_journals')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('component_transaction_journal');
}
}

View File

@@ -1,16 +0,0 @@
<?php
class ComponentTypeSeeder extends Seeder
{
public function run()
{
DB::table('component_types')->delete();
ComponentType::create(['type' => 'category']);
ComponentType::create(['type' => 'budget']);
}
}

View File

@@ -15,7 +15,6 @@ class DatabaseSeeder extends Seeder
$this->call('AccountTypeSeeder');
$this->call('TransactionCurrencySeeder');
$this->call('TransactionTypeSeeder');
$this->call('ComponentTypeSeeder');
$this->call('DefaultUserSeeder');
}

View File

@@ -0,0 +1,78 @@
<?php
namespace Firefly\Database;
abstract class SingleTableInheritanceEntity extends \Elegant
{
/**
* The field that stores the subclass
*
* @var string
*/
protected $subclassField = null;
/**
* must be overridden and set to true in subclasses
* @var bool
*/
protected $isSubclass = false;
public function newFromBuilder($attributes = array())
{
$instance = $this->mapData((array)$attributes)->newInstance(array(), true);
$instance->setRawAttributes((array)$attributes, true);
return $instance;
}
// if no subclass is defined, function as normal
public function mapData(array $attributes)
{
if (!$this->subclassField) {
return $this->newInstance();
}
return new $attributes[$this->subclassField];
}
// instead of using $this->newInstance(), call
// newInstance() on the object from mapData
public function newQuery($excludeDeleted = true)
{
// If using Laravel 4.0.x then use the following commented version of this command
// $builder = new Builder($this->newBaseQueryBuilder());
// newEloquentBuilder() was added in 4.1
$builder = $this->newEloquentBuilder($this->newBaseQueryBuilder());
// Once we have the query builders, we will set the model instances so the
// builder can easily access any information it may need from the model
// while it is constructing and executing various queries against it.
$builder->setModel($this)->with($this->with);
if ($excludeDeleted && $this->softDelete) {
$builder->whereNull($this->getQualifiedDeletedAtColumn());
}
if ($this->subclassField && $this->isSubclass()) {
$builder->where($this->subclassField, '=', get_class($this));
}
return $builder;
}
public function isSubclass()
{
return $this->isSubclass;
}
// ensure that the subclass field is assigned on save
public function save(array $options = array())
{
if ($this->subclassField) {
$this->attributes[$this->subclassField] = get_class($this);
}
return parent::save($options);
}
}

View File

@@ -49,9 +49,18 @@ class MigrationHelper implements MigrationHelperInterface
\DB::beginTransaction();
try {
// create cash account:
$this->_createCashAccount();
$this->_importAccounts();
$this->_importComponents();
$this->_importPiggybanks();
//$this->_importPiggybanks();
// create transactions:
$this->_importTransactions();
// create transfers:
$this->_importTransfers();
} catch (\Firefly\Exception\FireflyException $e) {
@@ -66,6 +75,15 @@ class MigrationHelper implements MigrationHelperInterface
return true;
}
protected function _createCashAccount()
{
$cashAT = \AccountType::where('description', 'Cash account')->first();
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$cash = $accounts->store(['name' => 'Cash account', 'account_type' => $cashAT, 'active' => false]);
$this->map['cash'] = $cash;
}
protected function _importAccounts()
{
@@ -83,7 +101,7 @@ class MigrationHelper implements MigrationHelperInterface
floatval($entry->openingbalance)
);
}
$this->map['accounts'][$entry->id] = $account->id;
$this->map['accounts'][$entry->id] = $account;
\Log::info('Imported account "' . $entry->name . '" with balance ' . $entry->openingbalance);
}
}
@@ -91,38 +109,25 @@ class MigrationHelper implements MigrationHelperInterface
protected function _importComponents()
{
$beneficiaryAT = \AccountType::where('description', 'Beneficiary account')->first();
$budgetType = \ComponentType::where('type', 'budget')->first();
$categoryType = \ComponentType::where('type', 'category')->first();
foreach ($this->JSON->components as $entry) {
switch ($entry->type->type) {
case 'beneficiary':
$beneficiary = $this->_importBeneficiary($entry, $beneficiaryAT);
$this->map['accounts'][$entry->id] = $beneficiary->id;
$this->map['accounts'][$entry->id] = $beneficiary;
break;
case 'category':
$component = $this->_importComponent($entry, $categoryType);
$this->map['components'][$entry->id] = $component->id;
$component = $this->_importCategory($entry);
$this->map['categories'][$entry->id] = $component;
break;
case 'budget':
$component = $this->_importComponent($entry, $budgetType);
$this->map['components'][$entry->id] = $component->id;
$component = $this->_importBudget($entry);
$this->map['budgets'][$entry->id] = $component;
break;
}
}
}
protected function _importPiggybanks() {
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
// get type for piggy:
$piggyAT = \AccountType::where('description', 'Piggy bank')->first();
foreach($this->JSON->piggybanks as $piggyBank) {
}
}
protected function _importBeneficiary($component, \AccountType $beneficiaryAT)
{
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
@@ -135,10 +140,98 @@ class MigrationHelper implements MigrationHelperInterface
);
}
protected function _importComponent($component, \ComponentType $type)
protected function _importCategory($component)
{
/** @var \Firefly\Storage\Component\ComponentRepositoryInterface $components */
$components = \App::make('Firefly\Storage\Component\ComponentRepositoryInterface');
return $components->store(['name' => $component->name, 'component_type' => $type]);
return $components->store(['name' => $component->name, 'class' => 'Category']);
}
protected function _importBudget($component)
{
/** @var \Firefly\Storage\Component\ComponentRepositoryInterface $components */
$components = \App::make('Firefly\Storage\Component\ComponentRepositoryInterface');
return $components->store(['name' => $component->name, 'class' => 'Budget']);
}
protected function _importTransactions()
{
/** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */
$journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface');
// loop component_transaction to find beneficiaries, categories and budgets:
$beneficiaries = [];
$categories = [];
$budgets = [];
foreach ($this->JSON->component_transaction as $entry) {
// beneficiaries
if (isset($this->map['accounts'][$entry->component_id])) {
$beneficiaries[$entry->transaction_id] = $this->map['accounts'][$entry->component_id];
}
// categories
if (isset($this->map['categories'][$entry->component_id])) {
$categories[$entry->transaction_id] = $this->map['categories'][$entry->component_id];
}
// budgets:
if (isset($this->map['budgets'][$entry->component_id])) {
$budgets[$entry->transaction_id] = $this->map['budgets'][$entry->component_id];
}
}
foreach ($this->JSON->transactions as $entry) {
$id = $entry->id;
// to properly save the amount, do it times -1:
$amount = $entry->amount * -1;
/** @var \Account $fromAccount */
$fromAccount = isset($this->map['accounts'][$entry->account_id])
? $this->map['accounts'][$entry->account_id] : false;
/** @var \Account $toAccount */
$toAccount = isset($beneficiaries[$entry->id]) ? $beneficiaries[$entry->id] : $this->map['cash'];
$date = new \Carbon\Carbon($entry->date);
$journal = $journals->createSimpleJournal($fromAccount, $toAccount, $entry->description, $amount, $date);
// save budgets and categories, on the journal
if(isset($budgets[$entry->id])) {
$budget = $budgets[$entry->id];
$journal->budgets()->save($budget);
}
if(isset($categories[$entry->id])) {
$category = $categories[$entry->id];
$journal->categories()->save($category);
}
}
}
protected function _importTransfers()
{
/** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */
$journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface');
foreach ($this->JSON->transfers as $entry) {
$id = $entry->id;
// to properly save the amount, do it times 1 (?):
$amount = $entry->amount * -1;
/** @var \Account $fromAccount */
$fromAccount = isset($this->map['accounts'][$entry->accountfrom_id])
? $this->map['accounts'][$entry->accountto_id] : false;
/** @var \Account $toAccount */
$toAccount = isset($this->map['accounts'][$entry->accountto_id])
? $this->map['accounts'][$entry->accountfrom_id] : false;
$date = new \Carbon\Carbon($entry->date);
$journals->createSimpleJournal($fromAccount, $toAccount, $entry->description, $amount, $date);
}
}
}

View File

@@ -9,6 +9,8 @@ interface AccountRepositoryInterface
public function count();
public function get();
public function store($data);
public function storeWithInitialBalance($data,\Carbon\Carbon $date, $amount = 0);

View File

@@ -13,6 +13,10 @@ class EloquentAccountRepository implements AccountRepositoryInterface
{
}
public function get() {
return \Auth::user()->accounts()->get();
}
public function count()
{
return \Auth::user()->accounts()->count();

View File

@@ -20,18 +20,26 @@ class EloquentComponentRepository implements ComponentRepositoryInterface
public function store($data)
{
if (!isset($data['component_type'])) {
throw new \Firefly\Exception\FireflyException('No component type present.');
if (!isset($data['class'])) {
throw new \Firefly\Exception\FireflyException('No class type present.');
}
switch ($data['class']) {
case 'Budget':
$component = new \Budget;
break;
case 'Category':
$component = new \Category;
break;
}
$component = new \Component;
$component->componentType()->associate($data['component_type']);
$component->name = $data['name'];
$component->user()->associate(\Auth::user());
try {
$component->save();
} catch (\Illuminate\Database\QueryException $e) {
\Log::error('DB ERROR: ' . $e->getMessage());
throw new \Firefly\Exception\FireflyException('Could not save component ' . $data['name']);
throw new \Firefly\Exception\FireflyException('Could not save component ' . $data['name'] . ' of type'
. $data['class']);
}
return $component;

View File

@@ -15,7 +15,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
public function createSimpleJournal(\Account $from, \Account $to, $description, $amount, \Carbon\Carbon $date)
{
\Log::debug('Creating tranaction "'.$description.'".');
/*
* We're building this thinking the money goes from A to B.
* If the amount is negative however, the money still goes
@@ -67,6 +67,10 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
$journalType = \TransactionType::where('type', 'Deposit')->first();
break;
}
// some debug information:
\Log::debug($journalType->type.': AccountFrom "'.$from->name.'" will gain/lose '.$amountFrom.' and AccountTo "'.$to->name.'" will gain/lose '.$amountTo);
if (is_null($journalType)) {
\Log::error('Could not figure out transacion type!');
throw new \Firefly\Exception\FireflyException('Could not figure out transaction type.');
@@ -122,10 +126,6 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
$journal->completed = true;
$journal->save();
return;
echo 'saved!';
return $journal;
}
}

14
app/models/Budget.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 05/07/14
* Time: 18:24
*/
class Budget extends Component {
protected $isSubclass = true;
}

6
app/models/Category.php Normal file
View File

@@ -0,0 +1,6 @@
<?php
class Category extends Component
{
protected $isSubclass = true;
}

View File

@@ -1,8 +1,12 @@
<?php
class Component extends Elegant
class Component extends Firefly\Database\SingleTableInheritanceEntity
{
protected $table = 'components';
protected $subclassField = 'class';
public static $rules
= [
'user_id' => 'exists:users,id|required',
@@ -11,15 +15,14 @@ class Component extends Elegant
];
public function componentType()
{
return $this->belongsTo('ComponentType');
}
public function transactions()
{
return $this->belongsToMany('Transaction');
}
public function transactionjournals()
{
return $this->belongsToMany('TransactionJournal');
}
public function user()
{

View File

@@ -1,11 +0,0 @@
<?php
class ComponentType extends Eloquent
{
public function components()
{
return $this->hasMany('Component');
}
}

View File

@@ -26,4 +26,13 @@ class Transaction extends Elegant
{
return $this->belongsToMany('Component');
}
public function budgets()
{
return $this->belongsToMany('Budget');
}
public function categories()
{
return $this->belongsToMany('Category');
}
}

View File

@@ -28,6 +28,21 @@ class TransactionJournal extends Elegant
return $this->hasMany('Transaction');
}
public function components()
{
return $this->belongsToMany('Component');
}
public function budgets()
{
return $this->belongsToMany('Budget','component_transaction_journal','transaction_journal_id','component_id');
}
public function categories()
{
return $this->belongsToMany('Category','component_transaction_journal','transaction_journal_id','component_id');
}
public function getDates()
{
return array('created_at', 'updated_at', 'date');

View File

@@ -15,10 +15,13 @@ Route::group(['before' => 'auth'], function () {
// migration controller
Route::get('/migrate', ['uses' => 'MigrationController@index', 'as' => 'migrate']);
// account controller:
Route::get('/accounts/create', ['uses' => 'AccountController@create', 'as' => 'accounts.create']);
}
);
// protected + csrf routes
// protected + csrf routes (POST)
Route::group(['before' => 'csrf|auth'], function () {
// profile controller
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword']);
@@ -26,6 +29,9 @@ Route::group(['before' => 'csrf|auth'], function () {
// migration controller
Route::post('/migrate', ['uses' => 'MigrationController@postIndex']);
// account controller:
Route::get('/accounts/store', ['uses' => 'AccountController@store', 'as' => 'accounts.store']);
}
);

View File

@@ -0,0 +1,19 @@
<?php
class AccountControllerTest extends TestCase {
public function setUp()
{
parent::setUp();
}
public function testCreate()
{
// mock:
View::shouldReceive('make')->with('accounts.create');
// call
$this->call('GET', '/accounts/create');
// test
$this->assertResponseOk();
}
}

View File

@@ -0,0 +1,21 @@
<?php
class MigrationControllerTest extends TestCase
{
public function setUp()
{
parent::setUp();
}
public function testIndex()
{
// mock:
View::shouldReceive('make')->with('migrate.index');
// call
$this->call('GET', '/migrate');
// test
$this->assertResponseOk();
}
}

View File

@@ -211,34 +211,6 @@ class UserControllerTest extends TestCase
}
public function testVerification()
{
$repository = $this->mock('Firefly\Storage\User\UserRepositoryInterface');
$email = $this->mock('Firefly\Helper\Email\EmailHelper');
$repository->shouldReceive('findByVerification')->once()->andReturn(new User);
$email->shouldReceive('sendPasswordMail')->once()->andReturn(true);
// test
$crawler = $this->client->request('GET', '/verify/blabla');
$this->assertTrue($this->client->getResponse()->isOk());
$this->assertCount(1, $crawler->filter('h1:contains("Password sent")'));
}
public function testVerificationFails()
{
$repository = $this->mock('Firefly\Storage\User\UserRepositoryInterface');
$repository->shouldReceive('findByVerification')->once()->andReturn(null);
// test
$crawler = $this->client->request('GET', '/verify/blabla');
$this->assertTrue($this->client->getResponse()->isOk());
$this->assertCount(1, $crawler->filter('h1:contains("Error")'));
$this->assertViewHas('message');
}
public function testReset()
{