diff --git a/app/controllers/AccountController.php b/app/controllers/AccountController.php index 4aecedeef594..57b2966d125e 100755 --- a/app/controllers/AccountController.php +++ b/app/controllers/AccountController.php @@ -132,13 +132,14 @@ class AccountController extends \BaseController { ); $recommendedGatewayArray[$recommendedGateway->name] = $arrayItem; } - $otherItem = array( - 'value' => 1000000, - 'other' => 'true', - 'data-imageUrl' => '', - 'data-siteUrl' => '' - ); - $recommendedGatewayArray['Other Options'] = $otherItem; + + $otherItem = array( + 'value' => 1000000, + 'other' => 'true', + 'data-imageUrl' => '', + 'data-siteUrl' => '' + ); + $recommendedGatewayArray['Other Options'] = $otherItem; $data = [ 'account' => $account, @@ -180,6 +181,14 @@ class AccountController extends \BaseController { { return View::make('accounts.import_export'); } + else if ($section == ACCOUNT_CUSTOM_FIELDS) + { + $data = [ + 'account' => Auth::user()->account + ]; + + return View::make('accounts.custom_fields', $data); + } } public function doSection($section = ACCOUNT_DETAILS) @@ -208,6 +217,26 @@ class AccountController extends \BaseController { { return AccountController::export(); } + else if ($section == ACCOUNT_CUSTOM_FIELDS) + { + return AccountController::saveCustomFields(); + } + } + + private function saveCustomFields() + { + $account = Auth::user()->account; + + $account->custom_label1 = Input::get('custom_label1'); + $account->custom_value1 = Input::get('custom_value1'); + $account->custom_label2 = Input::get('custom_label2'); + $account->custom_value2 = Input::get('custom_value2'); + $account->custom_client_label1 = Input::get('custom_client_label1'); + $account->custom_client_label2 = Input::get('custom_client_label2'); + $account->save(); + + Session::flash('message', trans('texts.updated_settings')); + return Redirect::to('company/custom_fields'); } private function export() @@ -466,7 +495,7 @@ class AccountController extends \BaseController { private function saveNotifications() { - $account = Account::findOrFail(Auth::user()->account_id); + $account = Auth::user()->account; $account->invoice_terms = Input::get('invoice_terms'); $account->email_footer = Input::get('email_footer'); $account->save(); diff --git a/app/controllers/ClientController.php b/app/controllers/ClientController.php index bc6fc75785a8..cc3475207520 100755 --- a/app/controllers/ClientController.php +++ b/app/controllers/ClientController.php @@ -60,31 +60,7 @@ class ClientController extends \BaseController { ->make(); } - /** - * Show the form for creating a new resource. - * - * @return Response - */ - public function create() - { - if (Client::scope()->count() > Auth::user()->getMaxNumClients()) - { - return View::make('error', ['error' => "Sorry, you've exceeded the limit of " . Auth::user()->getMaxNumClients() . " clients"]); - } - $data = array( - 'client' => null, - 'method' => 'POST', - 'url' => 'clients', - 'title' => '- New Client', - 'sizes' => Size::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), - 'industries' => Industry::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), - 'paymentTerms' => PaymentTerm::remember(DEFAULT_QUERY_CACHE)->orderBy('num_days')->get(['name', 'num_days']), - 'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), - 'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get()); - - return View::make('clients.edit', $data); - } /** * Store a newly created resource in storage. @@ -118,6 +94,29 @@ class ClientController extends \BaseController { return View::make('clients.show', $data); } + /** + * Show the form for creating a new resource. + * + * @return Response + */ + public function create() + { + if (Client::scope()->count() > Auth::user()->getMaxNumClients()) + { + return View::make('error', ['error' => "Sorry, you've exceeded the limit of " . Auth::user()->getMaxNumClients() . " clients"]); + } + + $data = [ + 'client' => null, + 'method' => 'POST', + 'url' => 'clients', + 'title' => '- New Client' + ]; + + $data = array_merge($data, self::getViewModel()); + return View::make('clients.edit', $data); + } + /** * Show the form for editing the specified resource. * @@ -127,18 +126,29 @@ class ClientController extends \BaseController { public function edit($publicId) { $client = Client::scope($publicId)->with('contacts')->firstOrFail(); - $data = array( + $data = [ 'client' => $client, 'method' => 'PUT', 'url' => 'clients/' . $publicId, - 'title' => '- ' . $client->name, + 'title' => '- ' . $client->name + ]; + + $data = array_merge($data, self::getViewModel()); + return View::make('clients.edit', $data); + } + + private static function getViewModel() + { + return [ 'sizes' => Size::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), 'paymentTerms' => PaymentTerm::remember(DEFAULT_QUERY_CACHE)->orderBy('num_days')->get(['name', 'num_days']), 'industries' => Industry::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), 'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), - 'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get()); - return View::make('clients.edit', $data); - } + 'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'customLabel1' => Auth::user()->account->custom_client_label1, + 'customLabel2' => Auth::user()->account->custom_client_label2, + ]; + } /** * Update the specified resource in storage. @@ -178,6 +188,8 @@ class ClientController extends \BaseController { $client->name = trim(Input::get('name')); $client->work_phone = trim(Input::get('work_phone')); + $client->custom_value1 = trim(Input::get('custom_value1')); + $client->custom_value2 = trim(Input::get('custom_value2')); $client->address1 = trim(Input::get('address1')); $client->address2 = trim(Input::get('address2')); $client->city = trim(Input::get('city')); diff --git a/app/controllers/InvoiceController.php b/app/controllers/InvoiceController.php index eb4fba8bfbc9..e9c26bd1bc4c 100755 --- a/app/controllers/InvoiceController.php +++ b/app/controllers/InvoiceController.php @@ -182,7 +182,7 @@ class InvoiceController extends \BaseController { 'url' => 'invoices/' . $publicId, 'title' => '- ' . $invoice->invoice_number, 'client' => $invoice->client); - $data = array_merge($data, InvoiceController::getViewModel()); + $data = array_merge($data, self::getViewModel()); return View::make('invoices.edit', $data); } @@ -206,11 +206,11 @@ class InvoiceController extends \BaseController { 'url' => 'invoices', 'title' => '- New Invoice', 'client' => $client); - $data = array_merge($data, InvoiceController::getViewModel()); + $data = array_merge($data, self::getViewModel()); return View::make('invoices.edit', $data); } - public static function getViewModel() + private static function getViewModel() { return [ 'account' => Auth::user()->account, diff --git a/app/database/migrations/2014_04_17_145108_add_custom_fields.php b/app/database/migrations/2014_04_17_145108_add_custom_fields.php new file mode 100644 index 000000000000..ac88c4012b70 --- /dev/null +++ b/app/database/migrations/2014_04_17_145108_add_custom_fields.php @@ -0,0 +1,60 @@ +string('custom_label1'); + $table->string('custom_value1'); + + $table->string('custom_label2'); + $table->string('custom_value2'); + + $table->string('custom_client_label1'); + $table->string('custom_client_label2'); + }); + + Schema::table('clients', function($table) + { + $table->string('custom_value1'); + $table->string('custom_value2'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('custom_label1'); + $table->dropColumn('custom_value1'); + + $table->dropColumn('custom_label2'); + $table->dropColumn('custom_value2'); + + $table->dropColumn('custom_client_label1'); + $table->dropColumn('custom_client_label2'); + }); + + Schema::table('clients', function($table) + { + $table->dropColumn('custom_value1'); + $table->dropColumn('custom_value2'); + }); + } + +} diff --git a/app/lang/en/texts.php b/app/lang/en/texts.php index dc707bbf39c4..ad88ad2696e2 100644 --- a/app/lang/en/texts.php +++ b/app/lang/en/texts.php @@ -311,5 +311,11 @@ return array( 'pro_plan_success' => 'Thanks for joining! Once the invoice is paid your Pro Plan membership will begin.', 'unsaved_changes' => 'You have unsaved changes', + 'custom_fields' => 'Custom fields', + 'company_fields' => 'Company Fields', + 'client_fields' => 'Client Fields', + 'field_label' => 'Field Label', + 'field_value' => 'Field Value', + 'edit' => 'Edit', ); diff --git a/app/libraries/utils.php b/app/libraries/utils.php index 0ca3bcbd3b8a..0b594834619c 100755 --- a/app/libraries/utils.php +++ b/app/libraries/utils.php @@ -12,6 +12,11 @@ class Utils return App::environment() == ENV_PRODUCTION; } + public static function isNinja() + { + return self::isNinjaProd() || self::isNinjaDev(); + } + public static function isNinjaProd() { return $_SERVER['SERVER_NAME'] == 'www.invoiceninja.com'; @@ -22,6 +27,20 @@ class Utils return isset($_ENV['NINJA_DEV']) && $_ENV['NINJA_DEV']; } + public static function getProLabel($feature) + { + if (Auth::check() + && !Auth::user()->isPro() + && $feature == 'custom_fields') + { + return ' PRO'; + } + else + { + return ''; + } + } + public static function basePath() { return substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/') + 1); diff --git a/app/models/Account.php b/app/models/Account.php index 25adac65d129..b4cccdc433dc 100755 --- a/app/models/Account.php +++ b/app/models/Account.php @@ -215,6 +215,11 @@ class Account extends Eloquent public function isPro() { + if (Utils::isNinja()) + { + return true; + } + if ($this->account_key == NINJA_ACCOUNT_KEY) { return true; diff --git a/app/models/Client.php b/app/models/Client.php index 6e805023bf98..92b283e36fb0 100755 --- a/app/models/Client.php +++ b/app/models/Client.php @@ -155,6 +155,24 @@ class Client extends EntityModel return $str; } + public function getCustomFields() + { + $str = ''; + $account = $this->account; + + if ($account->custom_client_label1 && $this->custom_value1) + { + $str .= "{$account->custom_client_label1}: {$this->custom_value1}
"; + } + + if ($account->custom_client_label2 && $this->custom_value2) + { + $str .= "{$account->custom_client_label2}: {$this->custom_value2}
"; + } + + return $str; + } + public function getWebsite() { if (!$this->website) diff --git a/app/ninja/repositories/ClientRepository.php b/app/ninja/repositories/ClientRepository.php index 6084a7847565..6b7631ca4410 100755 --- a/app/ninja/repositories/ClientRepository.php +++ b/app/ninja/repositories/ClientRepository.php @@ -46,8 +46,11 @@ class ClientRepository $contact = $client->contacts()->where('is_primary', '=', true)->firstOrFail(); } + $client->name = trim($data['name']); - $client->work_phone = trim($data['work_phone']); + $client->work_phone = trim($data['work_phone']); + $client->custom_value1 = trim($data['custom_value1']); + $client->custom_value2 = trim($data['custom_value2']); $client->address1 = trim($data['address1']); $client->address2 = trim($data['address2']); $client->city = trim($data['city']); diff --git a/app/routes.php b/app/routes.php index 9d4e13bc886c..e48b942d8a14 100755 --- a/app/routes.php +++ b/app/routes.php @@ -99,80 +99,9 @@ Route::group(array('before' => 'auth'), function() - -HTML::macro('nav_link', function($url, $text, $url2 = '', $extra = '') { - $class = ( Request::is($url) || Request::is($url.'/*') || Request::is($url2) ) ? ' class="active"' : ''; - return ''.trans("texts.$text").''; -}); - -HTML::macro('tab_link', function($url, $text, $active = false) { - $class = $active ? ' class="active"' : ''; - return ''.$text.''; -}); - -HTML::macro('menu_link', function($type) { - $types = $type.'s'; - $Type = ucfirst($type); - $Types = ucfirst($types); - $class = ( Request::is($types) || Request::is('*'.$type.'*')) ? ' active' : ''; - - return ''; -}); - -HTML::macro('image_data', function($imagePath) { - return 'data:image/jpeg;base64,' . base64_encode(file_get_contents($imagePath)); -}); - - -HTML::macro('breadcrumbs', function() { - $str = ''; -}); - - define('CONTACT_EMAIL', 'contact@invoiceninja.com'); define('CONTACT_NAME', 'Invoice Ninja'); - +define('NINJA_URL', 'https://www.invoiceninja.com'); define('ENV_DEVELOPMENT', 'local'); define('ENV_STAGING', 'staging'); @@ -194,6 +123,7 @@ define('ACCOUNT_IMPORT_EXPORT', 'import_export'); define('ACCOUNT_PAYMENTS', 'payments'); define('ACCOUNT_MAP', 'import_map'); define('ACCOUNT_EXPORT', 'export'); +define('ACCOUNT_CUSTOM_FIELDS', 'custom_fields'); define('DEFAULT_INVOICE_NUMBER', '0001'); define('RECENTLY_VIEWED_LIMIT', 8); @@ -259,6 +189,84 @@ define('GATEWAY_GOOGLE', 33); define('GATEWAY_QUICKBOOKS', 35); */ + + +HTML::macro('nav_link', function($url, $text, $url2 = '', $extra = '') { + $class = ( Request::is($url) || Request::is($url.'/*') || Request::is($url2) ) ? ' class="active"' : ''; + $title = ucwords(trans("texts.$text")) . Utils::getProLabel($text); + return ''.$title.''; +}); + +HTML::macro('tab_link', function($url, $text, $active = false) { + $class = $active ? ' class="active"' : ''; + return ''.$text.''; +}); + +HTML::macro('menu_link', function($type) { + $types = $type.'s'; + $Type = ucfirst($type); + $Types = ucfirst($types); + $class = ( Request::is($types) || Request::is('*'.$type.'*')) ? ' active' : ''; + + return ''; +}); + +HTML::macro('image_data', function($imagePath) { + return 'data:image/jpeg;base64,' . base64_encode(file_get_contents($imagePath)); +}); + + +HTML::macro('breadcrumbs', function() { + $str = ''; +}); + +function uctrans($text) +{ + return ucwords(trans($text)); +} + + if (Auth::check() && !Session::has(SESSION_TIMEZONE)) { Event::fire('user.refresh'); @@ -276,8 +284,8 @@ Validator::extend('has_credit', function($attribute, $value, $parameters) $client = Client::scope($publicClientId)->firstOrFail(); $credit = $client->getTotalCredit(); - - return $credit >= $amount; + + return $credit >= $amount; }); diff --git a/app/views/accounts/custom_fields.blade.php b/app/views/accounts/custom_fields.blade.php new file mode 100644 index 000000000000..5e83614bb014 --- /dev/null +++ b/app/views/accounts/custom_fields.blade.php @@ -0,0 +1,33 @@ +@extends('accounts.nav') + +@section('content') + @parent + + {{ Former::open()->addClass('col-md-8 col-md-offset-2 warn-on-exit') }} + {{ Former::populate($account) }} + + {{ Former::legend('company_fields') }} + {{ Former::text('custom_label1')->label(trans('texts.field_label')) }} + {{ Former::text('custom_value1')->label(trans('texts.field_value')) }} +

 

+ {{ Former::text('custom_label2')->label(trans('texts.field_label')) }} + {{ Former::text('custom_value2')->label(trans('texts.field_value')) }} + + {{ Former::legend('client_fields') }} + {{ Former::text('custom_client_label1')->label(trans('texts.field_label')) }} + {{ Former::text('custom_client_label2')->label(trans('texts.field_label')) }} + + @if (Auth::user()->isPro()) + {{ Former::actions( Button::lg_success_submit(trans('texts.save'))->append_with_icon('floppy-disk') ) }} + @else + + @endif + + {{ Former::close() }} + + +@stop \ No newline at end of file diff --git a/app/views/accounts/details.blade.php b/app/views/accounts/details.blade.php index 612e7aaeae3e..c1e96f3b7fb5 100755 --- a/app/views/accounts/details.blade.php +++ b/app/views/accounts/details.blade.php @@ -14,7 +14,7 @@ {{ Former::open_for_files()->addClass('col-md-10 col-md-offset-1 warn-on-exit')->rules(array( 'name' => 'required', 'email' => 'email|required' - )); }} + )) }} {{ Former::populate($account) }} {{ Former::populateField('first_name', $account->users()->first()->first_name) }} diff --git a/app/views/accounts/nav.blade.php b/app/views/accounts/nav.blade.php index 25acc844ad29..65d62812ef8a 100755 --- a/app/views/accounts/nav.blade.php +++ b/app/views/accounts/nav.blade.php @@ -5,8 +5,9 @@

 

