1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-09 12:42:36 +01:00

bug fixes

This commit is contained in:
Hillel Coren 2014-01-08 20:09:47 +00:00
parent 4f8d5d7890
commit 75b1350808
29 changed files with 212 additions and 47 deletions

View File

@ -1,7 +1,7 @@
# Invoice Ninja
## Simple, Intuitive Invoicing
### Live demo: [http://invoiceninja.eu1.frbit.net](http://invoiceninja.eu1.frbit.net)
### Live demo: [http://www.invoiceninja.com](http://www.invoiceninja.com)
### Introduction
Most online invoicing sites are expensive. They shouldn't be. The aim of this project is to provide a free, open-source alternative. Additionally, the hope is this codebase will serve as a sample site for Laravel as well as other JavaScript technologies.

View File

@ -111,7 +111,7 @@ return array(
| table, otherwise they will not be able to login after the payment.
|
*/
'signup_email' => false,
'signup_confirm' => false,
'signup_email' => true,
'signup_confirm' => true,
);

View File

@ -12,7 +12,7 @@ class ActivityController extends \BaseController {
return Datatable::query($query)
->addColumn('created_at', function($model) { return Utils::timestampToDateTimeString(strtotime($model->created_at)); })
->addColumn('message', function($model) { return $model->message; })
->addColumn('message', function($model) { return Utils::decodeActivity($model->message); })
->addColumn('balance', function($model) { return Utils::formatMoney($model->balance, $model->currency_id); })
->addColumn('adjustment', function($model) { return $model->adjustment != 0 ? Utils::formatMoney($model->adjustment, $model->currency_id) : ''; })
->make();

View File

@ -213,6 +213,8 @@ class ClientController extends \BaseController {
$contact->delete();
}
}
Activity::createClient($client);
if ($publicId) {
Session::flash('message', 'Successfully updated client');

View File

@ -9,6 +9,11 @@ class HomeController extends BaseController {
return View::make('splash');
}
public function showComingSoon()
{
return View::make('coming_soon');
}
public function logError()
{
$count = Session::get('error_count', 0);

View File

@ -74,8 +74,8 @@ class UserController extends BaseController {
{
if( Confide::user() )
{
Event::fire('user.login');
return Redirect::to('/clients');
Event::fire('user.login');
return Redirect::to('/invoices/create');
}
else
{

View File

@ -283,4 +283,31 @@ class Utils
}
}
public static function encodeActivity($person = null, $action, $entity = null, $otherPerson = null)
{
$person = $person ? $person->getFullName() : '<i>System</i>';
$entity = $entity ? '[' . $entity->getKey() . ']' : '';
$otherPerson = $otherPerson ? 'to ' . $otherPerson->getFullName() : '';
return trim("$person $action $entity $otherPerson");
}
public static function decodeActivity($message)
{
$pattern = '/\[([\w]*):([\d]*):(.*)\]/i';
preg_match($pattern, $message, $matches);
if (count($matches) > 0)
{
$match = $matches[0];
$type = $matches[1];
$publicId = $matches[2];
$name = $matches[3];
$link = link_to($type . 's/' . $publicId, $name);
$message = str_replace($match, "$type $link", $message);
}
return $message;
}
}

View File

@ -20,6 +20,9 @@ define("ACTIVITY_TYPE_DELETE_CREDIT", 15);
class Activity extends Eloquent
{
public $timestamps = true;
protected $softDelete = false;
public function scopeScope($query)
{
return $query->whereAccountId(Auth::user()->account_id);
@ -53,7 +56,7 @@ class Activity extends Eloquent
$activity = Activity::getBlank();
$activity->client_id = $client->id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_CLIENT;
$activity->message = Auth::user()->getFullName() . ' created client ' . link_to('clients/'.$client->public_id, $client->name);
$activity->message = Utils::encodeActivity(Auth::user(), 'created', $client);
$activity->save();
}
@ -64,7 +67,7 @@ class Activity extends Eloquent
$activity = Activity::getBlank();
$activity->client_id = $client->id;
$activity->activity_type_id = ACTIVITY_TYPE_DELETE_CLIENT;
$activity->message = Auth::user()->getFullName() . ' deleted client ' . link_to('clients/'.$client->public_id, $client->name);
$activity->message = Utils::encodeActivity(Auth::user(), 'deleted', $client);
$activity->save();
}
}
@ -76,7 +79,7 @@ class Activity extends Eloquent
$activity = Activity::getBlank();
$activity->client_id = $client->id;
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_CLIENT;
$activity->message = Auth::user()->getFullName() . ' archived client ' . link_to('clients/'.$client->public_id, $client->name);
$activity->message = Utils::encodeActivity(Auth::user(), 'archived', $client);
$activity->balance = $client->balance;
$activity->save();
}
@ -84,15 +87,13 @@ class Activity extends Eloquent
public static function createInvoice($invoice)
{
$userName = Auth::check() ? Auth::user()->getFullName() : '<i>System</i>';
if ($invoice->is_recurring)
{
$message = $userName . ' created ' . link_to('invoices/'.$invoice->public_id, 'recuring invoice');
$message = Utils::encodeActivity(null, 'created recurring', $invoice);
}
else
{
$message = $userName . ' created invoice ' . link_to('invoices/'.$invoice->public_id, $invoice->invoice_number);
$message = Utils::encodeActivity(Auth::user(), 'created', $invoice);
}
$activity = Activity::getBlank($invoice);
@ -125,7 +126,7 @@ class Activity extends Eloquent
$activity->invoice_id = $invoice->id;
$activity->client_id = $invoice->client_id;
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_INVOICE;
$activity->message = Auth::user()->getFullName() . ' archived invoice ' . $invoice->invoice_number;
$activity->message = Utils::encodeActivity(Auth::user(), 'archived', $invoice);
$activity->balance = $client->balance;
$activity->adjustment = $invoice->balance;
@ -151,7 +152,7 @@ class Activity extends Eloquent
$activity->invoice_id = $invitation->invoice_id;
$activity->contact_id = $invitation->contact_id;
$activity->activity_type_id = ACTIVITY_TYPE_EMAIL_INVOICE;
$activity->message = $userName . ' emailed invoice ' . link_to('invoices/'.$invitation->invoice->public_id, $invitation->invoice->invoice_number) . ' to ' . $invitation->contact->getDisplayName();
$activity->message = Utils::encodeActivity(Auth::check() ? Auth::user() : null, 'emailed', $invoice, $invitation->contact);
$activity->balance = $client->balance;
$activity->adjustment = $adjustment;
$activity->save();
@ -177,7 +178,7 @@ class Activity extends Eloquent
$activity->client_id = $invoice->client_id;
$activity->invoice_id = $invoice->id;
$activity->activity_type_id = ACTIVITY_TYPE_DELETE_INVOICE;
$activity->message = Auth::user()->getFullName() . ' deleted invoice ' . link_to('invoices/'.$invoice->public_id, $invoice->invoice_number);
$activity->message = Utils::encodeActivity(Auth::user(), 'deleted', $invoice);
$activity->balance = $client->balance;
$activity->adjustment = $invoice->balance * -1;
$activity->save();
@ -201,7 +202,7 @@ class Activity extends Eloquent
$activity->client_id = $invoice->client_id;
$activity->invoice_id = $invoice->id;
$activity->activity_type_id = ACTIVITY_TYPE_UPDATE_INVOICE;
$activity->message = Auth::user()->getFullName() . ' updated invoice ' . link_to('invoices/'.$invoice->public_id, $invoice->invoice_number);
$activity->message = Utils::encodeActivity(Auth::user(), 'updated', $invoice);
$activity->balance = $client->balance;
$activity->adjustment = $diff;
$activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON();
@ -219,7 +220,7 @@ class Activity extends Eloquent
if (Auth::check())
{
$activity = Activity::getBlank();
$activity->message = Auth::user()->getFullName() . ' created payment ' . $payment->transaction_reference;
$activity->message = Utils::encodeActivity(Auth::user(), 'created payment');
}
else
{
@ -254,7 +255,7 @@ class Activity extends Eloquent
$client->save();
$activity = Activity::getBlank();
$activity->message = Auth::user()->getFullName() . ' created credit';
$activity->message = Utils::encodeActivity(Auth::user(), 'created credit');
$activity->credit_id = $credit->id;
$activity->client_id = $credit->client_id;
@ -280,7 +281,7 @@ class Activity extends Eloquent
$activity->invoice_id = $invoice->id;
$activity->client_id = $invoice->client_id;
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_PAYMENT;
$activity->message = Auth::user()->getFullName() . ' archived payment';
$activity->message = Utils::encodeActivity(Auth::user(), 'archived payment');
$activity->balance = $payment->client->balance;
$activity->save();
}
@ -312,7 +313,7 @@ class Activity extends Eloquent
$activity->contact_id = $invitation->contact_id;
$activity->invoice_id = $invitation->invoice_id;
$activity->activity_type_id = ACTIVITY_TYPE_VIEW_INVOICE;
$activity->message = $invitation->contact->getFullName() . ' viewed invoice ' . link_to('invoices/'.$invitation->invoice->public_id, $invitation->invoice->invoice_number);
$activity->message = Utils::encodeActivity($invitation->contact, 'viewed', $invitation->invoice);
$activity->balance = $invitation->invoice->client->balance;
$activity->save();
}

