Working on PDF

This commit is contained in:
Hillel Coren 2013-12-01 22:58:25 +02:00
parent aff89cd073
commit 49800b394c
24 changed files with 579 additions and 150 deletions

View File

@ -167,6 +167,12 @@ class AccountController extends \BaseController {
$count = 0; $count = 0;
$hasHeaders = Input::get('header_checkbox'); $hasHeaders = Input::get('header_checkbox');
$countries = Country::all();
$countryMap = [];
foreach ($countries as $country) {
$countryMap[strtolower($country->name)] = $country->id;
}
foreach ($data as $row) foreach ($data as $row)
{ {
if ($hasHeaders) if ($hasHeaders)
@ -212,6 +218,11 @@ class AccountController extends \BaseController {
{ {
$client->postal_code = $value; $client->postal_code = $value;
} }
else if ($field == Client::$fieldCountry)
{
$value = strtolower($value);
$client->country_id = isset($countryMap[$value]) ? $countryMap[$value] : null;
}
else if ($field == Client::$fieldNotes) else if ($field == Client::$fieldNotes)
{ {
$client->notes = $value; $client->notes = $value;
@ -266,6 +277,7 @@ class AccountController extends \BaseController {
Client::$fieldCity, Client::$fieldCity,
Client::$fieldState, Client::$fieldState,
Client::$fieldPostalCode, Client::$fieldPostalCode,
Client::$fieldCountry,
Client::$fieldNotes, Client::$fieldNotes,
Contact::$fieldFirstName, Contact::$fieldFirstName,
Contact::$fieldLastName, Contact::$fieldLastName,
@ -304,6 +316,7 @@ class AccountController extends \BaseController {
'city' => Client::$fieldCity, 'city' => Client::$fieldCity,
'state' => Client::$fieldState, 'state' => Client::$fieldState,
'zip|postal|code' => Client::$fieldPostalCode, 'zip|postal|code' => Client::$fieldPostalCode,
'country' => Client::$fieldCountry,
'note' => Client::$fieldNotes, 'note' => Client::$fieldNotes,
); );

View File

@ -6,15 +6,10 @@ class ActivityController extends \BaseController {
{ {
return Datatable::collection(Activity::where('account_id','=',Auth::user()->account_id) return Datatable::collection(Activity::where('account_id','=',Auth::user()->account_id)
->where('client_id','=',$clientId)->get()) ->where('client_id','=',$clientId)->get())
->addColumn('date', function($model) ->addColumn('date', function($model) { return $model->created_at->format('m/d/y h:i a'); })
{ ->addColumn('message', function($model) { return $model->message; })
return $model->created_at->format('m/d/y h:i a'); ->addColumn('balance', function($model) { return '$' . $model->balance; })
}) ->orderColumns('date')
->addColumn('message', function($model)
{
return $model->message;
})
->orderColumns('date')
->make(); ->make();
} }

View File

@ -14,49 +14,39 @@ class ClientController extends \BaseController {
return View::make('list', array( return View::make('list', array(
'entityType'=>ENTITY_CLIENT, 'entityType'=>ENTITY_CLIENT,
'columns'=>['checkbox', 'Client', 'Contact', 'Balance', 'Last Login', 'Date Created', 'Email', 'Phone'] 'columns'=>['checkbox', 'Client', 'Contact', 'Balance', 'Last Login', 'Date Created', 'Email', 'Phone', 'Action']
)); ));
} }
public function getDatatable() public function getDatatable()
{ {
return Datatable::collection(Client::with('contacts')->where('account_id','=',Auth::user()->account_id)->get()) $clients = Client::with('contacts')->where('account_id','=',Auth::user()->account_id)->get();
->addColumn('checkbox', function($model)
{ return Datatable::collection($clients)
return '<input type="checkbox" name="ids[]" value="' . $model->id . '">'; ->addColumn('checkbox', function($model) { return '<input type="checkbox" name="ids[]" value="' . $model->id . '">'; })
}) ->addColumn('name', function($model) { return link_to('clients/' . $model->id, $model->name); })
->addColumn('name', function($model) ->addColumn('contact', function($model) { return $model->contacts[0]->getFullName(); })
{ ->addColumn('balance', function($model) { return '$' . $model->balance; })
//return $model->name; ->addColumn('last_login', function($model) { return $model->contacts[0]->getLastLogin(); })
return link_to('clients/' . $model->id, $model->name); ->addColumn('date_created', function($model) { return $model->getDateCreated(); })
}) ->addColumn('email', function($model) { return HTML::mailto($model->contacts[0]->email, $model->contacts[0]->email); })
->addColumn('contact', function($model) ->addColumn('phone', function($model) { return $model->contacts[0]->phone; })
{ ->addColumn('dropdown', function($model)
return $model->contacts[0]->getFullName(); {
}) return '<div class="btn-group tr-action" style="display:none">
->addColumn('balance', function($model) <button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
{ Select <span class="caret"></span>
return '$' . $model->balance; </button>
}) <ul class="dropdown-menu" role="menu">
->addColumn('last_login', function($model) <li><a href="' . URL::to('clients/'.$model->id.'/edit') . '">Edit</a></li>
{ <li class="divider"></li>
return $model->contacts[0]->getLastLogin(); <li><a href="' . URL::to('clients/'.$model->id.'/archive') . '">Archive</a></li>
}) <li><a href="javascript:deleteEntity(' . $model->id. ')">Delete</a></li>
->addColumn('date_created', function($model) </ul>
{ </div>';
return $model->getDateCreated(); })
})
->addColumn('email', function($model)
{
//return $model->contacts[0]->email;
return HTML::mailto($model->contacts[0]->email, $model->contacts[0]->email);
})
->addColumn('phone', function($model)
{
return $model->contacts[0]->phone;
})
->orderColumns('name') ->orderColumns('name')
->make(); ->make();
} }
/** /**
@ -199,11 +189,6 @@ class ClientController extends \BaseController {
} }
/**
* Bulk update the records
*
* @return Response
*/
public function bulk() public function bulk()
{ {
$action = Input::get('action'); $action = Input::get('action');
@ -223,4 +208,27 @@ class ClientController extends \BaseController {
return Redirect::to('clients'); return Redirect::to('clients');
} }
public function archive($id)
{
$client = Client::find($id);
$client->delete();
foreach ($client->invoices as $invoice)
{
$invoice->delete();
}
Session::flash('message', 'Successfully archived ' . $client->name);
return Redirect::to('clients');
}
public function delete($id)
{
$client = Client::find($id);
$client->forceDelete();
Session::flash('message', 'Successfully deleted ' . $client->name);
return Redirect::to('clients');
}
} }

View File

@ -0,0 +1,61 @@
<?php
class CreditController extends \BaseController {
/**
* Display a listing of the resource.
*
* @return Response
*/
public function index()
{
return View::make('list', array(
'entityType'=>ENTITY_CREDIT,
'columns'=>['checkbox', 'Credit Number', 'Client', 'Amount', 'Credit Date']
));
}
public function getDatatable($clientId = null)
{
$collection = Credit::with('client')->where('account_id','=',Auth::user()->account_id);
if ($clientId) {
$collection->where('client_id','=',$clientId);
}
$table = Datatable::collection($collection->get());
if (!$clientId) {
$table->addColumn('checkbox', function($model) { return '<input type="checkbox" name="ids[]" value="' . $model->id . '">'; });
}
$table->addColumn('credit_number', function($model) { return $model->credit_number; });
if (!$clientId) {
$table->addColumn('client', function($model) { return link_to('clients/' . $model->client->id, $model->client->name); });
}
return $table->addColumn('amount', function($model){ return '$' . money_format('%i', $model->amount); })
->addColumn('credit_date', function($model) { return (new Carbon($model->credit_date))->toFormattedDateString(); })
->orderColumns('number')
->make();
}
public function archive($id)
{
$credit = Credit::find($id);
$creidt->delete();
Session::flash('message', 'Successfully archived credit ' . $credit->credit_number);
return Redirect::to('credits');
}
public function delete($id)
{
$credit = Credit::find($id);
$credit->forceDelete();
Session::flash('message', 'Successfully deleted credit ' . $credit->credit_number);
return Redirect::to('credits');
}
}

View File

@ -9,11 +9,9 @@ class InvoiceController extends \BaseController {
*/ */
public function index() public function index()
{ {
//$invoices = Invoice::with('client')->orderBy('created_at', 'DESC')->get();
//return View::make('invoices.index');
return View::make('list', array( return View::make('list', array(
'entityType'=>ENTITY_INVOICE, 'entityType'=>ENTITY_INVOICE,
'columns'=>['checkbox', 'Invoice Number', 'Client', 'Total', 'Amount Due', 'Invoice Date', 'Due Date', 'Status'] 'columns'=>['checkbox', 'Invoice Number', 'Client', 'Total', 'Amount Due', 'Invoice Date', 'Due Date', 'Status', 'Action']
)); ));
} }
@ -25,43 +23,37 @@ class InvoiceController extends \BaseController {
$collection->where('client_id','=',$clientId); $collection->where('client_id','=',$clientId);
} }
$table = Datatable::collection($collection->get())->addColumn('checkbox', function($model) $table = Datatable::collection($collection->get());
{
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)
{
$table->addColumn('client', function($model) {
return link_to('clients/' . $model->client->id, $model->client->name);
});
if (!$clientId) {
$table->addColumn('checkbox', function($model) { return '<input type="checkbox" name="ids[]" value="' . $model->id . '">'; });
} }
return $table->addColumn('total', function($model) $table->addColumn('invoice_number', function($model) { return link_to('invoices/' . $model->id . '/edit', $model->invoice_number); });
{
return '$' . money_format('%i', $model->getTotal()); if (!$clientId) {
}) $table->addColumn('client', function($model) { return link_to('clients/' . $model->client->id, $model->client->name); });
->addColumn('amount_due', function($model) }
{
return '$' . money_format('%i', $model->getTotal()); return $table->addColumn('total', function($model){ return '$' . money_format('%i', $model->getTotal()); })
}) ->addColumn('amount_due', function($model) { return '$' . money_format('%i', $model->getTotal()); })
->addColumn('invoice_date', function($model) ->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(); })
return (new Carbon($model->invoice_date))->toFormattedDateString(); ->addColumn('status', function($model) { return $model->invoice_status->name; })
}) ->addColumn('dropdown', function($model)
->addColumn('due_date', function($model) {
{ return '<div class="btn-group tr-action" style="display:none">
return $model->due_date == '0000-00-00' ? '' : (new Carbon($model->due_date))->toFormattedDateString(); <button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
}) Select <span class="caret"></span>
->addColumn('status', function($model) </button>
{ <ul class="dropdown-menu" role="menu">
return $model->invoice_status->name; <li><a href="' . URL::to('invoices/'.$model->id.'/edit') . '">Edit</a></li>
}) <li class="divider"></li>
<li><a href="' . URL::to('invoices/'.$model->id.'/archive') . '">Archive</a></li>
<li><a href="javascript:deleteEntity(' . $model->id . ')">Delete</a></li>
</ul>
</div>';
})
->orderColumns('number') ->orderColumns('number')
->make(); ->make();
} }
@ -72,7 +64,10 @@ class InvoiceController extends \BaseController {
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.account.account_gateways')->where('key', '=', $key)->firstOrFail(); $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.account.account_gateways')->where('key', '=', $key)->firstOrFail();
$contact = null; $contact = null;
Activity::viewInvoice($invitation); $invitation->viewed_date = new date('Y-m-d H:i:s');
$invitation->save();
Activity::log($invitation->invoice->client, ACTIVITY_TYPE_VIEW_INVOICE, $contact, $invitation);
return View::make('invoices.view')->with('invoice', $invitation->invoice); return View::make('invoices.view')->with('invoice', $invitation->invoice);
} }
@ -205,10 +200,11 @@ class InvoiceController extends \BaseController {
public function edit($id) public function edit($id)
{ {
$invoice = Invoice::with('client', 'invoice_items')->find($id); $invoice = Invoice::with('account.country', 'client', 'invoice_items')->find($id);
trackViewed($invoice->invoice_number . ' - ' . $invoice->client->name); trackViewed($invoice->invoice_number . ' - ' . $invoice->client->name);
$data = array( $data = array(
'account' => $invoice->account,
'invoice' => $invoice, 'invoice' => $invoice,
'method' => 'PUT', 'method' => 'PUT',
'url' => 'invoices/' . $id, 'url' => 'invoices/' . $id,
@ -224,8 +220,10 @@ class InvoiceController extends \BaseController {
{ {
$client = null; $client = null;
$invoiceNumber = Auth::user()->account->getNextInvoiceNumber(); $invoiceNumber = Auth::user()->account->getNextInvoiceNumber();
$account = Account::with('country')->find(Auth::user()->account_id);
$data = array( $data = array(
'account' => $account,
'invoice' => null, 'invoice' => null,
'invoiceNumber' => $invoiceNumber, 'invoiceNumber' => $invoiceNumber,
'method' => 'POST', 'method' => 'POST',
@ -280,8 +278,8 @@ class InvoiceController extends \BaseController {
} }
else else
{ {
$client = Client::with('contacts')->find($clientId); $client = Client::with('contacts')->find($clientId);
$contact = $client->contacts[0]; $contact = $client->contacts()->first();
} }
if ($id) { if ($id) {
@ -290,8 +288,8 @@ class InvoiceController extends \BaseController {
} else { } else {
$invoice = new Invoice; $invoice = new Invoice;
$invoice->account_id = Auth::user()->account_id; $invoice->account_id = Auth::user()->account_id;
} }
$invoice->client_id = $clientId; $invoice->client_id = $clientId;
$invoice->invoice_number = Input::get('invoice_number'); $invoice->invoice_number = Input::get('invoice_number');
$invoice->discount = 0; $invoice->discount = 0;
@ -356,7 +354,6 @@ class InvoiceController extends \BaseController {
$invitation->key = str_random(20); $invitation->key = str_random(20);
$invitation->save(); $invitation->save();
Session::flash('message', 'Successfully emailed invoice'); Session::flash('message', 'Successfully emailed invoice');
} else { } else {
Session::flash('message', 'Successfully saved invoice'); Session::flash('message', 'Successfully saved invoice');
@ -376,8 +373,10 @@ class InvoiceController extends \BaseController {
*/ */
public function show($id) public function show($id)
{ {
$invoice = Invoice::find($id); return Redirect::to('invoices/'.$id.'/edit');
return View::make('invoices.show')->with('invoice', $invoice);
//$invoice = Invoice::find($id);
//return View::make('invoices.show')->with('invoice', $invoice);
} }
/** /**
@ -416,4 +415,22 @@ class InvoiceController extends \BaseController {
return Redirect::to('invoices'); return Redirect::to('invoices');
} }
public function archive($id)
{
$invoice = Invoice::find($id);
$invoice->delete();
Session::flash('message', 'Successfully archived invoice ' . $invoice->invoice_number);
return Redirect::to('invoices');
}
public function delete($id)
{
$invoice = Invoice::find($id);
$invoice->forceDelete();
Session::flash('message', 'Successfully deleted invoice ' . $invoice->invoice_number);
return Redirect::to('invoices');
}
} }

View File

@ -40,4 +40,21 @@ class PaymentController extends \BaseController
->make(); ->make();
} }
public function archive($id)
{
$payment = Payment::find($id);
$payment->delete();
Session::flash('message', 'Successfully archived payment');
return Redirect::to('payments');
}
public function delete($id)
{
$payment = Payment::find($id);
$payment->forceDelete();
Session::flash('message', 'Successfully deleted payment');
return Redirect::to('payments');
}
} }

View File

@ -10,6 +10,7 @@ class ConfideSetupUsersTable extends Migration {
*/ */
public function up() public function up()
{ {
Schema::dropIfExists('credits');
Schema::dropIfExists('activities'); Schema::dropIfExists('activities');
Schema::dropIfExists('invitations'); Schema::dropIfExists('invitations');
Schema::dropIfExists('account_gateways'); Schema::dropIfExists('account_gateways');
@ -196,6 +197,8 @@ class ConfideSetupUsersTable extends Migration {
$t->timestamps(); $t->timestamps();
$t->softDeletes(); $t->softDeletes();
$t->timestamp('viewed_date');
$t->foreign('user_id')->references('id')->on('users'); $t->foreign('user_id')->references('id')->on('users');
$t->foreign('contact_id')->references('id')->on('contacts'); $t->foreign('contact_id')->references('id')->on('contacts');
$t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); $t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
@ -210,7 +213,7 @@ class ConfideSetupUsersTable extends Migration {
$t->string('key'); $t->string('key');
$t->string('notes'); $t->string('notes');
$t->decimal('cost', 8, 2); $t->decimal('cost', 10, 2);
$t->integer('qty'); $t->integer('qty');
$t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
@ -227,7 +230,7 @@ class ConfideSetupUsersTable extends Migration {
$t->string('product_key'); $t->string('product_key');
$t->string('notes'); $t->string('notes');
$t->decimal('cost', 8, 2); $t->decimal('cost', 10, 2);
$t->integer('qty'); $t->integer('qty');
$t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); $t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
@ -239,13 +242,14 @@ class ConfideSetupUsersTable extends Migration {
$t->increments('id'); $t->increments('id');
$t->unsignedInteger('invoice_id'); $t->unsignedInteger('invoice_id');
$t->unsignedInteger('account_id'); $t->unsignedInteger('account_id');
$t->unsignedInteger('client_id')->nullable(); $t->unsignedInteger('client_id');
$t->unsignedInteger('contact_id')->nullable(); $t->unsignedInteger('contact_id')->nullable();
$t->unsignedInteger('user_id'); $t->unsignedInteger('user_id')->nullable();
$t->timestamps(); $t->timestamps();
$t->softDeletes(); $t->softDeletes();
$t->decimal('amount', 8, 2); $t->decimal('amount', 10, 2);
$t->date('payment_date');
$t->string('transaction_reference'); $t->string('transaction_reference');
$t->string('payer_id'); $t->string('payer_id');
@ -256,20 +260,44 @@ class ConfideSetupUsersTable extends Migration {
$t->foreign('user_id')->references('id')->on('users'); $t->foreign('user_id')->references('id')->on('users');
}); });
Schema::create('activities', function($t) Schema::create('credits', function($t)
{ {
$t->increments('id'); $t->increments('id');
$t->unsignedInteger('account_id'); $t->unsignedInteger('account_id');
$t->unsignedInteger('client_id'); $t->unsignedInteger('client_id')->nullable();
$t->unsignedInteger('user_id')->nullable();
$t->unsignedInteger('contact_id')->nullable(); $t->unsignedInteger('contact_id')->nullable();
$t->unsignedInteger('invoice_id')->nullable(); $t->timestamps();
$t->unsignedInteger('payment_id')->nullable(); $t->softDeletes();
$t->unsignedInteger('invitation_id')->nullable();
$t->decimal('amount', 10, 2);
$t->date('credit_date');
$t->string('credit_number');
$t->foreign('account_id')->references('id')->on('accounts');
$t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade');
$t->foreign('contact_id')->references('id')->on('contacts');
});
Schema::create('activities', function($t)
{
$t->increments('id');
$t->timestamps(); $t->timestamps();
$t->integer('activity_type_id'); $t->unsignedInteger('account_id');
$t->unsignedInteger('client_id');
$t->unsignedInteger('user_id');
$t->unsignedInteger('contact_id');
$t->unsignedInteger('payment_id');
$t->unsignedInteger('invoice_id');
$t->unsignedInteger('credit_id');
$t->text('message'); $t->text('message');
$t->integer('activity_type_id');
$t->decimal('adjustment', 10, 2);
$t->decimal('balance', 10, 2);
$t->foreign('account_id')->references('id')->on('accounts');
$t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade');
}); });
} }
@ -280,6 +308,7 @@ class ConfideSetupUsersTable extends Migration {
*/ */
public function down() public function down()
{ {
Schema::dropIfExists('credits');
Schema::dropIfExists('activities'); Schema::dropIfExists('activities');
Schema::dropIfExists('invitations'); Schema::dropIfExists('invitations');
Schema::dropIfExists('account_gateways'); Schema::dropIfExists('account_gateways');

View File

@ -24,6 +24,11 @@ class Account extends Eloquent
return $this->hasMany('AccountGateway'); return $this->hasMany('AccountGateway');
} }
public function country()
{
return $this->belongsTo('Country');
}
public function isGatewayConfigured($gatewayId = 0) public function isGatewayConfigured($gatewayId = 0)
{ {
if ($gatewayId) if ($gatewayId)
@ -73,7 +78,7 @@ class Account extends Eloquent
if ($order) if ($order)
{ {
$number = intval($order->invoice_number) + 1; $number = intval($order->invoice_number) + 1;
return str_pad($number, 5, "0", STR_PAD_LEFT); return str_pad($number, 4, "0", STR_PAD_LEFT);
} }
else else
{ {

View File

@ -1,13 +1,20 @@
<?php <?php
define("ACTIVITY_TYPE_CREATE_CLIENT", 1); define("ACTIVITY_TYPE_CREATE_CLIENT", 1);
define("ACTIVITY_TYPE_ARCHIVE_CLIENT", 2); define("ACTIVITY_TYPE_ARCHIVE_CLIENT", 2);
define("ACTIVITY_TYPE_CREATE_INVOICE", 3); define("ACTIVITY_TYPE_DELETE_CLIENT", 3);
define("ACTIVITY_TYPE_EMAIL_INVOICE", 4); define("ACTIVITY_TYPE_CREATE_INVOICE", 4);
define("ACTIVITY_TYPE_VIEW_INVOICE", 5); define("ACTIVITY_TYPE_EMAIL_INVOICE", 5);
define("ACTIVITY_TYPE_ARCHIVE_INVOICE", 6); define("ACTIVITY_TYPE_VIEW_INVOICE", 6);
define("ACTIVITY_TYPE_CREATE_PAYMENT", 7); define("ACTIVITY_TYPE_ARCHIVE_INVOICE", 7);
define("ACTIVITY_TYPE_ARCHIVE_PAYMENT", 8); define("ACTIVITY_TYPE_DELETE_INVOICE", 8);
define("ACTIVITY_TYPE_CREATE_PAYMENT", 9);
define("ACTIVITY_TYPE_ARCHIVE_PAYMENT", 10);
define("ACTIVITY_TYPE_DELETE_PAYMENT", 11);
define("ACTIVITY_TYPE_CREATE_CREDIT", 12);
define("ACTIVITY_TYPE_ARCHIVE_CREDIT", 13);
define("ACTIVITY_TYPE_DELETE_CREDIT", 14);
class Activity extends Eloquent class Activity extends Eloquent
{ {
@ -26,7 +33,8 @@ class Activity extends Eloquent
$activity = Activity::getBlank(); $activity = Activity::getBlank();
$activity->client_id = $client->id; $activity->client_id = $client->id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_CLIENT; $activity->activity_type_id = ACTIVITY_TYPE_CREATE_CLIENT;
$activity->message = Auth::user()->getFullName() . ' created client ' . $client->name; $activity->message = Auth::user()->getFullName() . ' created client ' . link_to('clients/'.$client->id, $client->name);
$activity->save(); $activity->save();
} }
@ -45,7 +53,7 @@ class Activity extends Eloquent
$activity->invoice_id = $invoice->id; $activity->invoice_id = $invoice->id;
$activity->client_id = $invoice->client_id; $activity->client_id = $invoice->client_id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_INVOICE; $activity->activity_type_id = ACTIVITY_TYPE_CREATE_INVOICE;
$activity->message = Auth::user()->getFullName() . ' created invoice ' . $invoice->number; $activity->message = Auth::user()->getFullName() . ' created invoice ' . link_to('invoices/'.$invoice->id, $invoice->invoice_number);
$activity->save(); $activity->save();
} }
@ -55,7 +63,7 @@ class Activity extends Eloquent
$activity->invoice_id = $invoice->id; $activity->invoice_id = $invoice->id;
$activity->client_id = $invoice->client_id; $activity->client_id = $invoice->client_id;
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_INVOICE; $activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_INVOICE;
$activity->message = Auth::user()->getFullName() . ' archived invoice ' . $invoice->number; $activity->message = Auth::user()->getFullName() . ' archived invoice ' . $invoice->invoice_number;
$activity->save(); $activity->save();
} }
@ -74,7 +82,7 @@ class Activity extends Eloquent
if (Auth::check()) if (Auth::check())
{ {
$activity = Activity::getBlank(); $activity = Activity::getBlank();
$activity->message = Auth::user()->getFullName() . ' created invoice ' . $payment->transaction_reference; $activity->message = Auth::user()->getFullName() . ' created payment ' . $payment->transaction_reference;
} }
else else
{ {

View File

@ -1,6 +1,6 @@
<?php <?php
class Client extends Eloquent class Client extends Eloquent implements iEntity
{ {
protected $softDelete = true; protected $softDelete = true;
@ -12,6 +12,7 @@ class Client extends Eloquent
public static $fieldState = 'Client - State'; public static $fieldState = 'Client - State';
public static $fieldPostalCode = 'Client - Postal Code'; public static $fieldPostalCode = 'Client - Postal Code';
public static $fieldNotes = 'Client - Notes'; public static $fieldNotes = 'Client - Notes';
public static $fieldCountry = 'Client - Country';
public function account() public function account()
{ {
@ -28,6 +29,21 @@ class Client extends Eloquent
return $this->hasMany('Contact'); return $this->hasMany('Contact');
} }
public function country()
{
return $this->belongsTo('Country');
}
public function getName()
{
return $this->name;
}
public function getEntityType()
{
return ENTITY_CLIENT;
}
public function getAddress() public function getAddress()
{ {
$str = ''; $str = '';
@ -47,6 +63,9 @@ class Client extends Eloquent
if ($this->postal_code) { if ($this->postal_code) {
$str .= $this->postal_code; $str .= $this->postal_code;
} }
if ($this->country) {
$str .= '<br/>' . $this->country->name;
}
if ($str) if ($str)
{ {

View File

@ -1,6 +1,6 @@
<?php <?php
class Contact extends Eloquent class Contact extends Eloquent implements iPerson
{ {
protected $softDelete = true; protected $softDelete = true;
@ -14,6 +14,11 @@ class Contact extends Eloquent
return $this->belongsTo('Client'); return $this->belongsTo('Client');
} }
public function getPersonType()
{
return PERSON_CONTACT;
}
public function getLastLogin() public function getLastLogin()
{ {
if ($this->last_login == '0000-00-00 00:00:00') if ($this->last_login == '0000-00-00 00:00:00')
@ -32,7 +37,7 @@ class Contact extends Eloquent
if ($fullName == ' ') if ($fullName == ' ')
{ {
return 'Guest'; return '';
} }
else else
{ {

26
app/models/Credit.php Executable file
View File

@ -0,0 +1,26 @@
<?php
class Credit extends Eloquent implements iEntity
{
protected $softDelete = true;
public function invoice()
{
return $this->belongsTo('Invoice');
}
public function getName()
{
return $this->credit_number;
}
public function getEntityType()
{
return ENTITY_CREDIT;
}
}
Credit::created(function($credit)
{
Activity::creaateCredit($credit);
});

View File

@ -1,8 +1,13 @@
<?php <?php
class Invoice extends Eloquent class Invoice extends Eloquent implements iEntity
{ {
protected $softDelete = true; protected $softDelete = true;
public function account()
{
return $this->belongsTo('Account');
}
public function client() public function client()
{ {
@ -19,6 +24,16 @@ class Invoice extends Eloquent
return $this->belongsTo('InvoiceStatus'); return $this->belongsTo('InvoiceStatus');
} }
public function getName()
{
return $this->invoice_number;
}
public function getEntityType()
{
return ENTITY_INVOICE;
}
public function getTotal() public function getTotal()
{ {
$total = 0; $total = 0;

View File

@ -1,6 +1,6 @@
<?php <?php
class Payment extends Eloquent class Payment extends Eloquent implements iEntity
{ {
protected $softDelete = true; protected $softDelete = true;
@ -8,6 +8,18 @@ class Payment extends Eloquent
{ {
return $this->belongsTo('Invoice'); return $this->belongsTo('Invoice');
} }
public function getName()
{
return '';
//return $this->invoice_number;
}
public function getEntityType()
{
return ENTITY_PAYMENT;
}
} }
Payment::created(function($payment) Payment::created(function($payment)

View File

@ -4,10 +4,11 @@ use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface; use Illuminate\Auth\Reminders\RemindableInterface;
use Zizaco\Confide\ConfideUser; use Zizaco\Confide\ConfideUser;
class User extends ConfideUser implements UserInterface, RemindableInterface { class User extends ConfideUser implements UserInterface, RemindableInterface, iPerson
{
protected $softDelete = true; protected $softDelete = true;
public static $rules = array( public static $rules = array(
/* /*
'username' => 'required|email|unique:users', 'username' => 'required|email|unique:users',
@ -31,12 +32,15 @@ class User extends ConfideUser implements UserInterface, RemindableInterface {
*/ */
protected $hidden = array('password'); protected $hidden = array('password');
public function account() public function account()
{ {
return $this->belongsTo('Account'); return $this->belongsTo('Account');
} }
public function getPersonType()
{
return PERSON_USER;
}
/** /**
* Get the unique identifier for the user. * Get the unique identifier for the user.
@ -74,7 +78,7 @@ class User extends ConfideUser implements UserInterface, RemindableInterface {
if ($fullName == ' ') if ($fullName == ' ')
{ {
return "Unknown"; return "Guest";
} }
else else
{ {

View File

@ -32,27 +32,38 @@ Route::filter('auth', function()
Route::group(array('before' => array('auth', 'csrf')), function() Route::group(array('before' => array('auth', 'csrf')), function()
{ {
Route::get('home', function() { return View::make('header'); });
Route::get('account/{section?}', 'AccountController@showSection'); Route::get('account/{section?}', 'AccountController@showSection');
Route::post('account/{section?}', 'AccountController@doSection'); Route::post('account/{section?}', 'AccountController@doSection');
Route::resource('clients', 'ClientController'); Route::resource('clients', 'ClientController');
Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable')); Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable'));
Route::get('api/activities/{client_id?}', array('as'=>'api.activities', 'uses'=>'ActivityController@getDatatable'));
Route::post('clients/bulk', 'ClientController@bulk'); Route::post('clients/bulk', 'ClientController@bulk');
Route::get('clients/{client_id}/archive', 'ClientController@archive');
Route::get('clients/{client_id}/delete', 'ClientController@delete');
Route::resource('invoices', 'InvoiceController'); Route::resource('invoices', 'InvoiceController');
Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable')); Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable'));
Route::get('invoices/create/{client_id}', 'InvoiceController@create'); Route::get('invoices/create/{client_id}', 'InvoiceController@create');
Route::post('invoices/bulk', 'InvoiceController@bulk'); Route::post('invoices/bulk', 'InvoiceController@bulk');
Route::get('invoices/{client_id}/archive', 'InvoiceController@archive');
Route::get('invoices/{client_id}/delete', 'InvoiceController@delete');
Route::get('payments', 'PaymentController@index'); Route::get('payments', 'PaymentController@index');
Route::get('api/payments/{client_id?}', array('as'=>'api.payments', 'uses'=>'PaymentController@getDatatable')); Route::get('api/payments/{client_id?}', array('as'=>'api.payments', 'uses'=>'PaymentController@getDatatable'));
Route::post('payments/bulk', 'PaymentController@bulk'); Route::post('payments/bulk', 'PaymentController@bulk');
Route::get('home', function() { return View::make('header'); });
Route::get('reports', function() { return View::make('header'); });
Route::get('payments/create', function() { return View::make('header'); }); Route::get('payments/create', function() { return View::make('header'); });
Route::get('payments/{client_id}/archive', 'PaymentController@archive');
Route::get('payments/{client_id}/delete', 'PaymentController@delete');
Route::get('api/activities/{client_id?}', array('as'=>'api.activities', 'uses'=>'ActivityController@getDatatable')); Route::get('credits', 'CreditController@index');
Route::get('api/credits/{client_id?}', array('as'=>'api.credits', 'uses'=>'CreditController@getDatatable'));
Route::get('credits/create', function() { return View::make('header'); });
Route::get('credits/{client_id}/archive', 'CreditController@archive');
Route::get('credits/{client_id}/delete', 'CreditController@delete');
Route::get('reports', function() { return View::make('header'); });
}); });
// Confide routes // Confide routes
@ -164,6 +175,7 @@ function trackViewed($name)
if ($object->url == $item->url) if ($object->url == $item->url)
{ {
array_splice($viewed, $i, 1); array_splice($viewed, $i, 1);
break;
} }
} }
@ -186,6 +198,10 @@ define("RECENTLY_VIEWED", "RECENTLY_VIEWED");
define("ENTITY_CLIENT", "client"); define("ENTITY_CLIENT", "client");
define("ENTITY_INVOICE", "invoice"); define("ENTITY_INVOICE", "invoice");
define("ENTITY_PAYMENT", "payment"); define("ENTITY_PAYMENT", "payment");
define("ENTITY_CREDIT", "credit");
define("PERSON_CONTACT", "contact");
define("PERSON_USER", "user");
define("ACCOUNT_DETAILS", "details"); define("ACCOUNT_DETAILS", "details");
define("ACCOUNT_SETTINGS", "settings"); define("ACCOUNT_SETTINGS", "settings");
@ -194,5 +210,18 @@ define("ACCOUNT_MAP", "import_map");
define("ACCOUNT_EXPORT", "export"); define("ACCOUNT_EXPORT", "export");
define("DEFAULT_INVOICE_NUMBER", "00001"); define("DEFAULT_INVOICE_NUMBER", "0001");
define("RECENTLY_VIEWED_LIMIT", 8); define("RECENTLY_VIEWED_LIMIT", 8);
interface iPerson
{
public function getFullName();
public function getPersonType();
}
interface iEntity
{
public function getName();
public function getEntityType();
}

View File

@ -0,0 +1,55 @@
<table class="table {{ $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

@ -39,6 +39,7 @@
{{ HTML::tab_link('#activity', 'Activity', true) }} {{ HTML::tab_link('#activity', 'Activity', true) }}
{{ HTML::tab_link('#invoices', 'Invoices') }} {{ HTML::tab_link('#invoices', 'Invoices') }}
{{ HTML::tab_link('#payments', 'Payments') }} {{ HTML::tab_link('#payments', 'Payments') }}
{{ HTML::tab_link('#credits', 'Credits') }}
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
@ -46,7 +47,7 @@
<div class="tab-pane active" id="activity"> <div class="tab-pane active" id="activity">
{{ Datatable::table() {{ Datatable::table()
->addColumn('Date', 'Message') ->addColumn('Date', 'Message', 'Balance')
->setUrl(url('api/activities/'. $client->id)) ->setUrl(url('api/activities/'. $client->id))
->setOptions('sPaginationType', 'bootstrap') ->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false) ->setOptions('bFilter', false)
@ -57,7 +58,7 @@
<div class="tab-pane" id="invoices"> <div class="tab-pane" id="invoices">
{{ Datatable::table() {{ Datatable::table()
->addColumn('Invoice Number', 'Amount', 'Date') ->addColumn('Invoice Number', 'Total', 'Amount Due', 'Invoice Date', 'Due Date', 'Status')
->setUrl(url('api/invoices/' . $client->id)) ->setUrl(url('api/invoices/' . $client->id))
->setOptions('sPaginationType', 'bootstrap') ->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false) ->setOptions('bFilter', false)
@ -66,7 +67,6 @@
</div> </div>
<div class="tab-pane" id="payments"> <div class="tab-pane" id="payments">
{{ Datatable::table() {{ Datatable::table()
->addColumn('Invoice Number', 'Amount', 'Date') ->addColumn('Invoice Number', 'Amount', 'Date')
->setUrl(url('api/payments/' . $client->id)) ->setUrl(url('api/payments/' . $client->id))
@ -75,6 +75,16 @@
->render() }} ->render() }}
</div> </div>
<div class="tab-pane" id="credits">
{{ Datatable::table()
->addColumn('Credit Number', 'Amount', 'Credit Date')
->setUrl(url('api/credits/' . $client->id))
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->render() }}
</div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">

View File

@ -1,4 +1,4 @@
<table class="table table-bordered {{ $class = str_random(8) }}"> <table class="table {{ $class = str_random(8) }}">
<colgroup> <colgroup>
@for ($i = 0; $i < count($columns); $i++) @for ($i = 0; $i < count($columns); $i++)
<col class="con{{ $i }}" /> <col class="con{{ $i }}" />

View File

@ -257,6 +257,7 @@
{{ HTML::menu_link('client') }} {{ HTML::menu_link('client') }}
{{ HTML::menu_link('invoice') }} {{ HTML::menu_link('invoice') }}
{{ HTML::menu_link('payment') }} {{ HTML::menu_link('payment') }}
{{ HTML::menu_link('credit') }}
{{-- HTML::nav_link('reports', 'Reports') --}} {{-- HTML::nav_link('reports', 'Reports') --}}
</ul> </ul>
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
@ -267,9 +268,7 @@
<li><a href="#">No items</a></li> <li><a href="#">No items</a></li>
@else @else
@foreach (Session::get(RECENTLY_VIEWED) as $link) @foreach (Session::get(RECENTLY_VIEWED) as $link)
@if (Request::url() != $link->url)
<li><a href="{{ $link->url }}">{{ $link->name }}</a></li> <li><a href="{{ $link->url }}">{{ $link->name }}</a></li>
@endif
@endforeach @endforeach
@endif @endif
</ul> </ul>

View File

@ -24,7 +24,7 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
{{ Former::select('client')->addOption('', '')->fromQuery($clients, 'name', 'id')->select($client ? $client->id : '') {{ Former::select('client')->addOption('', '')->fromQuery($clients, 'name', 'id')->select($client ? $client->id : '')
->help('<a data-toggle="modal" data-target="#myModal">Create new client</a>'); }} ->help('<a style="cursor:pointer" data-toggle="modal" data-target="#myModal">Create new client</a>'); }}
</div> </div>
<div class="col-md-5"> <div class="col-md-5">
{{ Former::text('invoice_number')->label('Invoice #') }} {{ Former::text('invoice_number')->label('Invoice #') }}
@ -83,19 +83,27 @@
</tr> </tr>
</tbody> </tbody>
<tfoot> <tfoot>
<tr data-bind="visible: subtotal() != total()"> <tr>
<td colspan="3" class="hide-border"/> <td class="hide-border"></td>
<td colspan="2"/>
<td colspan="2">Subtotal</td> <td colspan="2">Subtotal</td>
<td style="text-align: right"><span data-bind="text: subtotal"/></td> <td style="text-align: right"><span data-bind="text: subtotal"/></td>
</tr> </tr>
<tr>
<td class="hide-border"></td>
<td colspan="2" class="hide-border"/>
<td colspan="2">Paid to Date</td>
<td style="text-align: right"></td>
</tr>
<tr data-bind="visible: discount() > 0"> <tr data-bind="visible: discount() > 0">
<td colspan="3" class="hide-border"/> <td class="hide-border"></td>
<td colspan="2" class="hide-border"/>
<td colspan="2">Discount</td> <td colspan="2">Discount</td>
<td style="text-align: right"><span data-bind="text: discounted"/></td> <td style="text-align: right"><span data-bind="text: discounted"/></td>
</tr> </tr>
<tr> <tr>
<td class="hide-border"></td> <td class="hide-border"></td>
<td colspan="2"/> <td colspan="2" class="hide-border"/>
<td colspan="2"><b>Invoice Total</b></td> <td colspan="2"><b>Invoice Total</b></td>
<td style="text-align: right"><span data-bind="text: total"/></td> <td style="text-align: right"><span data-bind="text: total"/></td>
</tr> </tr>
@ -239,6 +247,17 @@
var invoice = { var invoice = {
invoice_number: $('#invoice_number').val(), invoice_number: $('#invoice_number').val(),
invoice_date: $('#invoice_date').val(), invoice_date: $('#invoice_date').val(),
account: {
name: "{{ $account->name }}",
address1: "{{ $account->address1 }}",
address2: "{{ $account->address2 }}",
city: "{{ $account->city }}",
state: "{{ $account->state }}",
postal_code: "{{ $account->postal_code }}",
country: {
name: "{{ $account->country->name }}"
}
},
client: { client: {
name: $('[name="client_combobox"]').val() name: $('[name="client_combobox"]').val()
}, },

View File

@ -15,8 +15,9 @@
, array('id'=>'archive'))->split(); }} , array('id'=>'archive'))->split(); }}
@if (in_array($entityType, [ENTITY_CLIENT, ENTITY_INVOICE]))
{{ Button::primary_link(URL::to($entityType . 's/create'), 'New ' . ucwords($entityType), array('class' => 'pull-right')) }} {{ Button::primary_link(URL::to($entityType . 's/create'), 'New ' . ucwords($entityType), array('class' => 'pull-right')) }}
@endif
{{ Datatable::table() {{ Datatable::table()
->addColumn($columns) ->addColumn($columns)
@ -30,10 +31,21 @@
<script type="text/javascript"> <script type="text/javascript">
function submitForm(action) { function submitForm(action) {
if (action == 'delete') {
if (!confirm('Are you sure')) {
return;
}
}
$('#action').val(action); $('#action').val(action);
$('form').submit(); $('form').submit();
} }
function deleteEntity(id) {
if (confirm("Are you sure?")) {
window.location = "{{ URL::to($entityType . 's') }}/" + id + "/delete";
}
}
</script> </script>
@stop @stop
@ -46,13 +58,22 @@
}); });
$('tbody tr').click(function(event) { $('tbody tr').click(function(event) {
if (event.target.type !== 'checkbox') { if (event.target.type !== 'checkbox' && event.target.type !== 'button' && event.target.tagName.toLowerCase() !== 'a') {
$checkbox = $(this).closest('tr').find(':checkbox'); $checkbox = $(this).closest('tr').find(':checkbox');
var checked = $checkbox.prop('checked'); var checked = $checkbox.prop('checked');
$checkbox.prop('checked', !checked); $checkbox.prop('checked', !checked);
setArchiveEnabled(); setArchiveEnabled();
} }
}); });
$('tbody tr').mouseover(function() {
$(this).closest('tr').find('.tr-action').show();
}).mouseout(function() {
$dropdown = $(this).closest('tr').find('.tr-action');
if (!$dropdown.hasClass('open')) {
$dropdown.hide();
}
});
} }
$('#archive > button').prop('disabled', true); $('#archive > button').prop('disabled', true);
@ -69,5 +90,7 @@
var checked = $('tbody :checkbox:checked').length > 0; var checked = $('tbody :checkbox:checked').length > 0;
$('#archive > button').prop('disabled', !checked); $('#archive > button').prop('disabled', !checked);
} }
@stop @stop

View File

@ -44,6 +44,7 @@
</button> </button>
<a class="navbar-brand" href="#">Invoice Ninja</a> <a class="navbar-brand" href="#">Invoice Ninja</a>
</div> </div>
<!--
<div class="navbar-collapse collapse"> <div class="navbar-collapse collapse">
{{ Form::open(array('url' => 'login', 'class' => 'navbar-form navbar-right')) }} {{ Form::open(array('url' => 'login', 'class' => 'navbar-form navbar-right')) }}
<div class="form-group"> <div class="form-group">
@ -54,6 +55,7 @@
</div> </div>
<button type="submit" class="btn btn-success">Sign in</button> <button type="submit" class="btn btn-success">Sign in</button>
{{ Form::close() }} {{ Form::close() }}
-->
</div><!--/.navbar-collapse --> </div><!--/.navbar-collapse -->
</div> </div>
</div> </div>

View File

@ -28,6 +28,7 @@ function generatePDF(invoice) {
doc.addImage(invoice.image, 'JPEG', 30, 30, invoice.imageWidth, invoice.imageHeight); doc.addImage(invoice.image, 'JPEG', 30, 30, invoice.imageWidth, invoice.imageHeight);
} }
/* table header */
doc.setDrawColor(200,200,200); doc.setDrawColor(200,200,200);
doc.setFillColor(230,230,230); doc.setFillColor(230,230,230);
doc.rect(headerLeft - 6, headerTop + rowHeight + 4, headerRight - headerLeft + 12, rowHeight + 2, 'FD'); doc.rect(headerLeft - 6, headerTop + rowHeight + 4, headerRight - headerLeft + 12, rowHeight + 2, 'FD');
@ -59,6 +60,7 @@ function generatePDF(invoice) {
doc.text(qtyX, tableTop, 'Quantity'); doc.text(qtyX, tableTop, 'Quantity');
doc.text(totalX, tableTop, 'Line Total'); doc.text(totalX, tableTop, 'Line Total');
/* line items */
doc.setFontType("normal"); doc.setFontType("normal");
var line = 1; var line = 1;
var total = 0; var total = 0;
@ -86,6 +88,7 @@ function generatePDF(invoice) {
line += doc.splitTextToSize(item.notes, 200).length; line += doc.splitTextToSize(item.notes, 200).length;
} }
/* table footer */
var x = tableTop + (line * rowHeight) + 14; var x = tableTop + (line * rowHeight) + 14;
doc.lines([[0,0],[headerRight-tableLeft+5,0]],tableLeft - 8, x); doc.lines([[0,0],[headerRight-tableLeft+5,0]],tableLeft - 8, x);
@ -100,6 +103,61 @@ function generatePDF(invoice) {
totalX = headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize()); totalX = headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize());
doc.text(totalX, headerTop + (2 * rowHeight), total); doc.text(totalX, headerTop + (2 * rowHeight), total);
/* payment stub */
var y = 680;
doc.lines([[0,0],[headerRight-tableLeft+5,0]],tableLeft - 8, y - 30);
doc.setFontSize(20);
doc.text(tableLeft, y, 'Payment Stub');
doc.setFontSize(10);
doc.setFontType("normal");
y += 40;
doc.text(tableLeft, y, invoice.account.name);
y += 16;
doc.text(tableLeft, y, invoice.account.address1);
if (invoice.account.address2) {
y += 16;
doc.text(tableLeft, y, invoice.account.address2);
}
y += 16;
doc.text(tableLeft, y, invoice.account.city + ', ' + invoice.account.state + ' ' + invoice.account.postal_code);
y += 16;
doc.text(tableLeft, y, invoice.account.country.name);
var clientX = headerRight - (doc.getStringUnitWidth(invoice.client.name) * doc.internal.getFontSize());
var numberX = headerRight - (doc.getStringUnitWidth(invoice.invoice_number) * doc.internal.getFontSize());
var dateX = headerRight - (doc.getStringUnitWidth(issuedOn) * doc.internal.getFontSize());
var totalX = headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize());
y = 720;
doc.setFontType("bold");
doc.text(headerLeft, y, 'Client');
doc.setFontType("normal");
doc.text(clientX, y, invoice.client.name);
y += 16;
doc.setFontType("bold");
doc.text(headerLeft, y, 'Invoice #');
doc.setFontType("normal");
doc.text(numberX, y, invoice.invoice_number);
y += 16;
doc.setFontType("bold");
doc.text(headerLeft, y, 'Invoice Date');
doc.setFontType("normal");
doc.text(dateX, y, issuedOn);
y += 16;
doc.setFontType("bold");
doc.text(headerLeft, y, 'Amount Due');
doc.setFontType("normal");
doc.text(totalX, y, total);
y += 16;
doc.setFontType("bold");
doc.text(headerLeft, y, 'Amount Enclosed');
return doc; return doc;
} }