Added ability to archive & delete

This commit is contained in:
Hillel Coren 2013-12-01 09:33:17 +02:00
parent 470e0bf06e
commit 329a47e761
20 changed files with 2355 additions and 54 deletions

View File

@ -216,5 +216,6 @@ return array(
'CreditCard' => 'Omnipay\Common\CreditCard',
'Image' => 'Intervention\Image\Facades\Image',
'Countries' => 'Webpatser\Countries\CountriesFacade',
'Carbon' => 'Carbon\Carbon',
),
);

View File

@ -12,12 +12,19 @@ class ClientController extends \BaseController {
//$clients = Client::orderBy('name')->get();
//return View::make('clients.index')->with('clients', $clients);
return View::make('clients.index');
return View::make('list', array(
'entityType'=>ENTITY_CLIENT,
'columns'=>['checkbox', 'Client', 'Contact', 'Balance', 'Last Login', 'Date Created', 'Email', 'Phone']
));
}
public function getDatatable()
{
return Datatable::collection(Client::with('contacts')->where('account_id','=',Auth::user()->account_id)->get())
->addColumn('checkbox', function($model)
{
return '<input type="checkbox" name="ids[]" value="' . $model->id . '">';
})
->addColumn('name', function($model)
{
//return $model->name;
@ -27,9 +34,17 @@ class ClientController extends \BaseController {
{
return $model->contacts[0]->getFullName();
})
->addColumn('balance', function($model)
{
return '$' . $model->balance;
})
->addColumn('last_login', function($model)
{
return $model->contacts[0]->lastLogin();
return $model->contacts[0]->getLastLogin();
})
->addColumn('date_created', function($model)
{
return $model->getDateCreated();
})
->addColumn('email', function($model)
{
@ -183,18 +198,27 @@ class ClientController extends \BaseController {
}
/**
* Remove the specified resource from storage.
* Bulk update the records
*
* @param int $id
* @return Response
*/
public function destroy($id)
public function bulk()
{
$client = Client::find($id);
$client->delete();
$action = Input::get('action');
$ids = Input::get('ids');
$clients = Client::find($ids);
foreach ($clients as $client) {
if ($action == 'archive') {
$client->delete();
} else if ($action == 'delete') {
$client->forceDelete();
}
}
$message = pluralize('Successfully '.$action.'d ? client', count($ids));
Session::flash('message', $message);
// redirect
Session::flash('message', 'Successfully deleted the client');
return Redirect::to('clients');
}
}

View File

@ -10,21 +10,29 @@ class InvoiceController extends \BaseController {
public function index()
{
//$invoices = Invoice::with('client')->orderBy('created_at', 'DESC')->get();
return View::make('invoices.index');
//return View::make('invoices.index');
return View::make('list', array(
'entityType'=>ENTITY_INVOICE,
'columns'=>['checkbox', 'Invoice Number', 'Client', 'Total', 'Amount Due', 'Invoice Date', 'Due Date', 'Status']
));
}
public function getDatatable($clientId = null)
{
$collection = Invoice::with('client','invoice_items')->where('account_id','=',Auth::user()->account_id);
$collection = Invoice::with('client','invoice_items','invoice_status')->where('account_id','=',Auth::user()->account_id);
if ($clientId) {
$collection->where('client_id','=',$clientId);
}
$table = Datatable::collection($collection->get())->addColumn('number', function($model)
{
return link_to('invoices/' . $model->id . '/edit', $model->invoice_number);
});
$table = Datatable::collection($collection->get())->addColumn('checkbox', function($model)
{
return '<input type="checkbox" name="ids[]" value="' . $model->id . '">';
})
->addColumn('invoice_number', function($model)
{
return link_to('invoices/' . $model->id . '/edit', $model->invoice_number);
});
if (!$clientId)
{
@ -34,13 +42,25 @@ class InvoiceController extends \BaseController {
}
return $table->addColumn('amount', function($model)
return $table->addColumn('total', function($model)
{
return '$' . money_format('%i', $model->getTotal());
})
->addColumn('date', function($model)
->addColumn('amount_due', function($model)
{
return $model->created_at->format('m/d/y h:i a');
return '$' . money_format('%i', $model->getTotal());
})
->addColumn('invoice_date', function($model)
{
return (new Carbon($model->invoice_date))->toFormattedDateString();
})
->addColumn('due_date', function($model)
{
return $model->due_date == '0000-00-00' ? '' : (new Carbon($model->due_date))->toFormattedDateString();
})
->addColumn('status', function($model)
{
return $model->invoice_status->name;
})
->orderColumns('number')
->make();
@ -375,13 +395,23 @@ class InvoiceController extends \BaseController {
* @param int $id
* @return Response
*/
public function destroy($id)
public function bulk()
{
$invoice = Invoice::find($id);
$invoice->delete();
$action = Input::get('action');
$ids = Input::get('ids');
$invoices = Invoice::find($ids);
foreach ($invoices as $invoice) {
if ($action == 'archive') {
$invoice->delete();
} else if ($action == 'delete') {
$invoice->forceDelete();
}
}
$message = pluralize('Successfully '.$action.'d ? invoice', count($ids));
Session::flash('message', $message);
// redirect
Session::flash('message', 'Successfully deleted the invoice');
return Redirect::to('invoices');
}
}

View File

@ -10,6 +10,7 @@ class ConfideSetupUsersTable extends Migration {
*/
public function up()
{
Schema::dropIfExists('invoice_statuses');
Schema::dropIfExists('invitations');
Schema::dropIfExists('activities');
Schema::dropIfExists('account_gateways');
@ -110,7 +111,7 @@ class ConfideSetupUsersTable extends Migration {
$t->integer('country_id');
$t->string('work_phone');
$t->text('notes');
$t->decimal('balance', 10, 2);
//$t->foreign('account_id')->references('id')->on('accounts');
});
@ -136,6 +137,7 @@ class ConfideSetupUsersTable extends Migration {
$t->increments('id');
$t->integer('client_id');
$t->integer('account_id');
$t->integer('invoice_status_id')->default(1);
$t->timestamps();
$t->softDeletes();
@ -147,6 +149,12 @@ class ConfideSetupUsersTable extends Migration {
//$t->foreign('account_id')->references('id')->on('accounts');
});
Schema::create('invoice_statuses', function($t)
{
$t->increments('id');
$t->string('name');
});
Schema::create('invitations', function($t)
{
@ -232,6 +240,7 @@ class ConfideSetupUsersTable extends Migration {
*/
public function down()
{
Schema::dropIfExists('invoice_statuses');
Schema::dropIfExists('invitations');
Schema::dropIfExists('activities');
Schema::dropIfExists('account_gateways');

View File

@ -5,7 +5,38 @@ class ConstantsSeeder extends Seeder
public function run()
{
DB::table('gateways')->delete();
// TEST DATA
/*
$contact = new Contact;
$contact->first_name = 'Hillel';
$contact->last_name = 'Hillel';
$contact->email = 'hillelcoren@gmail.com';
$contact->last_name = '2125551234';
$client->contacts()->save($contact);
$invoice = new Invoice;
$invoice->invoice_number = '0001';
$client->invoices()->save($invoice);
$invoice = new Invoice;
$invoice->invoice_number = '0002';
$client->invoices()->save($invoice);
$invoice = new Invoice;
$invoice->invoice_number = '0003';
$client->invoices()->save($invoice);
$invoice = new Invoice;
$invoice->invoice_number = '0004';
$client->invoices()->save($invoice);
*/
InvoiceStatus::create(array('name' => 'Draft'));
InvoiceStatus::create(array('name' => 'Sent'));
InvoiceStatus::create(array('name' => 'Viewed'));
InvoiceStatus::create(array('name' => 'Partial'));
InvoiceStatus::create(array('name' => 'Paid'));
$gateways = [
array('name'=>'Authorize.Net AIM', 'provider'=>'AuthorizeNet_AIM'),

View File

@ -81,11 +81,14 @@ Route::filter('csrf', function()
$tokenInput = Input::get('_token');
$tokenSession = Session::token();
/*
if ($url = Session::get($tokenInput))
{
return Redirect::to($url);
}
else if ($tokenSession != $tokenInput)
*/
if ($tokenSession != $tokenInput)
{
throw new Illuminate\Session\TokenMismatchException;
}

View File

@ -79,6 +79,19 @@ class Client extends Eloquent
return $str;
}
public function getDateCreated()
{
if ($this->created_at == '0000-00-00 00:00:00')
{
return '---';
}
else
{
return $this->created_at->format('m/d/y h:i a');
}
}
}
Client::created(function($client)

View File

@ -14,7 +14,7 @@ class Contact extends Eloquent
return $this->belongsTo('Client');
}
public function lastLogin()
public function getLastLogin()
{
if ($this->last_login == '0000-00-00 00:00:00')
{
@ -22,7 +22,7 @@ class Contact extends Eloquent
}
else
{
return $this->last_login;
return $this->last_login->format('m/d/y h:i a');
}
}

View File

@ -14,6 +14,11 @@ class Invoice extends Eloquent
return $this->hasMany('InvoiceItem');
}
public function invoice_status()
{
return $this->belongsTo('InvoiceStatus');
}
public function getTotal()
{
$total = 0;

6
app/models/InvoiceStatus.php Executable file
View File

@ -0,0 +1,6 @@
<?php
class InvoiceStatus extends Eloquent
{
public $timestamps = false;
}

View File

@ -37,13 +37,16 @@ Route::group(array('before' => array('auth', 'csrf')), function()
Route::resource('clients', 'ClientController');
Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable'));
Route::post('clients/bulk', 'ClientController@bulk');
Route::resource('invoices', 'InvoiceController');
Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable'));
Route::get('invoices/create/{client_id}', 'InvoiceController@create');
Route::post('invoices/bulk', 'InvoiceController@bulk');
Route::get('payments', 'PaymentController@index');
Route::get('api/payments/{client_id?}', array('as'=>'api.payments', 'uses'=>'PaymentController@getDatatable'));
Route::post('payments/bulk', 'PaymentController@bulk');
Route::get('home', function() { return View::make('header'); });
Route::get('reports', function() { return View::make('header'); });
@ -179,9 +182,9 @@ define("ENV_STAGING", "staging");
define("ENV_PRODUCTION", "production");
define("RECENTLY_VIEWED", "RECENTLY_VIEWED");
define("ENTITY_CLIENT", "Client");
define("ENTITY_INVOICE", "Invoice");
define("ENTITY_PAYMENT", "Payment");
define("ENTITY_CLIENT", "client");
define("ENTITY_INVOICE", "invoice");
define("ENTITY_PAYMENT", "payment");
define("ACCOUNT_DETAILS", "details");
define("ACCOUNT_SETTINGS", "settings");

View File

@ -5,7 +5,7 @@
{{ Button::primary_link(URL::to('clients/create'), 'New Client', array('class' => 'pull-right')) }}
{{ Datatable::table()
->addColumn('Client', 'Contact', 'Last Login', 'Email', 'Phone')
->addColumn('Client', 'Contact', 'Balance', 'Last Login', 'Date Created', 'Email', 'Phone')
->setUrl(route('api.clients'))
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)

55
app/views/datatable.blade.php Executable file
View File

@ -0,0 +1,55 @@
<table class="table table-bordered {{ $class = str_random(8) }}">
<colgroup>
@for ($i = 0; $i < count($columns); $i++)
<col class="con{{ $i }}" />
@endfor
</colgroup>
<thead>
<tr>
@foreach($columns as $i => $c)
<th align="center" valign="middle" class="head{{ $i }}">
@if ($c == 'checkbox' && $haeCheckboxes = true)
<input type="checkbox" id="selectAll"/>
@else
{{ $c }}
@endif
</th>
@endforeach
</tr>
</thead>
<tbody>
@foreach($data as $d)
<tr>
@foreach($d as $dd)
<td>{{ $dd }}</td>
@endforeach
</tr>
@endforeach
</tbody>
</table>
<script type="text/javascript">
jQuery(document).ready(function(){
// dynamic table
jQuery('.{{ $class }}').dataTable({
// Disable sorting on the first column
@if ($haeCheckboxes)
"aoColumnDefs" : [ {
'bSortable' : false,
'aTargets' : [ 0 ]
} ],
@endif
@foreach ($options as $k => $o)
{{ json_encode($k) }}: {{ json_encode($o) }},
@endforeach
@foreach ($callbacks as $k => $o)
{{ json_encode($k) }}: {{ $o }},
@endforeach
"fnDrawCallback": function(oSettings) {
//jQuery.uniform.update();
if (window.onDatatableReady) {
window.onDatatableReady();
}
}
});
});
</script>

View File

@ -37,7 +37,6 @@
<link rel="stylesheet" type="text/css" href="{{ asset('css/jquery.dataTables.css') }}">
<script type="text/javascript" src="{{ asset('js/jquery.dataTables.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/jquery.dataTables.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/knockout-3.0.0.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/knockout.mapping-latest.js') }}"></script>
<script src="{{ asset('js/knockout-sortable.js') }}" type="text/javascript"></script>
@ -51,13 +50,6 @@
<script src="{{ asset('js/script.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
@yield('onReady')
});
</script>
<style type="text/css">
@ -110,7 +102,7 @@
}
div.dataTables_paginate.paging_bootstrap {
margin-top: -30px;
margin-top: -20px;
}
table.table tbody tr.odd {
@ -312,6 +304,7 @@
}
@endif
@yield('onReady')
});
</script>

View File

@ -26,8 +26,8 @@
</div>
<div class="col-md-5">
{{ Former::text('invoice_number')->label('Invoice #') }}
{{ Former::text('invoice_date') }}
{{ Former::text('due_date') }}
{{ Former::text('invoice_date')->label('Invoice Date') }}
{{ Former::text('due_date')->label('Due Date') }}
{{-- Former::text('discount')->data_bind("value: discount, valueUpdate: 'afterkeydown'") --}}
</div>
</div>

View File

@ -2,13 +2,70 @@
@section('content')
{{ Former::open('invoices/action') }}
<div style="display:none">{{ Former::text('action') }}</div>
{{ DropdownButton::normal('Archive',
Navigation::links(
array(
array('Archive', "javascript:submitForm('archive')"),
array('Delete', "javascript:submitForm('delete')"),
)
)
, array('id'=>'archive'))->split(); }}
{{ Button::primary_link(URL::to('invoices/create'), 'New Invoice', array('class' => 'pull-right')) }}
{{ Datatable::table()
->addColumn('Invoice Number', 'Client', 'Amount', 'Date')
->addColumn('checkbox', 'Invoice Number', 'Client', 'Total', 'Amount Due', 'Invoice Date', 'Due Date', 'Status')
->setUrl(route('api.invoices'))
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->render() }}
->render('datatable') }}
{{ Former::close() }}
<script type="text/javascript">
function submitForm(action) {
$('#action').val(action);
$('form').submit();
}
</script>
@stop
@section('onReady')
window.onDatatableReady = function() {
$(':checkbox').click(function() {
setArchiveEnabled();
});
$('tbody tr').click(function() {
$checkbox = $(this).closest('tr').find(':checkbox');
var checked = $checkbox.prop('checked');
$checkbox.prop('checked', !checked);
setArchiveEnabled();
});
}
$('#archive > button').prop('disabled', true);
$('#archive > button:first').click(function() {
submitForm('archive');
});
$('#selectAll').click(function() {
$(':checkbox').prop('checked', this.checked);
});
function setArchiveEnabled() {
var checked = $('tbody :checkbox:checked').length > 0;
$('#archive > button').prop('disabled', !checked);
}
@stop

73
app/views/list.blade.php Executable file
View File

@ -0,0 +1,73 @@
@extends('header')
@section('content')
{{ Former::open($entityType . 's/bulk') }}
<div style="display:none">{{ Former::text('action') }}</div>
{{ DropdownButton::normal('Archive',
Navigation::links(
array(
array('Archive', "javascript:submitForm('archive')"),
array('Delete', "javascript:submitForm('delete')"),
)
)
, array('id'=>'archive'))->split(); }}
{{ Button::primary_link(URL::to($entityType . 's/create'), 'New ' . ucwords($entityType), array('class' => 'pull-right')) }}
{{ Datatable::table()
->addColumn($columns)
->setUrl(route('api.' . $entityType . 's'))
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->render('datatable') }}
{{ Former::close() }}
<script type="text/javascript">
function submitForm(action) {
$('#action').val(action);
$('form').submit();
}
</script>
@stop
@section('onReady')
window.onDatatableReady = function() {
$(':checkbox').click(function() {
setArchiveEnabled();
});
$('tbody tr').click(function(event) {
if (event.target.type !== 'checkbox') {
$checkbox = $(this).closest('tr').find(':checkbox');
var checked = $checkbox.prop('checked');
$checkbox.prop('checked', !checked);
setArchiveEnabled();
}
});
}
$('#archive > button').prop('disabled', true);
$('#archive > button:first').click(function() {
submitForm('archive');
});
$('#selectAll').click(function() {
$(':checkbox').prop('checked', this.checked);
});
function setArchiveEnabled() {
var checked = $('tbody :checkbox:checked').length > 0;
$('#archive > button').prop('disabled', !checked);
}
@stop

2002
public/js/bootstrap.js vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@ -126,16 +126,12 @@ function formatMoney(num) {
/* Set the defaults for DataTables initialisation */
$.extend( true, $.fn.dataTable.defaults, {
"sDom": "<'row-fluid'<'span6'l><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>",
"sDom": "t<'row-fluid'<'span6'l><'span6'p>>",
"sPaginationType": "bootstrap",
"bProcessing": false,
"bInfo": false,
"oLanguage": {
"sLengthMenu": "_MENU_ records per page"
}