View File

@ -49,7 +49,7 @@ class Client extends EntityModel
public function getName()
{
return $this->name;
return $this->getDisplayName();
}
public function getDisplayName()
@ -59,6 +59,7 @@ class Client extends EntityModel
return $this->name;
}
$this->load('contacts');
$contact = $this->contacts()->first();
return $contact->getDisplayName();
@ -164,10 +165,12 @@ class Client extends EntityModel
}
}
/*
Client::created(function($client)
{
Activity::createClient($client);
});
*/
Client::updating(function($client)
{

View File

@ -2,5 +2,8 @@
class Country extends Eloquent
{
public $timestamps = false;
protected $softDelete = false;
protected $visible = ['id', 'name'];
}

View File

@ -14,7 +14,7 @@ class Credit extends EntityModel
public function getName()
{
return $this->credit_number;
return '';
}
public function getEntityType()

View File

@ -3,6 +3,8 @@
class EntityModel extends Eloquent
{
protected $softDelete = true;
public $timestamps = false;
protected $hidden = ['id', 'created_at', 'deleted_at', 'updated_at'];
public static function createNew($parent = false)
@ -40,10 +42,22 @@ class EntityModel extends Eloquent
return $className::scope($publicId)->pluck('id');
}
public function getKey()
{
return $this->getEntityType() . ':' . $this->public_id . ':' . $this->getName();
}
/*
public function getEntityType()
{
return '';
}
public function getNmae()
{
return '';
}
*/
public function scopeScope($query, $publicId = false, $accountId = false)
{

View File

@ -3,4 +3,5 @@
class Frequency extends Eloquent
{
public $timestamps = false;
protected $softDelete = false;
}

View File

@ -2,5 +2,6 @@
class Gateway extends Eloquent
{
public $timestamps = false;
protected $softDelete = false;
}

View File

@ -3,4 +3,6 @@
class Industry extends Eloquent
{
public $timestamps = false;
protected $softDelete = false;
}

View File

@ -3,4 +3,5 @@
class InvoiceStatus extends Eloquent
{
public $timestamps = false;
protected $softDelete = false;
}

View File

@ -20,7 +20,6 @@ class Payment extends EntityModel
public function getName()
{
return '';
//return $this->invoice_number;
}
public function getEntityType()

View File

@ -3,4 +3,5 @@
class Size extends Eloquent
{
public $timestamps = false;
protected $softDelete = false;
}

View File

@ -3,4 +3,5 @@
class Timezone extends Eloquent
{
public $timestamps = false;
protected $softDelete = false;
}

View File

@ -87,4 +87,16 @@ class User extends ConfideUser implements UserInterface, RemindableInterface
{
return !$this->theme_id || in_array($this->theme_id, [2, 3, 5, 6, 7, 8, 10, 11, 12]);
}
public function afterSave($success=true, $forced = false)
{
if ($this->email)
{
return parent::afterSave($success=true, $forced = false);
}
else
{
return true;
}
}
}

View File

@ -95,6 +95,8 @@ class ClientRepository
}
$client->save();
\Activity::createClient($client);
return $client;
}

