bug fixes

This commit is contained in:
Hillel Coren 2014-01-07 23:59:06 +00:00
parent 21babe88a4
commit 2b56c8a299
17 changed files with 267 additions and 162 deletions

View File

@ -1,7 +1,7 @@
# Invoice Ninja # Invoice Ninja
## Simple, Intuitive Invoicing ## Simple, Intuitive Invoicing
### Live demo: [http://invoice-ninja.eu1.frbit.net](http://invoice-ninja.eu1.frbit.net) ### Live demo: [http://invoiceninja.eu1.frbit.net](http://invoiceninja.eu1.frbit.net)
### Introduction ### 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. 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.
@ -9,11 +9,13 @@ Most online invoicing sites are expensive. They shouldn't be. The aim of this pr
### Features ### Features
* Core application built using Laravel 4.1 * Core application built using Laravel 4.1
* Invoice PDF generation directly in the browser * Invoice PDF generation directly in the browser
* Tax rates and payment terms
* Integrates with many payment providers * Integrates with many payment providers
* Recurring invoices * Recurring invoices
### Remaining Work ### Remaining Work
* Home dashboard * Home dashboard
* Multiple language support
* Reports * Reports
### Steps to setup ### Steps to setup

View File

@ -10,13 +10,11 @@ class ActivityController extends \BaseController {
->where('activities.account_id', '=', Auth::user()->account_id) ->where('activities.account_id', '=', Auth::user()->account_id)
->select('activities.message', 'activities.created_at', 'activities.currency_id', 'activities.balance', 'activities.adjustment'); ->select('activities.message', 'activities.created_at', 'activities.currency_id', 'activities.balance', 'activities.adjustment');
return Datatable::query($query) return Datatable::query($query)
->addColumn('date', function($model) { return Utils::timestampToDateTimeString(strtotime($model->created_at)); }) ->addColumn('created_at', function($model) { return Utils::timestampToDateTimeString(strtotime($model->created_at)); })
->addColumn('message', function($model) { return $model->message; }) ->addColumn('message', function($model) { return $model->message; })
->addColumn('balance', function($model) { return Utils::formatMoney($model->balance, $model->currency_id); }) ->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) : ''; }) ->addColumn('adjustment', function($model) { return $model->adjustment != 0 ? Utils::formatMoney($model->adjustment, $model->currency_id) : ''; })
->orderColumns('date')
->make(); ->make();
} }

View File

@ -57,7 +57,6 @@ class ClientController extends \BaseController {
</ul> </ul>
</div>'; </div>';
}) })
->orderColumns('name','first_name','balance','last_login','created_at','email','phone')
->make(); ->make();
} }
@ -230,20 +229,9 @@ class ClientController extends \BaseController {
{ {
$action = Input::get('action'); $action = Input::get('action');
$ids = Input::get('id') ? Input::get('id') : Input::get('ids'); $ids = Input::get('id') ? Input::get('id') : Input::get('ids');
$clients = Client::scope($ids)->get(); $count = $this->clientRepo->bulk($ids, $action);
foreach ($clients as $client) $message = Utils::pluralize('Successfully '.$action.'d ? client', $count);
{
if ($action == 'delete')
{
$client->is_deleted = true;
$client->save();
}
$client->delete();
}
$message = Utils::pluralize('Successfully '.$action.'d ? client', count($clients));
Session::flash('message', $message); Session::flash('message', $message);
return Redirect::to('clients'); return Redirect::to('clients');

View File

@ -53,7 +53,6 @@ class CreditController extends \BaseController {
</ul> </ul>
</div>'; </div>';
}) })
->orderColumns('number')
->make(); ->make();
} }

View File

@ -73,7 +73,6 @@ class InvoiceController extends \BaseController {
</ul> </ul>
</div>'; </div>';
}) })
->orderColumns('invoice_number','client','total','balance','invoice_date','due_date','invoice_status_name')
->make(); ->make();
} }
@ -109,7 +108,6 @@ class InvoiceController extends \BaseController {
</ul> </ul>
</div>'; </div>';
}) })
->orderColumns('client','total','frequency','start_date','end_date')
->make(); ->make();
} }

View File

@ -52,7 +52,6 @@ class PaymentController extends \BaseController
</ul> </ul>
</div>'; </div>';
}) })
->orderColumns('transaction_reference', 'client_name', 'invoice_number', 'amount', 'payment_date')
->make(); ->make();
} }

View File