diff --git a/app/views/clients/edit.blade.php b/app/views/clients/edit.blade.php index 584a6d60b4f2..657bbf30216a 100755 --- a/app/views/clients/edit.blade.php +++ b/app/views/clients/edit.blade.php @@ -25,7 +25,15 @@ {{ Former::text('name')->data_bind("attr { placeholder: placeholderName }") }} {{ Former::text('website') }} {{ Former::text('work_phone') }} - + + @if (Auth::user()->isPro()) + @if ($customLabel1) + {{ Former::text('custom_value1')->label($customLabel1) }} + @endif + @if ($customLabel2) + {{ Former::text('custom_value2')->label($customLabel2) }} + @endif + @endif {{ Former::legend('address') }} {{ Former::text('address1') }} diff --git a/app/views/clients/show.blade.php b/app/views/clients/show.blade.php index 328541670489..4c420c5077f1 100755 --- a/app/views/clients/show.blade.php +++ b/app/views/clients/show.blade.php @@ -48,6 +48,7 @@

{{ trans('texts.details') }}

{{ $client->getAddress() }}

+

{{ $client->getCustomFields() }}

{{ $client->getPhone() }}

{{ $client->getNotes() }}

{{ $client->getIndustry() }}

diff --git a/app/views/header.blade.php b/app/views/header.blade.php index 3defd75ef960..44e9d8b69f93 100755 --- a/app/views/header.blade.php +++ b/app/views/header.blade.php @@ -1,7 +1,6 @@ @extends('master') - @section('head') @@ -90,7 +89,7 @@ - +
@@ -139,10 +138,11 @@