View File

@ -191,6 +191,13 @@ class InvoiceRepository
$invoice->balance = $total;
$invoice->save();
if ($data['set_default_terms'])
{
$account = \Auth::user()->account;
$account->invoice_terms = $invoice->terms;
$account->save();
}
return $invoice;
}
}

View File

@ -26,14 +26,16 @@ DB::listen(function($sql)) {
}
*/
// TODO_FIX replace with cron
Route::get('/send_emails', function() {
Artisan::call('ninja:send-invoices');
});
Route::get('/', 'HomeController@showWelcome');
Route::get('/', 'HomeController@showComingSoon');
Route::get('/rocksteady', 'HomeController@showWelcome');
Route::get('log_error', 'HomeController@logError');
Route::post('get_started', 'AccountController@getStarted');
@ -47,7 +49,7 @@ Route::post('signup/submit', 'AccountController@submitSignup');
// Confide routes
Route::get('login', 'UserController@login');
Route::post('login', 'UserController@do_login');
//Route::get( 'user/confirm/{code}', 'UserController@confirm');
Route::get( 'user/confirm/{code}', 'UserController@confirm');
Route::get('forgot_password', 'UserController@forgot_password');
Route::post('forgot_password', 'UserController@do_forgot_password');
//Route::get('user/reset_password/{token}', 'UserController@reset_password');
@ -135,7 +137,7 @@ define('CONTACT_EMAIL', 'contact@invoiceninja.com');
define('ENV_DEVELOPMENT', 'local');
define('ENV_STAGING', 'staging');
define('ENV_PRODUCTION', 'production');
define('ENV_PRODUCTION', 'fortrabbit');
define('RECENTLY_VIEWED', 'RECENTLY_VIEWED');
define('ENTITY_CLIENT', 'client');

