Working on expenses

This commit is contained in:
Hillel Coren 2016-01-21 22:36:49 +02:00
parent b24a6109ba
commit 7a26dd610c
9 changed files with 61 additions and 70 deletions

View File

@ -172,17 +172,12 @@ class ExpenseController extends BaseController
return Redirect::to('expenses'); return Redirect::to('expenses');
} }
if ($expense->should_be_invoiced == 0) {
Session::flash('error', trans('texts.expense_error_should_not_be_invoiced'));
return Redirect::to('expenses');
}
$account = Auth::user()->account; $account = Auth::user()->account;
$data[] = [ $data[] = [
'publicId' => $expense->public_id, 'publicId' => $expense->public_id,
'description' => $expense->public_notes, 'description' => $expense->public_notes,
'qty' => 1, 'qty' => 1,
'cost' => $expense->amount, 'cost' => $expense->present()->converted_amount,
]; ];
} }

View File

@ -16,6 +16,9 @@ class Expense extends EntityModel
protected $presenter = 'App\Ninja\Presenters\ExpensePresenter'; protected $presenter = 'App\Ninja\Presenters\ExpensePresenter';
protected $fillable = [ protected $fillable = [
'client_id',
'vendor_id',
'currency_id',
'amount', 'amount',
'foreign_amount', 'foreign_amount',
'exchange_rate', 'exchange_rate',

View File

@ -15,4 +15,9 @@ class ExpensePresenter extends Presenter {
{ {
return Utils::fromSqlDate($this->entity->expense_date); return Utils::fromSqlDate($this->entity->expense_date);
} }
public function converted_amount()
{
return round($this->entity->amount * $this->entity->exchange_rate, 2);
}
} }

View File

@ -50,7 +50,6 @@ class ExpenseRepository extends BaseRepository
->where('expenses.account_id', '=', $accountid) ->where('expenses.account_id', '=', $accountid)
->select('expenses.account_id', ->select('expenses.account_id',
'expenses.amount', 'expenses.amount',
'expenses.converted_amount',
'expenses.currency_id', 'expenses.currency_id',
'expenses.deleted_at', 'expenses.deleted_at',
'expenses.exchange_rate', 'expenses.exchange_rate',
@ -94,48 +93,15 @@ class ExpenseRepository extends BaseRepository
// First auto fill // First auto fill
$expense->fill($input); $expense->fill($input);
// We can have an expense without a vendor
if (isset($input['vendor_id'])) {
$expense->vendor_id = $input['vendor_id'];
}
$expense->expense_date = Utils::toSqlDate($input['expense_date']); $expense->expense_date = Utils::toSqlDate($input['expense_date']);
$expense->amount = Utils::parseFloat($input['amount']);
if (isset($input['converted_amount'])) {
$expense->converted_amount = Utils::parseFloat($input['converted_amount']);
}
$expense->private_notes = trim($input['private_notes']); $expense->private_notes = trim($input['private_notes']);
$expense->public_notes = trim($input['public_notes']); $expense->public_notes = trim($input['public_notes']);
if (isset($input['exchange_rate'])) {
$expense->exchange_rate = Utils::parseFloat($input['exchange_rate']);
} else {
$expense->exchange_rate = 100;
}
if ($expense->exchange_rate == 0) {
$expense->exchange_rate = 100;
}
// set the currency
if (isset($input['currency_id'])) {
$expense->currency_id = $input['currency_id'];
}
if ($expense->currency_id == 0) {
$expense->currency_id = Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY);
}
// Calculate the amount cur
$expense->converted_amount = ($expense->amount / 100) * $expense->exchange_rate;
$expense->should_be_invoiced = isset($input['should_be_invoiced']) || $expense->client_id ? true : false; $expense->should_be_invoiced = isset($input['should_be_invoiced']) || $expense->client_id ? true : false;
if (isset($input['client_id'])) { $rate = isset($input['exchange_rate']) ? Utils::parseFloat($input['exchange_rate']) : 1;
$expense->client_id = $input['client_id']; $expense->exchange_rate = round($rate, 4);
} $expense->amount = round(Utils::parseFloat($input['amount']), 2);
$expense->save(); $expense->save();
return $expense; return $expense;

View File

@ -75,7 +75,7 @@ class CreateVendorsTable extends Migration
$table->boolean('is_deleted')->default(false); $table->boolean('is_deleted')->default(false);
$table->decimal('amount', 13, 2); $table->decimal('amount', 13, 2);
$table->decimal('foreign_amount', 13, 2); $table->decimal('foreign_amount', 13, 2);
$table->decimal('exchange_rate', 13, 2); $table->decimal('exchange_rate', 13, 4);
$table->date('expense_date')->nullable(); $table->date('expense_date')->nullable();
$table->text('private_notes'); $table->text('private_notes');
$table->text('public_notes'); $table->text('public_notes');

View File

@ -30260,19 +30260,6 @@ if (window.ko) {
} }
}; };
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 = { ko.bindingHandlers.datePicker = {
init: function (element, valueAccessor, allBindingsAccessor) { init: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor()); var value = ko.utils.unwrapObservable(valueAccessor());
@ -30841,6 +30828,11 @@ function roundToTwo(num, toString) {
return toString ? val.toFixed(2) : (val || 0); return toString ? val.toFixed(2) : (val || 0);
} }
function roundToFour(num, toString) {
var val = +(Math.round(num + "e+4") + "e-4");
return toString ? val.toFixed(4) : (val || 0);
}
function truncate(str, length) { function truncate(str, length) {
return (str && str.length > length) ? (str.substr(0, length-1) + '...') : str; return (str && str.length > length) ? (str.substr(0, length-1) + '...') : str;
} }

View File

@ -950,6 +950,11 @@ function roundToTwo(num, toString) {
return toString ? val.toFixed(2) : (val || 0); return toString ? val.toFixed(2) : (val || 0);
} }
function roundToFour(num, toString) {
var val = +(Math.round(num + "e+4") + "e-4");
return toString ? val.toFixed(4) : (val || 0);
}
function truncate(str, length) { function truncate(str, length) {
return (str && str.length > length) ? (str.substr(0, length-1) + '...') : str; return (str && str.length > length) ? (str.substr(0, length-1) + '...') : str;
} }

