diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index f526fef67825..d03b13fa9e72 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -359,8 +359,6 @@ class AccountController extends BaseController $client->postal_code = trans('texts.postal_code'); $client->work_phone = trans('texts.work_phone'); $client->work_email = trans('texts.work_id'); - $client->id_number = trans('texts.id_number'); - $client->vat_number = trans('texts.var_number'); $invoice->invoice_number = '0000'; $invoice->invoice_date = Utils::fromSqlDate(date('Y-m-d')); diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index 6080a70331f2..84145afe9c1c 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -104,8 +104,10 @@ class ClientController extends BaseController } array_push($actionLinks, + \DropdownButton::DIVIDER, ['label' => trans('texts.enter_payment'), 'url' => '/payments/create/'.$client->public_id], - ['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id] + ['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id], + ['label' => trans('texts.enter_expense'), 'url' => '/expenses/create/0/'.$client->public_id] ); $data = array( diff --git a/app/Http/Controllers/ExpenseController.php b/app/Http/Controllers/ExpenseController.php index 4746e1ac95c3..b7f5bdaaccdd 100644 --- a/app/Http/Controllers/ExpenseController.php +++ b/app/Http/Controllers/ExpenseController.php @@ -67,7 +67,7 @@ class ExpenseController extends BaseController return $this->expenseService->getDatatableVendor($vendorPublicId); } - public function create($vendorPublicId = 0) + public function create($vendorPublicId = null, $clientPublicId = null) { if($vendorPublicId != 0) { $vendor = Vendor::scope($vendorPublicId)->with('vendorcontacts')->firstOrFail(); @@ -83,7 +83,7 @@ class ExpenseController extends BaseController 'vendors' => Vendor::scope()->with('vendorcontacts')->orderBy('name')->get(), 'vendor' => $vendor, 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), - 'clientPublicId' => null, + 'clientPublicId' => $clientPublicId, ); $data = array_merge($data, self::getViewModel()); diff --git a/app/Http/routes.php b/app/Http/routes.php index 216365ffc7e8..e0ded5dd46e3 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -200,7 +200,7 @@ Route::group(['middleware' => 'auth'], function() { // Expense Route::resource('expenses', 'ExpenseController'); - Route::get('expenses/create/{vendor_id?}', 'ExpenseController@create'); + Route::get('expenses/create/{vendor_id?}/{client_id?}', 'ExpenseController@create'); Route::get('api/expense', array('as'=>'api.expenses', 'uses'=>'ExpenseController@getDatatable')); Route::get('api/expenseVendor/{id}', array('as'=>'api.expense', 'uses'=>'ExpenseController@getDatatableVendor')); Route::post('expenses/bulk', 'ExpenseController@bulk'); diff --git a/app/Models/Account.php b/app/Models/Account.php index 51ec3aa88277..08c10017c0a0 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -251,6 +251,11 @@ class Account extends Eloquent return Utils::formatMoney($amount, $currencyId, $countryId, $hideSymbol); } + public function getCurrencyId() + { + return $this->currency_id ?: DEFAULT_CURRENCY; + } + public function formatDate($date) { $date = $this->getDateTime($date); diff --git a/app/Models/Expense.php b/app/Models/Expense.php index e79c348ceaeb..a4340d9b7674 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -37,6 +37,11 @@ class Expense extends EntityModel return $this->belongsTo('App\Models\Vendor')->withTrashed(); } + public function client() + { + return $this->belongsTo('App\Models\Client')->withTrashed(); + } + public function getName() { if($this->expense_number) diff --git a/app/Ninja/Presenters/AccountPresenter.php b/app/Ninja/Presenters/AccountPresenter.php index d955c76e5bd6..dc9cacbb8aa7 100644 --- a/app/Ninja/Presenters/AccountPresenter.php +++ b/app/Ninja/Presenters/AccountPresenter.php @@ -14,4 +14,11 @@ class AccountPresenter extends Presenter { { return Utils::addHttp($this->entity->website); } + + public function currencyCode() + { + $currencyId = $this->entity->getCurrencyId(); + $currency = Utils::getFromCache($currencyId, 'currencies'); + return $currency->code; + } } \ No newline at end of file diff --git a/app/Ninja/Repositories/ExpenseRepository.php b/app/Ninja/Repositories/ExpenseRepository.php index 213e24dae310..b8083cb0f157 100644 --- a/app/Ninja/Repositories/ExpenseRepository.php +++ b/app/Ninja/Repositories/ExpenseRepository.php @@ -1,4 +1,4 @@ -join('accounts', 'accounts.id', '=', 'expenses.account_id') ->where('expenses.account_id', '=', $accountid) - ->where('expenses.vendor_id','=',$vendorPublicId) + ->where('expenses.vendor_id', '=', $vendorPublicId) ->select('expenses.id', 'expenses.expense_date', 'expenses.amount', 'expenses.public_notes', 'expenses.public_id', - 'expenses.deleted_at','expenses.should_be_invoiced','expenses.created_at'); - return $query; + 'expenses.deleted_at', 'expenses.should_be_invoiced', 'expenses.created_at'); + + return $query; } public function find($filter = null) @@ -45,11 +46,11 @@ class ExpenseRepository extends BaseRepository $accountid = \Auth::user()->account_id; $query = DB::table('expenses') ->join('accounts', 'accounts.id', '=', 'expenses.account_id') - ->leftjoin('vendors','vendors.public_id','=', 'expenses.vendor_id') + ->leftjoin('vendors', 'vendors.public_id', '=', 'expenses.vendor_id') ->where('expenses.account_id', '=', $accountid) ->select('expenses.account_id', 'expenses.amount', - 'expenses.foreign_amount', + 'expenses.converted_amount', 'expenses.currency_id', 'expenses.deleted_at', 'expenses.exchange_rate', @@ -94,40 +95,46 @@ class ExpenseRepository extends BaseRepository $expense->fill($input); // We can have an expense without a vendor - if(isset($input['vendor'])) { - $expense->vendor_id = $input['vendor']; + if (isset($input['vendor_id'])) { + $expense->vendor_id = $input['vendor_id']; } $expense->expense_date = Utils::toSqlDate($input['expense_date']); $expense->amount = Utils::parseFloat($input['amount']); - if(isset($input['foreign_amount'])) - $expense->foreign_amount = Utils::parseFloat($input['foreign_amount']); + if (isset($input['converted_amount'])) { + $expense->converted_amount = Utils::parseFloat($input['converted_amount']); + } $expense->private_notes = trim($input['private_notes']); $expense->public_notes = trim($input['public_notes']); - if(isset($input['exchange_rate'])) + if (isset($input['exchange_rate'])) { $expense->exchange_rate = Utils::parseFloat($input['exchange_rate']); - else + } else { $expense->exchange_rate = 100; + } - if($expense->exchange_rate == 0) + if ($expense->exchange_rate == 0) { $expense->exchange_rate = 100; + } // set the currency - if(isset($input['currency_id'])) + if (isset($input['currency_id'])) { $expense->currency_id = $input['currency_id']; + } - if($expense->currency_id == 0) + if ($expense->currency_id == 0) { $expense->currency_id = Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY); + } // Calculate the amount cur - $expense->foreign_amount = ($expense->amount / 100) * $expense->exchange_rate; + $expense->converted_amount = ($expense->amount / 100) * $expense->exchange_rate; - $expense->should_be_invoiced = isset($input['should_be_invoiced']) ? true : false; - if(isset($input['client'])) { - $expense->client_id = $input['client']; + $expense->should_be_invoiced = isset($input['should_be_invoiced']) || $expense->client_id ? true : false; + + if (isset($input['client_id'])) { + $expense->client_id = $input['client_id']; } $expense->save(); @@ -156,5 +163,4 @@ class ExpenseRepository extends BaseRepository return count($tasks); } - } diff --git a/app/Services/ClientService.php b/app/Services/ClientService.php index 7490dc8739b4..d7cb08a77d86 100644 --- a/app/Services/ClientService.php +++ b/app/Services/ClientService.php @@ -125,6 +125,12 @@ class ClientService extends BaseService function ($model) { return URL::to("credits/create/{$model->public_id}"); } + ], + [ + trans('texts.enter_expense'), + function ($model) { + return URL::to("expenses/create/0/{$model->public_id}"); + } ] ]; } diff --git a/database/migrations/2016_01_04_175228_create_vendors_table.php b/database/migrations/2016_01_04_175228_create_vendors_table.php index 68cc58c3dc80..7c63933c00dd 100644 --- a/database/migrations/2016_01_04_175228_create_vendors_table.php +++ b/database/migrations/2016_01_04_175228_create_vendors_table.php @@ -79,7 +79,7 @@ class CreateVendorsTable extends Migration $table->date('expense_date')->nullable(); $table->text('private_notes'); $table->text('public_notes'); - $table->integer('currency_id', false, true)->nullable(); + $table->unsignedInteger('currency_id')->nullable(); $table->boolean('should_be_invoiced')->default(true); // Relations @@ -96,10 +96,9 @@ class CreateVendorsTable extends Migration $table->softDeletes(); $table->unsignedInteger('user_id'); $table->unsignedInteger('account_id'); - $table->integer('public_id')->default(0); - $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + //$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + //$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->unsignedInteger('public_id')->index(); $table->unique(array('account_id', 'public_id')); @@ -112,7 +111,7 @@ class CreateVendorsTable extends Migration ->get(); $i = 1; foreach ($paymentTerms as $pTerm) { - $data = ['public_id' => $i]; + $data = ['public_id' => $i++]; DB::table('paymet_terms')->where('id', $pTerm->id)->update($data); } diff --git a/database/seeds/ConstantsSeeder.php b/database/seeds/ConstantsSeeder.php index 8bef4c105342..ec2a94d49164 100644 --- a/database/seeds/ConstantsSeeder.php +++ b/database/seeds/ConstantsSeeder.php @@ -97,13 +97,13 @@ class ConstantsSeeder extends Seeder Size::create(array('name' => '101 - 500')); Size::create(array('name' => '500+')); - PaymentTerm::create(array('num_days' => 7, 'name' => 'Net 7')); - PaymentTerm::create(array('num_days' => 10, 'name' => 'Net 10')); - PaymentTerm::create(array('num_days' => 14, 'name' => 'Net 14')); - PaymentTerm::create(array('num_days' => 15, 'name' => 'Net 15')); - PaymentTerm::create(array('num_days' => 30, 'name' => 'Net 30')); - PaymentTerm::create(array('num_days' => 60, 'name' => 'Net 60')); - PaymentTerm::create(array('num_days' => 90, 'name' => 'Net 90')); + PaymentTerm::create(array('num_days' => 7, 'name' => 'Net 7', 'public_id' => 1)); + PaymentTerm::create(array('num_days' => 10, 'name' => 'Net 10', 'public_id' => 2)); + PaymentTerm::create(array('num_days' => 14, 'name' => 'Net 14', 'public_id' => 3)); + PaymentTerm::create(array('num_days' => 15, 'name' => 'Net 15', 'public_id' => 4)); + PaymentTerm::create(array('num_days' => 30, 'name' => 'Net 30', 'public_id' => 5)); + PaymentTerm::create(array('num_days' => 60, 'name' => 'Net 60', 'public_id' => 6)); + PaymentTerm::create(array('num_days' => 90, 'name' => 'Net 90', 'public_id' => 7)); PaymentLibrary::create(['name' => 'Omnipay']); PaymentLibrary::create(['name' => 'PHP-Payments [Deprecated]']); diff --git a/public/js/built.js b/public/js/built.js index 22b404a0efeb..0fc348bfa966 100644 --- a/public/js/built.js +++ b/public/js/built.js @@ -30234,6 +30234,44 @@ if (window.ko) { } }; + ko.bindingHandlers.combobox = { + init: function (element, valueAccessor, allBindingsAccessor) { + var options = allBindingsAccessor().dropdownOptions|| {}; + var value = ko.utils.unwrapObservable(valueAccessor()); + var id = (value && value.public_id) ? value.public_id() : (value && value.id) ? value.id() : value ? value : false; + if (id) $(element).val(id); + $(element).combobox(options); + + ko.utils.registerEventHandler(element, "change", function () { + var value = valueAccessor(); + value($(element).val()); + }); + }, + update: function (element, valueAccessor) { + var value = ko.utils.unwrapObservable(valueAccessor()); + var id = (value && value.public_id) ? value.public_id() : (value && value.id) ? value.id() : value ? value : false; + if (id) { + $(element).val(id); + $(element).combobox('refresh'); + } else { + $(element).combobox('clearTarget'); + $(element).combobox('clearElement'); + } + } + }; + + ko.bindingHandlers.fadeVisible = { + init: function(element, valueAccessor) { + // Initially set the element to be instantly visible/hidden depending on the value + var value = valueAccessor(); + $(element).toggle(ko.unwrap(value)); // Use "unwrapObservable" so we can handle values that may or may not be observable + }, + update: function(element, valueAccessor) { + // Whenever the value subsequently changes, slowly fade the element in or out + var value = valueAccessor(); + ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut(); + } + }; ko.bindingHandlers.datePicker = { init: function (element, valueAccessor, allBindingsAccessor) { @@ -30298,17 +30336,6 @@ function getClientDisplayName(client) return ''; } -function getVendorDisplayName(vendor) -{ - var contact = vendor.contacts ? vendor.vendorcontacts[0] : false; - if (vendor.name) { - return vendor.name; - } else if (contact) { - return getContactDisplayName(contact); - } - return ''; -} - function populateInvoiceComboboxes(clientId, invoiceId) { var clientMap = {}; var invoiceMap = {}; diff --git a/public/js/script.js b/public/js/script.js index 3857feae5f00..02dbc4b0c462 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -356,6 +356,31 @@ if (window.ko) { } }; + ko.bindingHandlers.combobox = { + init: function (element, valueAccessor, allBindingsAccessor) { + var options = allBindingsAccessor().dropdownOptions|| {}; + var value = ko.utils.unwrapObservable(valueAccessor()); + var id = (value && value.public_id) ? value.public_id() : (value && value.id) ? value.id() : value ? value : false; + if (id) $(element).val(id); + $(element).combobox(options); + + ko.utils.registerEventHandler(element, "change", function () { + var value = valueAccessor(); + value($(element).val()); + }); + }, + update: function (element, valueAccessor) { + var value = ko.utils.unwrapObservable(valueAccessor()); + var id = (value && value.public_id) ? value.public_id() : (value && value.id) ? value.id() : value ? value : false; + if (id) { + $(element).val(id); + $(element).combobox('refresh'); + } else { + $(element).combobox('clearTarget'); + $(element).combobox('clearElement'); + } + } + }; ko.bindingHandlers.datePicker = { init: function (element, valueAccessor, allBindingsAccessor) { diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 9110ad91dc79..a152021756c4 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -1016,7 +1016,8 @@ return array( // Expense / vendor 'expense' => 'Expense', 'expenses' => 'Expenses', - 'new_expense' => 'Create Expense', + 'new_expense' => 'Enter Expense', + 'enter_expense' => 'Enter Expense', 'vendors' => 'Vendors', 'new_vendor' => 'Create Vendor', 'payment_terms_net' => 'Net', @@ -1027,6 +1028,8 @@ return array( 'view_vendor' => 'View Vendor', 'deleted_expense' => 'Successfully deleted expense', 'archived_expense' => 'Successfully archived expense', + 'deleted_expenses' => 'Successfully deleted expenses', + 'archived_expenses' => 'Successfully archived expenses', // Expenses 'expense_amount' => 'Expense Amount', @@ -1034,7 +1037,7 @@ return array( 'expense_date' => 'Expense Date', 'expense_should_be_invoiced' => 'Should this expense be invoiced?', 'public_notes' => 'Public Notes', - 'foreign_amount' => 'Foreign Amount', + 'converted_amount' => 'Converted Amount', 'exchange_rate' => 'Exchange Rate', 'yes' => 'Yes', 'no' => 'No', @@ -1053,6 +1056,7 @@ return array( 'expense_error_multiple_clients' =>'The expenses can\'t belong to different clients', 'expense_error_invoiced' => 'Expense have already been invoiced', 'expense_error_should_not_be_invoiced' => 'Expense maked not to be invoiced', + 'convert_currency' => 'Convert currency', // Payment terms 'num_days' => 'Number of days', diff --git a/resources/views/accounts/bank_account.blade.php b/resources/views/accounts/bank_account.blade.php index 384ffe3e96fd..9ac7811b247f 100644 --- a/resources/views/accounts/bank_account.blade.php +++ b/resources/views/accounts/bank_account.blade.php @@ -166,10 +166,11 @@ $('#testModal').on('shown.bs.modal', function() { $('#bank_password').focus(); }); + + $('#bank_id').focus(); }); - // Here's my data model var ViewModel = function() { var self = this; self.bank_id = ko.observable({{ $bankAccount ? $bankAccount->bank_id : 0 }}); @@ -186,8 +187,6 @@ self.disableDoTest = ko.computed(function() { return !self.bank_id() || !self.bank_username() || !self.bank_password(); }, self); - - $('#bank_id').focus(); }; window.model = new ViewModel(); diff --git a/resources/views/expenses/edit.blade.php b/resources/views/expenses/edit.blade.php index 4fbcbd4e7321..2ad3559650b8 100644 --- a/resources/views/expenses/edit.blade.php +++ b/resources/views/expenses/edit.blade.php @@ -3,14 +3,7 @@ @section('head') @parent - + @include('money_script') @stop @section('content') @@ -27,31 +20,58 @@