35
app/views/coming_soon.blade.php Executable file
View File

@ -0,0 +1,35 @@
@extends('master')
@section('body')
<style type="text/css">
html, body {
height: 100%
vertical-align: middle;
}
.main_div {
width: 500px;
height: 200px;
position: absolute;
top:0;
bottom: 0;
left: 0;
right: 0;
font-size: 72px;
font-family: arial;
color: #CCCCCC;
margin: auto;
}
</style>
<div class="main_div">
coming soon
</div>
@stop

View File

@ -41,7 +41,7 @@
@if (isset($hasCheckboxes) && $hasCheckboxes)
"aoColumnDefs" : [ {
'bSortable' : false,
'aTargets' : [ 0 ]
'aTargets' : [ 0, {{ count($columns) - 1 }} ]
} ],
@endif
@foreach ($options as $k => $o)

View File

@ -35,7 +35,8 @@
@if (!Auth::check() || Auth::user()->showGreyBackground())
body {
background-color: #F6F6F6;
/* background-color: #F6F6F6; */
background-color: #EEEEEE;
}
@endif

View File

@ -147,7 +147,11 @@
{{ Former::textarea('public_notes')->data_bind("value: wrapped_notes, valueUpdate: 'afterkeydown'")
->label(false)->placeholder('Note to client')->style('width: 520px; resize: none') }}
{{ Former::textarea('terms')->data_bind("value: wrapped_terms, valueUpdate: 'afterkeydown'")
->label(false)->placeholder('Invoice terms')->style('width: 520px; resize: none') }}
->label(false)->placeholder('Invoice terms')->style('width: 520px; resize: none')
->addGroupClass('less-space-bottom') }}
<label class="checkbox">
<input type="checkbox" style="width: 24px" data-bind="checked: set_default_terms"/>Save as default terms
</label>
</td>
<td data-bind="visible: $root.invoice_item_taxes.show"/>
<td colspan="2">Subtotal</td>
@ -250,7 +254,7 @@
{{ Button::primary_submit('Save Invoice', array('data-bind'=>'css: $root.enable.save')) }}
@endif
{{ Button::primary('Send Email', array('id' => 'email_button', 'onclick' => 'onEmailClick()', 'data-bind' => 'css: $root.enable.email')) }}
{{ Button::primary('Email Invoice', array('id' => 'email_button', 'onclick' => 'onEmailClick()', 'data-bind' => 'css: $root.enable.email')) }}
</div>
<p>&nbsp;</p>
@ -269,7 +273,7 @@
</div>
<div class="container" style="width: 100%">
<div style="background-color: #F6F6F6" class="row" data-bind="with: client" onkeypress="clientModalEnterClick(event)">
<div style="background-color: #EEEEEE" class="row" data-bind="with: client" onkeypress="clientModalEnterClick(event)">
<div class="col-md-6" style="margin-left:0px;margin-right:0px" >
{{ Former::legend('Organization') }}
@ -347,7 +351,7 @@
<h4 class="modal-title" id="taxModalLabel">Tax Rates</h4>
</div>
<div style="background-color: #F6F6F6" onkeypress="taxModalEnterClick(event)">
<div style="background-color: #EEEEEE" onkeypress="taxModalEnterClick(event)">
<table class="table invoice-table sides-padded" style="margin-bottom: 0px !important">
<thead>
<tr>
@ -376,7 +380,7 @@
{{ Former::checkbox('invoice_taxes')->text('Enable specifying an <b>invoice tax</b>')
->label('Settings')->data_bind('checked: $root.invoice_taxes, enable: $root.tax_rates().length > 1') }}
{{ Former::checkbox('invoice_item_taxes')->text('Enable specifying <b>line item taxes</b>')->addOnGroupClass('no-space-bottom')
{{ Former::checkbox('invoice_item_taxes')->text('Enable specifying <b>line item taxes</b>')
->label('&nbsp;')->data_bind('checked: $root.invoice_item_taxes, enable: $root.tax_rates().length > 1') }}
<br/>
@ -393,11 +397,43 @@
</div>
<div class="modal fade" id="notSignedUpModal" tabindex="-1" role="dialog" aria-labelledby="notSignedUpModalLabel" aria-hidden="true">
<div class="modal-dialog" style="min-width:150px">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="notSignedUpModalLabel">Email Invoice</h4>
</div>
<div style="background-color: #EEEEEE; padding-left: 16px; padding-right: 16px">
@if (Auth::user()->registered)
<p>Please confirm your account to email an invoice.</p>
@else
<p>Please sign up to email an invoice.</p>
@endif
</div>
<div class="modal-footer" style="margin-top: 0px">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
@if (!Auth::user()->registered)
<button type="button" class="btn btn-primary" onclick="showSignUp()">Sign Up</button>
@endif
</div>
</div>
</div>
</div>
{{ Former::close() }}
</div>
<script type="text/javascript">
function showSignUp() {
$('#notSignedUpModal').modal('hide');
$('#signUpModal').modal('show');
}
$(function() {
@ -557,9 +593,13 @@
}
function onEmailClick() {
if (confirm('Are you sure you want to email this invoice?')) {
$('#action').val('email');
$('.main_form').submit();
if ({{ !Auth::user()->confirmed ? 'true' : 'false' }}) {
$('#notSignedUpModal').modal('show');
} else {
if (confirm('Are you sure you want to email this invoice?')) {
$('#action').val('email');
$('.main_form').submit();
}
}
}
@ -801,12 +841,13 @@
//$('.client_select .combobox-container').addClass('combobox-selected');
$('#emailError').css( "display", "none" );
//$('.client_select input.form-control').focus();
$('#invoice_number').focus();
//$('.client_select input.form-control').focus();
refreshPDF();
model.clientBackup = false;
$('#clientModal').modal('hide');
$('#invoice_number').focus();
}
self.enable = {};
@ -858,6 +899,7 @@
//self.currency_id = ko.observable({{ Session::get(SESSION_CURRENCY) }});
self.currency_id = ko.observable({{ $client && $client->currency_id ? $client->currency_id : Session::get(SESSION_CURRENCY) }});
self.terms = ko.observable(wordWrapText('{{ $account->invoice_terms }}', 340));
self.set_default_terms = ko.observable(false);
self.public_notes = ko.observable('');
self.po_number = ko.observable('');
self.invoice_date = ko.observable('{{ Utils::today() }}');
@ -1256,8 +1298,11 @@
this.totals.total = ko.computed(function() {
var total = self.totals.rawTotal();
//return total ? formatMoney(total, model.invoice.currency_id()) : '';
return total ? formatMoney(total, 1) : ''; // TODO_FIX
if (window.hasOwnProperty('model') && model.invoice && model.invoice()) {
return total ? formatMoney(total, model.invoice().currency_id()) : '';
} else {
return total ? formatMoney(total, 1) : '';
}
});
this.hideActions = function() {

View File

@ -37,7 +37,7 @@
<body>
@if (App::environment() != ENV_DEVELOPMENT)
@if (App::environment() == ENV_PRODUCTION)
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),

View File

@ -21,9 +21,9 @@ div.panel {
text-align: center;
}
.no-space-bottom {
padding-bottom: 0px !important;
margin-bottom: 0px !important;
.less-space-bottom {
padding-bottom: 4px !important;
margin-bottom: 4px !important;
}
/* DataTables and BootStrap */