View File

@ -1055,7 +1055,6 @@ return array(
'invoice_expense' => 'Invoice Expense', 'invoice_expense' => 'Invoice Expense',
'expense_error_multiple_clients' =>'The expenses can\'t belong to different clients', 'expense_error_multiple_clients' =>'The expenses can\'t belong to different clients',
'expense_error_invoiced' => 'Expense have already been invoiced', 'expense_error_invoiced' => 'Expense have already been invoiced',
'expense_error_should_not_be_invoiced' => 'Expense maked not to be invoiced',
'convert_currency' => 'Convert currency', 'convert_currency' => 'Convert currency',
// Payment terms // Payment terms

View File

@ -27,6 +27,7 @@
{!! Former::text('amount') {!! Former::text('amount')
->label(trans('texts.amount')) ->label(trans('texts.amount'))
->data_bind("value: amount, valueUpdate: 'afterkeydown'")
->addGroupClass('amount') ->addGroupClass('amount')
->append($account->present()->currencyCode) !!} ->append($account->present()->currencyCode) !!}
@ -42,10 +43,12 @@
->data_bind('combobox: client_id') ->data_bind('combobox: client_id')
->addGroupClass('client-select') !!} ->addGroupClass('client-select') !!}
{!! Former::checkbox('should_be_invoiced') @if (!$expense || ($expense && !$expense->invoice_id))
->text(trans('texts.should_be_invoiced')) {!! Former::checkbox('should_be_invoiced')
->data_bind('checked: should_be_invoiced() || client_id(), enable: !client_id()') ->text(trans('texts.should_be_invoiced'))
->label(' ') !!}<br/> ->data_bind('checked: should_be_invoiced() || client_id(), enable: !client_id()')
->label(' ') !!}<br/>
@endif
<span style="display:none" data-bind="visible: !client_id()"> <span style="display:none" data-bind="visible: !client_id()">
{!! Former::select('currency_id')->addOption('','') {!! Former::select('currency_id')->addOption('','')
@ -60,11 +63,11 @@
</span> </span>
{!! Former::text('exchange_rate') {!! Former::text('exchange_rate')
->data_bind('enable: enableExchangeRate') !!} ->data_bind("value: exchange_rate, enable: enableExchangeRate, valueUpdate: 'afterkeydown'") !!}
{!! Former::text('converted_amount') {!! Former::text('converted_amount')
->addGroupClass('converted-amount') ->addGroupClass('converted-amount')
->data_bind('enable: enableExchangeRate') ->data_bind("value: convertedAmount, enable: enableExchangeRate")
->append('<span data-bind="html: currencyCode"></span>') !!} ->append('<span data-bind="html: currencyCode"></span>') !!}
</div> </div>
@ -127,8 +130,15 @@
onClientChange(); onClientChange();
}); });
window.model = new ViewModel(); @if ($data)
ko.applyBindings(model); // this means we failed so we'll reload the previous state
window.model = new ViewModel({!! $data !!});
@else
// otherwise create blank model
window.model = new ViewModel({!! $expense !!});
ko.applyBindings(model);
@endif
@if (!$expense && $clientPublicId) @if (!$expense && $clientPublicId)
onClientChange(); onClientChange();
@ -141,15 +151,30 @@
@endif @endif
}); });
var ViewModel = function() { var ViewModel = function(data) {
var self = this; var self = this;
self.client_id = ko.observable({{ $clientPublicId }}); self.client_id = ko.observable({{ $clientPublicId }});
self.vendor_id = ko.observable({{ $vendorPublicId }}); self.vendor_id = ko.observable({{ $vendorPublicId }});
self.currency_id = ko.observable({{ $expense && $expense->currency_id ? $expense->currency_id : null }}); self.currency_id = ko.observable();
self.should_be_invoiced = ko.observable({{ $expense && ($expense->should_be_invoiced || $expense->client_id) ? 'true' : 'false' }}); self.amount = ko.observable();
self.exchange_rate = ko.observable(1);
self.should_be_invoiced = ko.observable();
self.account_currency_id = ko.observable({{ $account->getCurrencyId() }}); self.account_currency_id = ko.observable({{ $account->getCurrencyId() }});
if (data) {
ko.mapping.fromJS(data, {}, this);
}
self.convertedAmount = ko.computed({
read: function () {
return roundToTwo(self.amount() * self.exchange_rate()).toFixed(2);
},
write: function(value) {
self.exchange_rate(roundToFour(value / self.amount()));
}
}, self);
self.currencyCode = ko.computed(function() { self.currencyCode = ko.computed(function() {
var currencyId = self.currency_id() || self.account_currency_id(); var currencyId = self.currency_id() || self.account_currency_id();
var currency = currencyMap[currencyId]; var currency = currencyMap[currencyId];
@ -159,6 +184,7 @@
self.currencyName = ko.computed(function() { self.currencyName = ko.computed(function() {
var currencyId = self.currency_id() || self.account_currency_id(); var currencyId = self.currency_id() || self.account_currency_id();
var currency = currencyMap[currencyId]; var currency = currencyMap[currencyId];
console.log(currencyId);
return currency.name; return currency.name;
}); });