@ -88,7 +88,8 @@ class ConstantsSeeder extends Seeder
Industry::create(array('name' => 'Transportation')); Industry::create(array('name' => 'Transportation'));
Industry::create(array('name' => 'Travel & Luxury')); Industry::create(array('name' => 'Travel & Luxury'));
Size::create(array('name' => '1 - 10')); Size::create(array('name' => '1 = 3'));
Size::create(array('name' => '4 - 10'));
Size::create(array('name' => '11 - 50')); Size::create(array('name' => '11 - 50'));
Size::create(array('name' => '51 - 100')); Size::create(array('name' => '51 - 100'));
Size::create(array('name' => '101 - 500')); Size::create(array('name' => '101 - 500'));

View File

@ -57,14 +57,29 @@ class Activity extends Eloquent
$activity->save(); $activity->save();
} }
public static function updateClient($client)
{
if ($client->is_deleted && !$client->getOriginal('is_deleted'))
{
$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->save();
}
}
public static function archiveClient($client) public static function archiveClient($client)
{ {
$activity = Activity::getBlank(); if (!$client->is_deleted)
$activity->client_id = $client->id; {
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_CLIENT; $activity = Activity::getBlank();
$activity->message = Auth::user()->getFullName() . ' archived client ' . $client->name; $activity->client_id = $client->id;
$activity->balance = $client->balance; $activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_CLIENT;
$activity->save(); $activity->message = Auth::user()->getFullName() . ' archived client ' . link_to('clients/'.$client->public_id, $client->name);
$activity->balance = $client->balance;
$activity->save();
}
} }
public static function createInvoice($invoice) public static function createInvoice($invoice)
@ -92,13 +107,30 @@ class Activity extends Eloquent
public static function archiveInvoice($invoice) public static function archiveInvoice($invoice)
{ {
$activity = Activity::getBlank(); if ($invoice->invoice_status_id < INVOICE_STATUS_SENT)
$activity->invoice_id = $invoice->id; {
$activity->client_id = $invoice->client_id; return;
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_INVOICE; }
$activity->message = Auth::user()->getFullName() . ' archived invoice ' . $invoice->invoice_number;
$activity->balance = $invoice->client->balance; if (!$invoice->is_deleted)
$activity->save(); {
if ($invoice->balance > 0)
{
$client = $invoice->client;
$client->balance = $client->balance - $invoice->balance;
$client->save();
}
$activity = Activity::getBlank();
$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->balance = $client->balance;
$activity->adjustment = $invoice->balance;
$activity->save();
}
} }
public static function emailInvoice($invitation) public static function emailInvoice($invitation)
@ -132,35 +164,56 @@ class Activity extends Eloquent
return; return;
} }
$diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount')); if ($invoice->is_deleted && !$invoice->getOriginal('is_deleted'))
if ($diff == 0)
{ {
return; if ($invoice->balance > 0)
{
$client = $invoice->client;
$client->balance = $client->balance - $invoice->balance;
$client->save();
}
$activity = Activity::getBlank();
$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->balance = $client->balance;
$activity->adjustment = $invoice->balance * -1;
$activity->save();
} }
else
{
$diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount'));
$backupInvoice = Invoice::with('invoice_items', 'client.account', 'client.contacts')->find($invoice->id); if ($diff == 0)
//dd($backupInvoice->hidePrivateFields()->toJSON()); {
return;
}
$client = $invoice->client; $backupInvoice = Invoice::with('invoice_items', 'client.account', 'client.contacts')->find($invoice->id);
$client->balance = $client->balance + $diff;
$client->save();
$activity = Activity::getBlank($invoice); $client = $invoice->client;
$activity->client_id = $invoice->client_id; $client->balance = $client->balance + $diff;
$activity->invoice_id = $invoice->id; $client->save();
$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 = Activity::getBlank($invoice);
$activity->balance = $client->balance; $activity->client_id = $invoice->client_id;
$activity->adjustment = $diff; $activity->invoice_id = $invoice->id;
$activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON(); $activity->activity_type_id = ACTIVITY_TYPE_UPDATE_INVOICE;
$activity->save(); $activity->message = Auth::user()->getFullName() . ' updated invoice ' . link_to('invoices/'.$invoice->public_id, $invoice->invoice_number);
$activity->balance = $client->balance;
$activity->adjustment = $diff;
$activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON();
$activity->save();
}
} }
public static function createPayment($payment) public static function createPayment($payment)
{ {
$client = $payment->client; $client = $payment->client;
$client->balance = $client->balance - $payment->amount; $client->balance = $client->balance - $payment->amount;
$client->paid_to_date = $client->paid_to_date + $payment->amount;
$client->save(); $client->save();
if (Auth::check()) if (Auth::check())

View File

@ -168,3 +168,13 @@ Client::created(function($client)
{ {
Activity::createClient($client); Activity::createClient($client);
}); });
Client::updating(function($client)
{
Activity::updateClient($client);
});
Client::deleting(function($client)
{
Activity::archiveClient($client);
});

View File

@ -16,12 +16,18 @@ class ContactMailer extends Mailer {
foreach ($invoice->invitations as $invitation) foreach ($invoice->invitations as $invitation)
{ {
if (!$invitation->user->email)
{
return false;
}
$invitation->sent_date = \Carbon::now()->toDateTimeString(); $invitation->sent_date = \Carbon::now()->toDateTimeString();
$invitation->save(); $invitation->save();
$data = array('link' => URL::to('view') . '/' . $invitation->invitation_key); $data = array('link' => URL::to('view') . '/' . $invitation->invitation_key);
$this->sendTo($invitation->contact->email, $invitation->user->email, $subject, $view, $data); $this->sendTo($invitation->contact->email, $invitation->user->email, $subject, $view, $data);
//$this->sendTo($invitation->contact->email, $subject, $view, $data);
Activity::emailInvoice($invitation); Activity::emailInvoice($invitation);
} }

View File

@ -7,9 +7,10 @@ abstract class Mailer {
public function sendTo($toEmail, $fromEmail, $subject, $view, $data = []) public function sendTo($toEmail, $fromEmail, $subject, $view, $data = [])
{ {
$views = [ $views = [
'html' => 'emails.'.$view.'_html', 'emails.'.$view.'_html',
'text' => 'emails.'.$view.'_text' 'emails.'.$view.'_text'
]; ];
\Log::info('data: ' . json_encode($data));
Mail::queue($views, $data, function($message) use ($toEmail, $fromEmail, $subject) Mail::queue($views, $data, function($message) use ($toEmail, $fromEmail, $subject)
{ {

View File

@ -15,7 +15,7 @@ class UserMailer extends Mailer {
$view = 'invoice'; $view = 'invoice';
//$data = array('link' => URL::to('view') . '/' . $invoice->invoice_key); //$data = array('link' => URL::to('view') . '/' . $invoice->invoice_key);
$data = []; $data = ['link' => ''];
$subject = 'Notification - Invoice ' . $type; $subject = 'Notification - Invoice ' . $type;
$this->sendTo($user->email, CONTACT_EMAIL, $subject, $view, $data); $this->sendTo($user->email, CONTACT_EMAIL, $subject, $view, $data);

View File

@ -98,4 +98,22 @@ class ClientRepository
return $client; return $client;
} }
public function bulk($ids, $action)
{
$clients = Client::scope($ids)->get();
foreach ($clients as $client)
{
if ($action == 'delete')
{
$client->is_deleted = true;
$client->save();
}
$client->delete();
}
return count($clients);
}
} }

View File

@ -133,29 +133,29 @@ HTML::macro('image_data', function($imagePath) {
define('CONTACT_EMAIL', 'contact@invoiceninja.com'); define('CONTACT_EMAIL', 'contact@invoiceninja.com');
define("ENV_DEVELOPMENT", "local"); define('ENV_DEVELOPMENT', 'local');
define("ENV_STAGING", "staging"); define('ENV_STAGING', 'staging');
define("ENV_PRODUCTION", "production"); define('ENV_PRODUCTION', 'production');
define("RECENTLY_VIEWED", "RECENTLY_VIEWED"); define('RECENTLY_VIEWED', 'RECENTLY_VIEWED');
define("ENTITY_CLIENT", "client"); define('ENTITY_CLIENT', 'client');
define("ENTITY_INVOICE", "invoice"); define('ENTITY_INVOICE', 'invoice');
define("ENTITY_RECURRING_INVOICE", "recurring_invoice"); define('ENTITY_RECURRING_INVOICE', 'recurring_invoice');
define("ENTITY_PAYMENT", "payment"); define('ENTITY_PAYMENT', 'payment');
define("ENTITY_CREDIT", "credit"); define('ENTITY_CREDIT', 'credit');
define("PERSON_CONTACT", "contact"); define('PERSON_CONTACT', 'contact');
define("PERSON_USER", "user"); define('PERSON_USER', 'user');
define("ACCOUNT_DETAILS", "details"); define('ACCOUNT_DETAILS', 'details');
define("ACCOUNT_SETTINGS", "settings"); define('ACCOUNT_SETTINGS', 'settings');
define("ACCOUNT_IMPORT", "import"); define('ACCOUNT_IMPORT', 'import');
define("ACCOUNT_MAP", "import_map"); define('ACCOUNT_MAP', 'import_map');
define("ACCOUNT_EXPORT", "export"); define('ACCOUNT_EXPORT', 'export');
define("DEFAULT_INVOICE_NUMBER", "0001"); define('DEFAULT_INVOICE_NUMBER', '0001');
define("RECENTLY_VIEWED_LIMIT", 8); define('RECENTLY_VIEWED_LIMIT', 8);
define("LOGGED_ERROR_LIMIT", 100); define('LOGGED_ERROR_LIMIT', 100);
define('INVOICE_STATUS_DRAFT', 1); define('INVOICE_STATUS_DRAFT', 1);
define('INVOICE_STATUS_SENT', 2); define('INVOICE_STATUS_SENT', 2);

View File

@ -170,7 +170,7 @@
<td class="hide-border" colspan="3"/> <td class="hide-border" colspan="3"/>
<td class="hide-border" data-bind="visible: $root.invoice_item_taxes.show"/> <td class="hide-border" data-bind="visible: $root.invoice_item_taxes.show"/>
<td colspan="2">Paid to Date</td> <td colspan="2">Paid to Date</td>
<td style="text-align: right"></td> <td style="text-align: right" data-bind="text: totals.paidToDate"></td>
</tr> </tr>
<tr> <tr>
<td class="hide-border" colspan="3"/> <td class="hide-border" colspan="3"/>
@ -634,6 +634,17 @@
self.loadClient = function(client) { self.loadClient = function(client) {
ko.mapping.fromJS(client, model.invoice().client().mapping, model.invoice().client); ko.mapping.fromJS(client, model.invoice().client().mapping, model.invoice().client);
self.setDueDate();
}
self.setDueDate = function() {
var paymentTerms = parseInt(self.invoice().client().payment_terms());
if (paymentTerms && !self.invoice().due_date())
{
var dueDate = $('#invoice_date').datepicker('getDate');
dueDate.setDate(dueDate.getDate() + paymentTerms);
self.invoice().due_date(dueDate);
}
} }
self.invoice_taxes = ko.observable({{ Auth::user()->account->invoice_taxes ? 'true' : 'false' }}); self.invoice_taxes = ko.observable({{ Auth::user()->account->invoice_taxes ? 'true' : 'false' }});
@ -773,6 +784,8 @@
self.invoice().client().public_id(-1); self.invoice().client().public_id(-1);
} }
model.setDueDate();
if (name) { if (name) {
// //
} else if (firstName || lastName) { } else if (firstName || lastName) {
@ -857,7 +870,8 @@
self.is_recurring = ko.observable(false); self.is_recurring = ko.observable(false);
self.invoice_status_id = ko.observable(0); self.invoice_status_id = ko.observable(0);
self.invoice_items = ko.observableArray(); self.invoice_items = ko.observableArray();
self.amount = ko.observable(0);
self.balance = ko.observable(0);
self.mapping = { self.mapping = {
'client': { 'client': {
@ -982,6 +996,14 @@
} }
}); });
this.totals.rawPaidToDate = ko.computed(function() {
return self.amount() - self.balance();
});
this.totals.paidToDate = ko.computed(function() {
var total = self.totals.rawPaidToDate();
return total > 0 ? formatMoney(total, self.currency_id()) : '';
});
this.totals.total = ko.computed(function() { this.totals.total = ko.computed(function() {
var total = self.totals.rawSubtotal(); var total = self.totals.rawSubtotal();
@ -996,7 +1018,12 @@
total = parseFloat(total) + (total * (taxRate/100)); total = parseFloat(total) + (total * (taxRate/100));
} }
return total > 0 ? formatMoney(total, self.currency_id()) : ''; var paid = self.totals.rawPaidToDate();
if (paid > 0) {
total -= paid;
}
return total != 0 ? formatMoney(total, self.currency_id()) : '';
}); });
self.onDragged = function(item) { self.onDragged = function(item) {

148
composer.lock generated
View File

@ -211,12 +211,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git", "url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "22f1751267e7a2714f0df74fe207623cc928c68b" "reference": "d1ec609e371dc081562b106c36a77357641fefa3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/22f1751267e7a2714f0df74fe207623cc928c68b", "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/d1ec609e371dc081562b106c36a77357641fefa3",
"reference": "22f1751267e7a2714f0df74fe207623cc928c68b", "reference": "d1ec609e371dc081562b106c36a77357641fefa3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -248,7 +248,7 @@
"profiler", "profiler",
"webprofiler" "webprofiler"
], ],
"time": "2014-01-05 20:29:11" "time": "2014-01-07 10:13:21"
}, },
{ {
"name": "chumper/datatable", "name": "chumper/datatable",
@ -915,12 +915,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "c472ca9b043c373230ded1363dd05d1478effca4" "reference": "a49d68a0c048718d442855f52c4c68b97d76fd89"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/c472ca9b043c373230ded1363dd05d1478effca4", "url": "https://api.github.com/repos/laravel/framework/zipball/a49d68a0c048718d442855f52c4c68b97d76fd89",
"reference": "c472ca9b043c373230ded1363dd05d1478effca4", "reference": "a49d68a0c048718d442855f52c4c68b97d76fd89",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1024,7 +1024,7 @@
"framework", "framework",
"laravel" "laravel"
], ],
"time": "2014-01-06 02:22:05" "time": "2014-01-07 02:54:25"
}, },
{ {
"name": "laravelbook/ardent", "name": "laravelbook/ardent",
@ -1087,16 +1087,16 @@
}, },
{ {
"name": "maximebf/debugbar", "name": "maximebf/debugbar",
"version": "1.8", "version": "1.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/maximebf/php-debugbar.git", "url": "https://github.com/maximebf/php-debugbar.git",
"reference": "f1dd126ec13ad912a9c3a1b9b4d27e16da182d38" "reference": "ec6a857a308373fb61449e74a5aaf06af5f2ce87"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/f1dd126ec13ad912a9c3a1b9b4d27e16da182d38", "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/ec6a857a308373fb61449e74a5aaf06af5f2ce87",
"reference": "f1dd126ec13ad912a9c3a1b9b4d27e16da182d38", "reference": "ec6a857a308373fb61449e74a5aaf06af5f2ce87",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1133,7 +1133,7 @@
"keywords": [ "keywords": [
"debug" "debug"
], ],
"time": "2013-12-19 22:23:19" "time": "2014-01-07 20:49:48"
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
@ -1204,16 +1204,16 @@
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "1.7.0", "version": "1.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/briannesbitt/Carbon.git", "url": "https://github.com/briannesbitt/Carbon.git",
"reference": "03ede52a1f360441b5826cb8a798e0d0a919731f" "reference": "21c4cb4301969c7d85aee8a62eefdfa881413af0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/03ede52a1f360441b5826cb8a798e0d0a919731f", "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/21c4cb4301969c7d85aee8a62eefdfa881413af0",
"reference": "03ede52a1f360441b5826cb8a798e0d0a919731f", "reference": "21c4cb4301969c7d85aee8a62eefdfa881413af0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1246,7 +1246,7 @@
"datetime", "datetime",
"time" "time"
], ],
"time": "2013-12-05 04:13:29" "time": "2014-01-07 05:10:44"
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
@ -2943,12 +2943,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/patricktalmadge/bootstrapper.git", "url": "https://github.com/patricktalmadge/bootstrapper.git",
"reference": "d606a1c5b8b059ccc64b1c75fa45bad6b90008d5" "reference": "85c8e3ec29d0f98554d85b73d1e454b6600c0432"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/patricktalmadge/bootstrapper/zipball/d606a1c5b8b059ccc64b1c75fa45bad6b90008d5", "url": "https://api.github.com/repos/patricktalmadge/bootstrapper/zipball/85c8e3ec29d0f98554d85b73d1e454b6600c0432",
"reference": "d606a1c5b8b059ccc64b1c75fa45bad6b90008d5", "reference": "85c8e3ec29d0f98554d85b73d1e454b6600c0432",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2990,7 +2990,7 @@
"bootstrap", "bootstrap",
"laravel" "laravel"
], ],
"time": "2014-01-04 17:50:59" "time": "2014-01-07 16:02:34"
}, },
{ {
"name": "phpseclib/phpseclib", "name": "phpseclib/phpseclib",
@ -3282,12 +3282,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/BrowserKit.git", "url": "https://github.com/symfony/BrowserKit.git",
"reference": "0248b2dfc9cd6b259555d232eedfb1283eb496c3" "reference": "c6b3cd51651f445908a11f3f81f965a157daef38"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/BrowserKit/zipball/0248b2dfc9cd6b259555d232eedfb1283eb496c3", "url": "https://api.github.com/repos/symfony/BrowserKit/zipball/c6b3cd51651f445908a11f3f81f965a157daef38",
"reference": "0248b2dfc9cd6b259555d232eedfb1283eb496c3", "reference": "c6b3cd51651f445908a11f3f81f965a157daef38",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3328,7 +3328,7 @@
], ],
"description": "Symfony BrowserKit Component", "description": "Symfony BrowserKit Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2013-12-28 21:39:51" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
@ -3337,12 +3337,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/Console.git", "url": "https://github.com/symfony/Console.git",
"reference": "4c1ed2ff514bd85ee186eebb010ccbdeeab05af7" "reference": "86e13d5b06146fbe81006570ad26cb7cbeafba15"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/Console/zipball/4c1ed2ff514bd85ee186eebb010ccbdeeab05af7", "url": "https://api.github.com/repos/symfony/Console/zipball/86e13d5b06146fbe81006570ad26cb7cbeafba15",
"reference": "4c1ed2ff514bd85ee186eebb010ccbdeeab05af7", "reference": "86e13d5b06146fbe81006570ad26cb7cbeafba15",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3381,7 +3381,7 @@
], ],
"description": "Symfony Console Component", "description": "Symfony Console Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2014-01-01 08:14:50" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "symfony/css-selector", "name": "symfony/css-selector",
@ -3390,12 +3390,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/CssSelector.git", "url": "https://github.com/symfony/CssSelector.git",
"reference": "352552da1f50a79f6a6fa427e4a85ee2ea1945f6" "reference": "251273e7700b93a24012d4113ee5681a9000de5a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/CssSelector/zipball/352552da1f50a79f6a6fa427e4a85ee2ea1945f6", "url": "https://api.github.com/repos/symfony/CssSelector/zipball/251273e7700b93a24012d4113ee5681a9000de5a",
"reference": "352552da1f50a79f6a6fa427e4a85ee2ea1945f6", "reference": "251273e7700b93a24012d4113ee5681a9000de5a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3432,7 +3432,7 @@
], ],
"description": "Symfony CssSelector Component", "description": "Symfony CssSelector Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2014-01-01 08:14:50" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "symfony/debug", "name": "symfony/debug",
@ -3441,12 +3441,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/Debug.git", "url": "https://github.com/symfony/Debug.git",
"reference": "74110be5ec681a83fc5bd66dd5fd29fe85fe9c1f" "reference": "7bd04476b53d676189196ba4c526ccde4302a8de"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/Debug/zipball/74110be5ec681a83fc5bd66dd5fd29fe85fe9c1f", "url": "https://api.github.com/repos/symfony/Debug/zipball/7bd04476b53d676189196ba4c526ccde4302a8de",
"reference": "74110be5ec681a83fc5bd66dd5fd29fe85fe9c1f", "reference": "7bd04476b53d676189196ba4c526ccde4302a8de",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3487,7 +3487,7 @@
], ],
"description": "Symfony Debug Component", "description": "Symfony Debug Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2014-01-01 09:02:49" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "symfony/dom-crawler", "name": "symfony/dom-crawler",
@ -3496,12 +3496,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/DomCrawler.git", "url": "https://github.com/symfony/DomCrawler.git",
"reference": "58e85928ad277c67102a41a046160de86df44d55" "reference": "fa7d0ca404202d4330075ac90c6c22c546753d64"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/DomCrawler/zipball/58e85928ad277c67102a41a046160de86df44d55", "url": "https://api.github.com/repos/symfony/DomCrawler/zipball/fa7d0ca404202d4330075ac90c6c22c546753d64",
"reference": "58e85928ad277c67102a41a046160de86df44d55", "reference": "fa7d0ca404202d4330075ac90c6c22c546753d64",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3540,7 +3540,7 @@
], ],
"description": "Symfony DomCrawler Component", "description": "Symfony DomCrawler Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2013-12-29 20:33:52" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
@ -3549,12 +3549,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/EventDispatcher.git", "url": "https://github.com/symfony/EventDispatcher.git",
"reference": "6a30cf4f7951794e2179c29b3ce30fb478019cd8" "reference": "a37a9430e2eafb6a66de240ac13f91b45b4c3d37"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/6a30cf4f7951794e2179c29b3ce30fb478019cd8", "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/a37a9430e2eafb6a66de240ac13f91b45b4c3d37",
"reference": "6a30cf4f7951794e2179c29b3ce30fb478019cd8", "reference": "a37a9430e2eafb6a66de240ac13f91b45b4c3d37",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3596,7 +3596,7 @@
], ],
"description": "Symfony EventDispatcher Component", "description": "Symfony EventDispatcher Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2014-01-01 09:18:08" "time": "2014-01-07 13:29:57"
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
@ -3605,12 +3605,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/Filesystem.git", "url": "https://github.com/symfony/Filesystem.git",
"reference": "548000429823d067206bdfe73d4eb850c585e810" "reference": "e81f1b30eb9748c3f8e0de3a92ea210845cff0a9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/548000429823d067206bdfe73d4eb850c585e810", "url": "https://api.github.com/repos/symfony/Filesystem/zipball/e81f1b30eb9748c3f8e0de3a92ea210845cff0a9",
"reference": "548000429823d067206bdfe73d4eb850c585e810", "reference": "e81f1b30eb9748c3f8e0de3a92ea210845cff0a9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3643,7 +3643,7 @@
], ],
"description": "Symfony Filesystem Component", "description": "Symfony Filesystem Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2013-12-31 13:43:37" "time": "2014-01-07 13:29:57"
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
@ -3652,12 +3652,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/Finder.git", "url": "https://github.com/symfony/Finder.git",
"reference": "6904345cf2b3bbab1f6d6e4ce1724cb99df9f00a" "reference": "b6735d1fc16da13c4c7dddfe78366a4a098cf011"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/Finder/zipball/6904345cf2b3bbab1f6d6e4ce1724cb99df9f00a", "url": "https://api.github.com/repos/symfony/Finder/zipball/b6735d1fc16da13c4c7dddfe78366a4a098cf011",
"reference": "6904345cf2b3bbab1f6d6e4ce1724cb99df9f00a", "reference": "b6735d1fc16da13c4c7dddfe78366a4a098cf011",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3690,7 +3690,7 @@
], ],
"description": "Symfony Finder Component", "description": "Symfony Finder Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2014-01-01 08:14:50" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "symfony/http-foundation", "name": "symfony/http-foundation",
@ -3699,12 +3699,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/HttpFoundation.git", "url": "https://github.com/symfony/HttpFoundation.git",
"reference": "6c6b8a7bcd7e2cc920cd6acace563fdbf121d844" "reference": "25b49c494ea6aed2cfd8448ae3f8437d01e731eb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/6c6b8a7bcd7e2cc920cd6acace563fdbf121d844", "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/25b49c494ea6aed2cfd8448ae3f8437d01e731eb",
"reference": "6c6b8a7bcd7e2cc920cd6acace563fdbf121d844", "reference": "25b49c494ea6aed2cfd8448ae3f8437d01e731eb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3740,7 +3740,7 @@
], ],
"description": "Symfony HttpFoundation Component", "description": "Symfony HttpFoundation Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2014-01-05 02:10:50" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "symfony/http-kernel", "name": "symfony/http-kernel",
@ -3749,12 +3749,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/HttpKernel.git", "url": "https://github.com/symfony/HttpKernel.git",
"reference": "2f5c4d0c7f273c0575f46823674ce2c1d0a5b310" "reference": "eb1ed60a4a066238106721f67f664fd6382a99ea"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/HttpKernel/zipball/2f5c4d0c7f273c0575f46823674ce2c1d0a5b310", "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/eb1ed60a4a066238106721f67f664fd6382a99ea",
"reference": "2f5c4d0c7f273c0575f46823674ce2c1d0a5b310", "reference": "eb1ed60a4a066238106721f67f664fd6382a99ea",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3811,7 +3811,7 @@
], ],
"description": "Symfony HttpKernel Component", "description": "Symfony HttpKernel Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2014-01-05 10:33:23" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
@ -3820,12 +3820,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/Process.git", "url": "https://github.com/symfony/Process.git",
"reference": "58fdccb311e44f28866f976c2d7b3227e9f713db" "reference": "4f196b9d307d9e1a3d4372f1735c301c03d476c5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/Process/zipball/58fdccb311e44f28866f976c2d7b3227e9f713db", "url": "https://api.github.com/repos/symfony/Process/zipball/4f196b9d307d9e1a3d4372f1735c301c03d476c5",
"reference": "58fdccb311e44f28866f976c2d7b3227e9f713db", "reference": "4f196b9d307d9e1a3d4372f1735c301c03d476c5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3858,7 +3858,7 @@
], ],
"description": "Symfony Process Component", "description": "Symfony Process Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2014-01-05 02:10:50" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "symfony/routing", "name": "symfony/routing",
@ -3867,12 +3867,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/Routing.git", "url": "https://github.com/symfony/Routing.git",
"reference": "4abfb500aab8be458c9e3a227ea56b190584f78a" "reference": "e4ef317134f5628b5f0d3b0ac96d30ba1c8146cc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/Routing/zipball/4abfb500aab8be458c9e3a227ea56b190584f78a", "url": "https://api.github.com/repos/symfony/Routing/zipball/e4ef317134f5628b5f0d3b0ac96d30ba1c8146cc",
"reference": "4abfb500aab8be458c9e3a227ea56b190584f78a", "reference": "e4ef317134f5628b5f0d3b0ac96d30ba1c8146cc",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3924,7 +3924,7 @@
"uri", "uri",
"url" "url"
], ],
"time": "2014-01-05 02:10:50" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "symfony/translation", "name": "symfony/translation",
@ -3933,12 +3933,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/Translation.git", "url": "https://github.com/symfony/Translation.git",
"reference": "7f76dffd7eaf2c9a3a8f47649404c71440d18c8b" "reference": "d08c27077115e4bd3030a812e4083daa49254ca9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/Translation/zipball/7f76dffd7eaf2c9a3a8f47649404c71440d18c8b", "url": "https://api.github.com/repos/symfony/Translation/zipball/d08c27077115e4bd3030a812e4083daa49254ca9",
"reference": "7f76dffd7eaf2c9a3a8f47649404c71440d18c8b", "reference": "d08c27077115e4bd3030a812e4083daa49254ca9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3979,7 +3979,7 @@
], ],
"description": "Symfony Translation Component", "description": "Symfony Translation Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2013-12-31 13:43:26" "time": "2014-01-07 13:28:54"
}, },
{ {
"name": "webpatser/laravel-countries", "name": "webpatser/laravel-countries",

View File

@ -21,6 +21,7 @@ function generatePDF(invoice, checkMath) {
var rowHeight = 15; var rowHeight = 15;
var tableRowHeight = 20; var tableRowHeight = 20;
var footerLeft = 420; var footerLeft = 420;
var tablePadding = 6;
var tableTop = 240; var tableTop = 240;
var tableLeft = 60; var tableLeft = 60;
@ -60,7 +61,7 @@ function generatePDF(invoice, checkMath) {
/* table header */ /* table header */
doc.setDrawColor(200,200,200); doc.setDrawColor(200,200,200);
doc.setFillColor(230,230,230); doc.setFillColor(230,230,230);
var x1 = headerLeft - 6; var x1 = headerLeft - tablePadding;
var y1 = headerTop + rowHeight + 4; var y1 = headerTop + rowHeight + 4;
var x2 = headerRight - headerLeft + 11; var x2 = headerRight - headerLeft + 11;
var y2 = rowHeight + 1; var y2 = rowHeight + 1;
@ -150,7 +151,7 @@ function generatePDF(invoice, checkMath) {
doc.setDrawColor(200,200,200); doc.setDrawColor(200,200,200);
doc.setFillColor(230,230,230); doc.setFillColor(230,230,230);
doc.rect(tableLeft - 6, tableTop - 12, headerRight - tableLeft + 12, rowHeight + 2, 'FD'); doc.rect(tableLeft - tablePadding, tableTop - 12, headerRight - tableLeft + 12, rowHeight + 2, 'FD');
var costX = unitCostRight - (doc.getStringUnitWidth('Unit Cost') * doc.internal.getFontSize()); var costX = unitCostRight - (doc.getStringUnitWidth('Unit Cost') * doc.internal.getFontSize());
var qtyX = qtyRight - (doc.getStringUnitWidth('Quantity') * doc.internal.getFontSize()); var qtyX = qtyRight - (doc.getStringUnitWidth('Quantity') * doc.internal.getFontSize());
@ -227,7 +228,9 @@ function generatePDF(invoice, checkMath) {
line += doc.splitTextToSize(item.notes, 200).length; line += doc.splitTextToSize(item.notes, 200).length;
if (i < invoice.invoice_items.length - 2) { if (i < invoice.invoice_items.length - 2) {
doc.lines([[0,0],[headerRight-tableLeft+5,0]],tableLeft - 8, tableTop + (line * tableRowHeight) - 8); doc.setLineWidth(0.5);
doc.line(tableLeft - tablePadding, tableTop + (line * tableRowHeight) - 8,
lineTotalRight+tablePadding, tableTop + (line * tableRowHeight) - 8);
} }
} }
@ -235,8 +238,10 @@ function generatePDF(invoice, checkMath) {
/* table footer */ /* table footer */
doc.setDrawColor(200,200,200); doc.setDrawColor(200,200,200);
var x = tableTop + (line * tableRowHeight); var x = tableTop + (line * tableRowHeight);
doc.lines([[0,0],[headerRight-tableLeft+5,0]],tableLeft - 8, x);
doc.setLineWidth(1);
doc.line(tableLeft - tablePadding, x, lineTotalRight+tablePadding, x);
console.log('%s %s %s', lineTotalRight, tableLeft, (lineTotalRight-tableLeft));
doc.text(tableLeft, x+16, invoice.public_notes); doc.text(tableLeft, x+16, invoice.public_notes);
doc.text(tableLeft, x+16 + (doc.splitTextToSize(invoice.public_notes, 340).length * rowHeight) + (rowHeight/2), invoice.terms); doc.text(tableLeft, x+16 + (doc.splitTextToSize(invoice.public_notes, 340).length * rowHeight) + (rowHeight/2), invoice.terms);
@ -295,7 +300,7 @@ function generatePDF(invoice, checkMath) {
return doc; return doc;
} }
var total = formatMoney(invoice.balance, currencyId); var total = formatMoney(total - (invoice.amount - invoice.balance), currencyId);
var totalX = headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize()); var totalX = headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize());
doc.text(totalX, x, total); doc.text(totalX, x, total);