1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00

bug fixes

This commit is contained in:
Hillel Coren 2013-12-30 22:17:45 +02:00
parent ef24ac2c36
commit 2b5f42e5ac
24 changed files with 364 additions and 171 deletions

View File

@ -40,7 +40,8 @@ class SendRecurringInvoices extends Command {
$invoice->client_id = $recurInvoice->client_id;
$invoice->recurring_invoice_id = $recurInvoice->id;
$invoice->invoice_number = $recurInvoice->account->getNextInvoiceNumber();
$invoice->total = $recurInvoice->total;
$invoice->amount = $recurInvoice->amount;
$invoice->currency_id = $recurInvoice->currency_id;
$invoice->invoice_date = new DateTime();
$invoice->due_date = new DateTime();
$invoice->save();

View File

@ -4,12 +4,18 @@ class ActivityController extends \BaseController {
public function getDatatable($clientPublicId)
{
$clientId = Client::getPrivateId($clientPublicId);
$query = DB::table('activities')
->join('clients', 'clients.id', '=', 'activities.client_id')
->where('clients.public_id', '=', $clientPublicId)
->where('activities.account_id', '=', Auth::user()->account_id)
->select('activities.message', 'activities.created_at', 'activities.currency_id', 'activities.balance', 'activities.adjustment');
return Datatable::collection(Activity::scope()->where('client_id','=',$clientId)->get())
return Datatable::query($query)
->addColumn('date', function($model) { return Utils::timestampToDateTimeString(strtotime($model->created_at)); })
->addColumn('message', function($model) { return $model->message; })
->addColumn('balance', function($model) { return Utils::formatMoney($model->balance, $model->account->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) : ''; })
->orderColumns('date')
->make();
}

View File

@ -15,7 +15,7 @@ class ClientController extends \BaseController {
return View::make('list', array(
'entityType'=>ENTITY_CLIENT,
'title' => '- Clients',
'columns'=>['checkbox', 'Client', 'Contact', 'Date Created', 'Email', 'Phone', 'Last Login', 'Balance', 'Action']
'columns'=>['checkbox', 'Client', 'Contact', 'Email', 'Date Created', 'Phone', 'Last Login', 'Balance', 'Action']
));
}
@ -46,9 +46,9 @@ class ClientController extends \BaseController {
return Datatable::query($query)
->addColumn('checkbox', function($model) { return '<input type="checkbox" name="ids[]" value="' . $model->public_id . '">'; })
->addColumn('name', function($model) { return link_to('clients/' . $model->public_id, $model->name); })
->addColumn('first_name', function($model) { return $model->first_name . ' ' . $model->last_name; })
->addColumn('first_name', function($model) { return link_to('clients/' . $model->public_id, $model->first_name . ' ' . $model->last_name); })
->addColumn('email', function($model) { return link_to('clients/' . $model->public_id, $model->email); })
->addColumn('created_at', function($model) { return Utils::timestampToDateString(strtotime($model->created_at)); })
->addColumn('email', function($model) { return $model->email ? HTML::mailto($model->email, $model->email) : ''; })
->addColumn('work_phone', function($model) { return Utils::formatPhoneNumber($model->work_phone); })
->addColumn('last_login', function($model) { return Utils::timestampToDateString($model->last_login); })
->addColumn('balance', function($model) { return Utils::formatMoney($model->balance, $model->currency_id); })
@ -88,6 +88,7 @@ class ClientController extends \BaseController {
'title' => '- New Client',
'clientSizes' => ClientSize::orderBy('id')->get(),
'clientIndustries' => ClientIndustry::orderBy('name')->get(),
'currencies' => Currency::orderBy('name')->get(),
'countries' => Country::orderBy('name')->get());
return View::make('clients.edit', $data);
@ -117,7 +118,7 @@ class ClientController extends \BaseController {
$data = array(
'client' => $client,
'title' => '- ' . $client->name,
'hasRecurringInvoices' => Invoice::scope()->where('frequency_id', '>', '0')->whereClientId($client->id)->count() > 0
'hasRecurringInvoices' => Invoice::scope()->where('is_recurring', '=', true)->whereClientId($client->id)->count() > 0
);
return View::make('clients.show', $data);
@ -158,7 +159,7 @@ class ClientController extends \BaseController {
private function save($publicId = null)
{
$rules = array(
'name' => 'required'
'email' => 'required'
);
$validator = Validator::make(Input::all(), $rules);
@ -182,7 +183,7 @@ class ClientController extends \BaseController {
$client->state = trim(Input::get('state'));
$client->postal_code = trim(Input::get('postal_code'));
$client->country_id = Input::get('country_id') ? Input::get('country_id') : null;
$client->notes = trim(Input::get('notes'));
$client->private_notes = trim(Input::get('private_notes'));
$client->client_size_id = Input::get('client_size_id') ? Input::get('client_size_id') : null;
$client->client_industry_id = Input::get('client_industry_id') ? Input::get('client_industry_id') : null;
$client->currency_id = Input::get('currency_id') ? Input::get('currency_id') : null;

View File

@ -20,10 +20,12 @@ class CreditController extends \BaseController {
{
$query = DB::table('credits')
->join('clients', 'clients.id', '=','credits.client_id')
->join('contacts', 'contacts.client_id', '=', 'clients.id')
->where('clients.account_id', '=', Auth::user()->account_id)
->where('clients.deleted_at', '=', null)
->where('credits.deleted_at', '=', null)
->select('credits.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', 'credits.amount', 'credits.credit_date', 'credits.currency_id');
->where('contacts.is_primary', '=', true)
->select('credits.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', 'credits.amount', 'credits.credit_date', 'credits.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email');
if ($clientPublicId) {
$query->where('clients.public_id', '=', $clientPublicId);
@ -42,7 +44,7 @@ class CreditController extends \BaseController {
if (!$clientPublicId) {
$table->addColumn('checkbox', function($model) { return '<input type="checkbox" name="ids[]" value="' . $model->public_id . '">'; })
->addColumn('client_name', function($model) { return link_to('clients/' . $model->client_public_id, $model->client_name); });
->addColumn('client_name', function($model) { return link_to('clients/' . $model->client_public_id, Utils::getClientDisplayName($model)); });
}
return $table->addColumn('amount', function($model){ return Utils::formatMoney($model->amount, $model->currency_id); })
@ -68,19 +70,14 @@ class CreditController extends \BaseController {
public function create($clientPublicId = null)
{
$client = null;
if ($clientPublicId) {
$client = Client::scope($clientPublicId)->firstOrFail();
}
$data = array(
'client' => $client,
'clientPublicId' => $clientPublicId,
'credit' => null,
'method' => 'POST',
'url' => 'credits',
'title' => '- New Credit',
'currencies' => Currency::orderBy('name')->get(),
'clients' => Client::scope()->orderBy('name')->get());
'clients' => Client::scope()->with('contacts')->orderBy('name')->get());
return View::make('credits.edit', $data);
}
@ -95,7 +92,7 @@ class CreditController extends \BaseController {
'url' => 'credits/' . $publicId,
'title' => '- Edit Credit',
'currencies' => Currency::orderBy('name')->get(),
'clients' => Client::scope()->orderBy('name')->get());
'clients' => Client::scope()->with('contacts')->orderBy('name')->get());
return View::make('credit.edit', $data);
}

View File

@ -51,7 +51,7 @@ class InvoiceController extends \BaseController {
$table->addColumn('invoice_number', function($model) { return link_to('invoices/' . $model->public_id . '/edit', $model->invoice_number); });
if (!$clientPublicId) {
$table->addColumn('client', function($model) { return link_to('clients/' . $model->client_public_id, $model->client_name); });
$table->addColumn('client', function($model) { return link_to('clients/' . $model->client_public_id, Utils::getClientDisplayName($model)); });
}
return $table->addColumn('invoice_date', function($model) { return Utils::fromSqlDate($model->invoice_date); })
@ -89,7 +89,7 @@ class InvoiceController extends \BaseController {
$table->addColumn('frequency', function($model) { return link_to('invoices/' . $model->public_id, $model->frequency); });
if (!$clientPublicId) {
$table->addColumn('client', function($model) { return link_to('clients/' . $model->client_public_id, $model->client_name); });
$table->addColumn('client', function($model) { return link_to('clients/' . $model->client_public_id, Utils::getClientDisplayName($model)); });
}
return $table->addColumn('start_date', function($model) { return Utils::fromSqlDate($model->start_date); })
@ -220,7 +220,7 @@ class InvoiceController extends \BaseController {
$payment = Payment::createNew();
$payment->invitation_id = $invitation->id;
$payment->invoice_id = $invoice->id;
$payment->amount = $invoice->amount;
$payment->amount = $invoice->amount;
$payment->client_id = $invoice->client_id;
//$payment->contact_id = 0; // TODO_FIX
$payment->transaction_reference = $ref;
@ -384,11 +384,9 @@ class InvoiceController extends \BaseController {
return InvoiceController::bulk();
}
$input = json_decode(Input::get('data'));
$inputClient = $input->client;
$inputClient->name = trim($inputClient->name);
$input = json_decode(Input::get('data'));
if (!$inputClient->name)
if (!$input->client->contacts[0]->email)
{
return Redirect::to('invoices/create')
->withInput();
@ -521,7 +519,7 @@ class InvoiceController extends \BaseController {
$invoice = Invoice::with('invoice_items')->scope($publicId)->firstOrFail();
$clone = Invoice::createNew();
foreach (['client_id', 'discount', 'invoice_date', 'due_date', 'is_recurring', 'frequency_id', 'start_date', 'end_date', 'notes'] as $field)
foreach (['client_id', 'discount', 'invoice_date', 'due_date', 'is_recurring', 'frequency_id', 'start_date', 'end_date', 'terms', 'currency_id'] as $field)
{
$clone->$field = $invoice->$field;
}
@ -537,7 +535,7 @@ class InvoiceController extends \BaseController {
{
$cloneItem = InvoiceItem::createNew();
foreach (['product_id', 'product_key', 'notes', 'cost', 'qty'] as $field)
foreach (['product_id', 'product_key', 'notes', 'cost', 'qty', 'tax_name', 'tax_rate'] as $field)
{
$cloneItem->$field = $item->$field;
}

View File

@ -16,10 +16,12 @@ class PaymentController extends \BaseController
$query = DB::table('payments')
->join('clients', 'clients.id', '=','payments.client_id')
->leftJoin('invoices', 'invoices.id', '=','payments.invoice_id')
->join('contacts', 'contacts.client_id', '=', 'clients.id')
->where('payments.account_id', '=', Auth::user()->account_id)
->where('payments.deleted_at', '=', null)
->where('clients.deleted_at', '=', null)
->select('payments.public_id', 'payments.transaction_reference', 'clients.name as client_name', 'clients.public_id as client_public_id', 'payments.amount', 'payments.payment_date', 'invoices.public_id as invoice_public_id', 'invoices.invoice_number', 'payments.currency_id');
->where('contacts.is_primary', '=', true)
->select('payments.public_id', 'payments.transaction_reference', 'clients.name as client_name', 'clients.public_id as client_public_id', 'payments.amount', 'payments.payment_date', 'invoices.public_id as invoice_public_id', 'invoices.invoice_number', 'payments.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email');
if ($clientPublicId) {
$query->where('clients.public_id', '=', $clientPublicId);
@ -43,7 +45,7 @@ class PaymentController extends \BaseController
$table->addColumn('transaction_reference', function($model) { return $model->transaction_reference ? $model->transaction_reference : '<i>Manual entry</i>'; });
if (!$clientPublicId) {
$table->addColumn('client_name', function($model) { return link_to('clients/' . $model->client_public_id, $model->client_name); });
$table->addColumn('client_name', function($model) { return link_to('clients/' . $model->client_public_id, Utils::getClientDisplayName($model)); });
}
return $table->addColumn('invoice_number', function($model) { return $model->invoice_public_id ? link_to('invoices/' . $model->invoice_public_id . '/edit', $model->invoice_number) : ''; })
@ -70,21 +72,16 @@ class PaymentController extends \BaseController
public function create($clientPublicId = 0)
{
$client = null;
if ($clientPublicId) {
$client = Client::scope($clientPublicId)->firstOrFail();
}
$data = array(
'client' => $client,
'clientPublicId' => $clientPublicId,
'invoice' => null,
'invoices' => Invoice::with('client')->scope()->orderBy('invoice_number')->get(),
'invoices' => Invoice::scope()->with('client')->orderBy('invoice_number')->get(),
'payment' => null,
'method' => 'POST',
'url' => 'payments',
'title' => '- New Payment',
'currencies' => Currency::orderBy('name')->get(),
'clients' => Client::scope()->orderBy('name')->get());
'clients' => Client::scope()->with('contacts')->orderBy('name')->get());
return View::make('payments.edit', $data);
}
@ -95,13 +92,13 @@ class PaymentController extends \BaseController
$data = array(
'client' => null,
'invoice' => null,
'invoices' => Invoice::scope()->orderBy('invoice_number')->get(array('public_id','invoice_number')),
'invoices' => Invoice::scope()->with('client')->orderBy('invoice_number')->get(array('public_id','invoice_number')),
'payment' => $payment,
'method' => 'PUT',
'url' => 'payments/' . $publicId,
'title' => '- Edit Payment',
'currencies' => Currency::orderBy('name')->get(),
'clients' => Client::scope()->orderBy('name')->get());
'clients' => Client::scope()->with('contacts')->orderBy('name')->get());
return View::make('payments.edit', $data);
}

View File

@ -165,7 +165,7 @@ class ConfideSetupUsersTable extends Migration {
$t->boolean('confirmed')->default(false);
$t->integer('theme_id');
$t->boolean('notify_sent')->default(false);
$t->boolean('notify_sent')->default(true);
$t->boolean('notify_viewed')->default(false);
$t->boolean('notify_paid')->default(true);
@ -212,7 +212,7 @@ class ConfideSetupUsersTable extends Migration {
$t->string('postal_code');
$t->unsignedInteger('country_id')->nullable();
$t->string('work_phone');
$t->text('notes');
$t->text('private_notes');
$t->decimal('balance', 13, 4);
$t->decimal('paid_to_date', 13, 4);
$t->timestamp('last_login')->nullable();
@ -285,6 +285,7 @@ class ConfideSetupUsersTable extends Migration {
$t->date('invoice_date')->nullable();
$t->date('due_date')->nullable();
$t->text('terms');
$t->text('public_notes');
$t->boolean('is_deleted');
$t->boolean('is_recurring');
$t->unsignedInteger('frequency_id');

View File

@ -246,4 +246,20 @@ class Utils
return ucwords(str_replace('_', ' ', $entityType));
}
public static function getClientDisplayName($model)
{
if ($model->client_name)
{
return $model->client_name;
}
else if ($model->first_name || $model->last_name)
{
return $model->first_name . ' ' . $model->last_name;
}
else
{
return $model->email;
}
}
}

View File

@ -5,16 +5,17 @@ define("ACTIVITY_TYPE_CREATE_CLIENT", 1);
define("ACTIVITY_TYPE_ARCHIVE_CLIENT", 2);
define("ACTIVITY_TYPE_DELETE_CLIENT", 3);
define("ACTIVITY_TYPE_CREATE_INVOICE", 4);
define("ACTIVITY_TYPE_EMAIL_INVOICE", 5);
define("ACTIVITY_TYPE_VIEW_INVOICE", 6);
define("ACTIVITY_TYPE_ARCHIVE_INVOICE", 7);
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);
define("ACTIVITY_TYPE_UPDATE_INVOICE", 5);
define("ACTIVITY_TYPE_EMAIL_INVOICE", 6);
define("ACTIVITY_TYPE_VIEW_INVOICE", 7);
define("ACTIVITY_TYPE_ARCHIVE_INVOICE", 8);
define("ACTIVITY_TYPE_DELETE_INVOICE", 9);
define("ACTIVITY_TYPE_CREATE_PAYMENT", 10);
define("ACTIVITY_TYPE_ARCHIVE_PAYMENT", 11);
define("ACTIVITY_TYPE_DELETE_PAYMENT", 12);
define("ACTIVITY_TYPE_CREATE_CREDIT", 13);
define("ACTIVITY_TYPE_ARCHIVE_CREDIT", 14);
define("ACTIVITY_TYPE_DELETE_CREDIT", 15);
class Activity extends Eloquent
@ -55,7 +56,6 @@ class Activity extends Eloquent
$activity->client_id = $client->id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_CLIENT;
$activity->message = Auth::user()->getFullName() . ' created client ' . link_to('clients/'.$client->public_id, $client->name);
$activity->save();
}
@ -65,6 +65,7 @@ class Activity extends Eloquent
$activity->client_id = $client->id;
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_CLIENT;
$activity->message = Auth::user()->getFullName() . ' archived client ' . $client->name;
$activity->balance = $client->balance;
$activity->save();
}
@ -72,9 +73,12 @@ class Activity extends Eloquent
{
$userName = Auth::check() ? Auth::user()->getFullName() : '<i>System</i>';
if ($invoice->is_recurring) {
if ($invoice->is_recurring)
{
$message = $userName . ' created ' . link_to('invoices/'.$invoice->public_id, 'recuring invoice');
} else {
}
else
{
$message = $userName . ' created invoice ' . link_to('invoices/'.$invoice->public_id, $invoice->invoice_number);
}
@ -84,6 +88,7 @@ class Activity extends Eloquent
$activity->currency_id = $invoice->currency_id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_INVOICE;
$activity->message = $message;
$activity->balance = $invoice->client->balance;
$activity->save();
}
@ -94,11 +99,22 @@ class Activity extends Eloquent
$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 = $invoice->client->balance;
$activity->save();
}
public static function emailInvoice($invitation)
{
$adjustment = 0;
if (!$invitation->invoice->isSent())
{
$adjustment = $invitation->invoice->amount;
$client = $invitation->invoice->client;
$client->balance = $client->balance + $adjustment;
$client->save();
}
$userName = Auth::check() ? Auth::user()->getFullName() : '<i>System</i>';
$activity = Activity::getBlank($invitation);
$activity->client_id = $invitation->invoice->client_id;
@ -106,11 +122,45 @@ class Activity extends Eloquent
$activity->contact_id = $invitation->contact_id;
$activity->activity_type_id = ACTIVITY_TYPE_EMAIL_INVOICE;
$activity->message = $userName . ' emailed invoice ' . link_to('invoices/'.$invitation->invoice->public_id, $invitation->invoice->invoice_number) . ' to ' . $invitation->contact->getFullName();
$activity->balance = $invitation->invoice->client->balance;
$activity->adjustment = $adjustment;
$activity->save();
}
public static function updateInvoice($invoice)
{
if ($invoice->invoice_status_id < INVOICE_STATUS_SENT)
{
return;
}
$diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount'));
if ($diff == 0)
{
return;
}
$client = $invoice->client;
$client->balance = $client->balance + $diff;
$client->save();
$activity = Activity::getBlank($invoice);
$activity->client_id = $invoice->client_id;
$activity->invoice_id = $invoice->id;
$activity->activity_type_id = ACTIVITY_TYPE_UPDATE_INVOICE;
$activity->message = Auth::user()->getFullName() . ' updated invoice ' . link_to('invoices/'.$invoice->public_id, $invoice->invoice_number);
$activity->balance = $client->balance;
$activity->adjustment = $diff;
$activity->save();
}
public static function createPayment($payment)
{
$client = $payment->client;
$client->balance = $client->balance - $payment->amount;
$client->save();
if (Auth::check())
{
$activity = Activity::getBlank();
@ -130,23 +180,28 @@ class Activity extends Eloquent
$activity->client_id = $payment->client_id;
$activity->currency_id = $payment->currency_id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_PAYMENT;
$activity->balance = $client->balance;
$activity->adjustment = $payment->amount * -1;
$activity->save();
}
public static function createCredit($credit)
{
$client = $credit->client;
$client->balance = $client->balance - $credit->amount;
$client->save();
$activity = Activity::getBlank();
$activity->message = Auth::user()->getFullName() . ' created credit';
$activity->credit_id = $credit->id;
$activity->client_id = $credit->client_id;
$activity->currency_id = $credit->currency_id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_CREDIT;
$activity->balance = $client->balance;
$activity->adjustment = $credit->amount * -1;
$activity->save();
}
public static function archivePayment($payment)
{
$activity = Activity::getBlank();
@ -154,6 +209,7 @@ class Activity extends Eloquent
$activity->client_id = $invoice->client_id;
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_PAYMENT;
$activity->message = Auth::user()->getFullName() . ' archived payment';
$activity->balance = $payment->client->balance;
$activity->save();
}
@ -168,6 +224,7 @@ class Activity extends Eloquent
$activity->invoice_id = $invitation->invoice_id;
$activity->activity_type_id = ACTIVITY_TYPE_VIEW_INVOICE;
$activity->message = $invitation->contact->getFullName() . ' viewed invoice ' . link_to('invoices/'.$invitation->invoice->public_id, $invitation->invoice->invoice_number);
$activity->balance = $invitation->invoice->client->balance;
$activity->save();
}
}

View File

@ -2,7 +2,7 @@
class Client extends EntityModel
{
protected $hidden = array('id', 'account_id', 'created_at', 'updated_at', 'deleted_at', 'notes', 'last_login');
protected $hidden = array('id', 'account_id', 'created_at', 'updated_at', 'deleted_at', 'private_notes', 'last_login');
public static $fieldName = 'Client - Name';
public static $fieldPhone = 'Client - Phone';

View File

@ -35,6 +35,11 @@ class Contact extends EntityModel
public function getFullName()
{
if (!$this->first_name && !$this->last_name)
{
return $this->email;
}
$fullName = $this->first_name . ' ' . $this->last_name;
if ($fullName == ' ')

View File

@ -18,9 +18,4 @@ class Invitation extends EntityModel
{
return $this->belongsTo('User');
}
}
Invitation::created(function($invitation)
{
Activity::emailInvoice($invitation);
});
}

View File

@ -95,4 +95,9 @@ class Invoice extends EntityModel
Invoice::created(function($invoice)
{
Activity::createInvoice($invoice);
});
Invoice::updating(function($invoice)
{
Activity::updateInvoice($invoice);
});

View File

@ -5,6 +5,7 @@ use Contact;
use Invitation;
use URL;
use Auth;
use Activity;
class ContactMailer extends Mailer {
@ -20,8 +21,10 @@ class ContactMailer extends Mailer {
$invitation->save();
$this->sendTo($invitation->contact->email, $subject, $view, $data);
}
Activity::emailInvoice($invitation);
}
if (!$invoice->isSent())
{
$invoice->invoice_status_id = INVOICE_STATUS_SENT;

View File

@ -9,13 +9,14 @@ class AccountRepository
{
$clients = \DB::table('clients')
->where('clients.deleted_at', '=', null)
->whereRaw("clients.name <> ''")
->select(\DB::raw("'Clients' as type, clients.public_id, clients.name, '' as token"));
$contacts = \DB::table('clients')
->join('contacts', 'contacts.client_id', '=', 'clients.id')
->where('clients.deleted_at', '=', null)
->whereRaw("CONCAT(contacts.first_name, contacts.last_name) <> ''")
->select(\DB::raw("'Contacts' as type, clients.public_id, CONCAT(contacts.first_name, ' ', contacts.last_name, ': ', clients.name) as name, '' as token"));
->whereRaw("CONCAT(contacts.first_name, contacts.last_name, contacts.email) <> ''")
->select(\DB::raw("'Contacts' as type, clients.public_id, CONCAT(contacts.first_name, ' ', contacts.last_name, ' ', contacts.email) as name, '' as token"));
$invoices = \DB::table('clients')
->join('invoices', 'invoices.client_id', '=', 'clients.id')

View File

@ -27,7 +27,7 @@ class ClientRepository
$client->state = trim($data['state']);
$client->postal_code = trim($data['postal_code']);
$client->country_id = $data['country_id'] ? $data['country_id'] : null;
$client->notes = trim($data['notes']);
$client->private_notes = trim($data['private_notes']);
$client->client_size_id = $data['client_size_id'] ? $data['client_size_id'] : null;
$client->client_industry_id = $data['client_industry_id'] ? $data['client_industry_id'] : null;
$client->currency_id = $data['currency_id'] ? $data['currency_id'] : null;

View File

@ -13,11 +13,13 @@ class InvoiceRepository
$query = \DB::table('invoices')
->join('clients', 'clients.id', '=','invoices.client_id')
->join('invoice_statuses', 'invoice_statuses.id', '=', 'invoices.invoice_status_id')
->join('contacts', 'contacts.client_id', '=', 'clients.id')
->where('invoices.account_id', '=', $accountId)
->where('invoices.deleted_at', '=', null)
->where('clients.deleted_at', '=', null)
->where('invoices.is_recurring', '=', false)
->select('clients.public_id as client_public_id', 'invoice_number', 'clients.name as client_name', 'invoices.public_id', 'amount', 'invoices.balance', 'invoice_date', 'due_date', 'invoice_statuses.name as invoice_status_name', 'invoices.currency_id');
->where('invoices.is_recurring', '=', false)
->where('contacts.is_primary', '=', true)
->select('clients.public_id as client_public_id', 'invoice_number', 'clients.name as client_name', 'invoices.public_id', 'amount', 'invoices.balance', 'invoice_date', 'due_date', 'invoice_statuses.name as invoice_status_name', 'invoices.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email');
if ($clientPublicId)
{
@ -42,10 +44,12 @@ class InvoiceRepository
$query = \DB::table('invoices')
->join('clients', 'clients.id', '=','invoices.client_id')
->join('frequencies', 'frequencies.id', '=', 'invoices.frequency_id')
->join('contacts', 'contacts.client_id', '=', 'clients.id')
->where('invoices.account_id', '=', $accountId)
->where('invoices.deleted_at', '=', null)
->where('invoices.is_recurring', '=', true)
->select('clients.public_id as client_public_id', 'clients.name as client_name', 'invoices.public_id', 'amount', 'frequencies.name as frequency', 'start_date', 'end_date', 'invoices.currency_id');
->where('contacts.is_primary', '=', true)
->select('clients.public_id as client_public_id', 'clients.name as client_name', 'invoices.public_id', 'amount', 'frequencies.name as frequency', 'start_date', 'end_date', 'invoices.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email');
if ($clientPublicId)
{
@ -87,6 +91,7 @@ class InvoiceRepository
$invoice->start_date = Utils::toSqlDate($data['start_date']);
$invoice->end_date = Utils::toSqlDate($data['end_date']);
$invoice->terms = trim($data['terms']);
$invoice->public_notes = trim($data['public_notes']);
$invoice->po_number = trim($data['po_number']);
$invoice->currency_id = $data['currency_id'];
@ -108,6 +113,7 @@ class InvoiceRepository
}
$invoice->amount = $total;
$invoice->balance = $total;
$invoice->save();
foreach ($data['invoice_items'] as $item)

View File

@ -2,7 +2,7 @@
@section('onReady')
$('input#name').focus();
$('input#first_name').focus();
@stop
@section('content')
@ -10,8 +10,7 @@
<!--<h3>{{ $title }} Client</h3>-->
{{ Former::open($url)->addClass('col-md-10 col-md-offset-1 main_form')->method($method)->rules(array(
'name' => 'required',
'email' => 'email'
'email' => 'email|required'
)); }}
@if ($client)
@ -20,25 +19,6 @@
<div class="row">
<div class="col-md-6">
{{ Former::legend('Organization') }}
{{ Former::text('name') }}
{{ Former::text('website') }}
{{ Former::text('work_phone')->label('Phone') }}
{{ Former::legend('Address') }}
{{ Former::text('address1')->label('Street') }}
{{ Former::text('address2')->label('Apt/Floor') }}
{{ Former::text('city') }}
{{ Former::text('state') }}
{{ Former::text('postal_code') }}
{{ Former::select('country_id')->addOption('','')->label('Country')
->fromQuery($countries, 'name', 'id')->select($client ? $client->country_id : '') }}
</div>
<div class="col-md-6">
{{ Former::legend('Contacts') }}
@ -70,7 +50,28 @@
->fromQuery($clientSizes, 'name', 'id')->select($client ? $client->client_size_id : '') }}
{{ Former::select('client_industry_id')->addOption('','')->label('Industry')
->fromQuery($clientIndustries, 'name', 'id')->select($client ? $client->client_industry_id : '') }}
{{ Former::textarea('notes') }}
{{ Former::textarea('private_notes') }}
</div>
<div class="col-md-6">
{{ Former::legend('Organization') }}
{{ Former::text('name') }}
{{ Former::text('website') }}
{{ Former::text('work_phone')->label('Phone') }}
{{ Former::legend('Address') }}
{{ Former::text('address1')->label('Street') }}
{{ Former::text('address2')->label('Apt/Floor') }}
{{ Former::text('city') }}
{{ Former::text('state') }}
{{ Former::text('postal_code') }}
{{ Former::select('country_id')->addOption('','')->label('Country')
->fromQuery($countries, 'name', 'id')->select($client ? $client->country_id : '') }}
</div>
</div>

View File

@ -62,8 +62,8 @@
<div class="col-md-6">
<h3>Standing</h3>
<h3>$0.00 <small>Paid to Date USD</small></h3>
<h3>$0.00 <small>Balance USD</small></h3>
<h3>{{ Utils::formatMoney($client->paid_to_date, $client->currency_id); }} <small>Paid to Date USD</small></h3>
<h3>{{ Utils::formatMoney($client->balance, $client->currency_id); }} <small>Balance USD</small></h3>
</div>
</div>
@ -81,7 +81,7 @@
<div class="tab-pane active" id="activity">
{{ Datatable::table()
->addColumn('Date', 'Message', 'Balance')
->addColumn('Date', 'Message', 'Balance', 'Adjustment')
->setUrl(url('api/activities/'. $client->public_id))
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)

View File

@ -15,6 +15,8 @@
@if ($credit)
{{ Former::populate($credit) }}
@else
{{ Former::populateField('credit_date', date('Y-m-d')) }}
@endif
@ -27,11 +29,11 @@
{{ Former::legend('New Credit') }}
@endif
{{ Former::select('client')->fromQuery($clients, 'name', 'public_id')->select($client ? $client->public_id : '')->addOption('', '')->addGroupClass('client-select') }}
{{ Former::select('currency_id')->addOption('','')->label('Currency')
->fromQuery($currencies, 'name', 'id')->select(Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY)) }}
{{ Former::select('client')->addOption('', '')->addGroupClass('client-select') }}
{{ Former::text('amount') }}
{{ Former::text('credit_date')->data_date_format(DEFAULT_DATE_PICKER_FORMAT) }}
{{ Former::select('currency_id')->addOption('','')->label('Currency')
->fromQuery($currencies, 'name', 'id')->select(Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY)) }}
</div>
<div class="col-md-6">
@ -48,10 +50,20 @@
<script type="text/javascript">
var clients = {{ $clients }};
$(function() {
var $input = $('select#client');
for (var i=0; i<clients.length; i++) {
var client = clients[i];
$input.append(new Option(getClientDisplayName(client), client.public_id));
}
@if ($clientPublicId)
$('select#client').val({{ $clientPublicId }});
@endif
$input.combobox();
$('#currency_id').combobox();
$('#credit_date').datepicker({

View File

@ -9,7 +9,7 @@
@foreach($columns as $i => $c)
<th align="center" valign="middle" class="head{{ $i }}"
@if ($c == 'checkbox')
style="width:20px"
style="width:20px"
@endif
>
@if ($c == 'checkbox' && $hasCheckboxes = true)
@ -37,6 +37,7 @@
jQuery('.{{ $class }}').dataTable({
// Disable sorting on the first column
"aaSorting": [],
"bAutoWidth": false,
@if (isset($hasCheckboxes) && $hasCheckboxes)
"aoColumnDefs" : [ {
'bSortable' : false,

View File

@ -13,12 +13,13 @@
{{ Former::open($url)->method($method)->addClass('main_form')->rules(array(
'client' => 'required',
'email' => 'required',
'product_key' => 'max:14',
)); }}
<div class="row" style="min-height:195px" onkeypress="formEnterClick(event)">
<div class="col-md-5" id="col_1">
{{ Former::select('client')->addOption('', '')->fromQuery($clients, 'name', 'public_id')->data_bind("dropdown: client")
{{ Former::select('client')->addOption('', '')->data_bind("dropdown: client")
->addGroupClass('client_select closer-row') }}
<div class="form-group" style="margin-bottom: 8px">
@ -38,6 +39,7 @@
</div>
</div>
{{ Former::textarea('terms')->data_bind("value: wrapped_terms, valueUpdate: 'afterkeydown'") }}
{{ Former::textarea('public_notes')->data_bind("value: wrapped_notes, valueUpdate: 'afterkeydown'") }}
</div>
<div class="col-md-4" id="col_2">
@ -51,14 +53,15 @@
{{ Former::text('start_date')->data_bind("value: start_date, valueUpdate: 'afterkeydown'")->data_date_format(DEFAULT_DATE_PICKER_FORMAT) }}
{{ Former::text('end_date')->data_bind("value: end_date, valueUpdate: 'afterkeydown'")->data_date_format(DEFAULT_DATE_PICKER_FORMAT) }}
</div>
<div data-bind="visible: invoice_status_id() < CONSTS.INVOICE_STATUS_SENT">
{{ Former::checkbox('recurring')->text('Enable | <a href="#" rel="tooltip" data-toggle="tooltip" title="Recurring invoices are automatically sent. Use :MONTH, :QUARTER or :YEAR for dynamic dates. Basic math works as well. ie, :MONTH-1.">Learn more</a>')->data_bind("checked: is_recurring")
->inlineHelp($invoice && $invoice->last_sent_date ? 'Last invoice sent ' . Utils::timestampToDateString($invoice->last_sent_date) : '') }}
</div>
@if ($invoice && $invoice->recurring_invoice_id)
<div style="padding-top: 6px">
<div class="pull-right" style="padding-top: 6px">
Created by a {{ link_to('/invoices/'.$invoice->recurring_invoice_id, 'recurring invoice') }}
</div>
@else
<div data-bind="visible: invoice_status_id() < CONSTS.INVOICE_STATUS_SENT">
{{ Former::checkbox('recurring')->text('Enable | <a href="#" rel="tooltip" data-toggle="tooltip" title="Recurring invoices are automatically sent. Use :MONTH, :QUARTER or :YEAR for dynamic dates. Basic math works as well. ie, :MONTH-1.">Learn more</a>')->data_bind("checked: is_recurring")
->inlineHelp($invoice && $invoice->last_sent_date ? 'Last invoice sent ' . Utils::dateToString($invoice->last_sent_date) : '') }}
</div>
@endif
</div>
@ -131,16 +134,16 @@
<td colspan="2">Subtotal</td>
<td style="text-align: right"><span data-bind="text: subtotal"/></td>
</tr>
<tr>
<td class="hide-border" data-bind="attr: {colspan: tax_rates().length > 1 ? 4 : 3}"/>
<td colspan="2">Paid to Date</td>
<td style="text-align: right"></td>
</tr>
<tr data-bind="visible: discount() > 0">
<td class="hide-border" data-bind="attr: {colspan: tax_rates().length > 1 ? 4 : 3}"/>
<td colspan="2">Discount</td>
<td style="text-align: right"><span data-bind="text: discounted"/></td>
</tr>
<tr>
<td class="hide-border" data-bind="attr: {colspan: tax_rates().length > 1 ? 4 : 3}"/>
<td colspan="2">Paid to Date</td>
<td style="text-align: right"></td>
</tr>
<tr>
<td class="hide-border" data-bind="attr: {colspan: tax_rates().length > 1 ? 4 : 3}"/>
<td colspan="2"><b>Balance Due</b></td>
@ -200,23 +203,6 @@
<div style="background-color: #F6F6F6" class="row" data-bind="with: client" onkeypress="clientModalEnterClick(event)">
<div class="col-md-6" style="margin-left:0px;margin-right:0px" >
{{ Former::legend('Organization') }}
{{ Former::text('name')->data_bind("value: name, valueUpdate: 'afterkeydown'") }}
{{ Former::text('website')->data_bind("value: website, valueUpdate: 'afterkeydown'") }}
{{ Former::text('work_phone')->data_bind("value: work_phone, valueUpdate: 'afterkeydown'")->label('Phone') }}
{{ Former::legend('Address') }}
{{ Former::text('address1')->label('Street')->data_bind("value: address1, valueUpdate: 'afterkeydown'") }}
{{ Former::text('address2')->label('Apt/Floor')->data_bind("value: address2, valueUpdate: 'afterkeydown'") }}
{{ Former::text('city')->data_bind("value: city, valueUpdate: 'afterkeydown'") }}
{{ Former::text('state')->data_bind("value: state, valueUpdate: 'afterkeydown'") }}
{{ Former::text('postal_code')->data_bind("value: postal_code, valueUpdate: 'afterkeydown'") }}
{{ Former::select('country_id')->addOption('','')->label('Country')->addGroupClass('country_select')
->fromQuery($countries, 'name', 'id')->data_bind("dropdown: country_id") }}
</div>
<div class="col-md-6" style="margin-left:0px;margin-right:0px" >
{{ Former::legend('Contacts') }}
<div data-bind='template: { foreach: contacts,
@ -247,14 +233,33 @@
->fromQuery($clientSizes, 'name', 'id')->select($client ? $client->client_size_id : '') }}
{{ Former::select('client_industry_id')->addOption('','')->label('Industry')->data_bind('value: client_industry_id')
->fromQuery($clientIndustries, 'name', 'id')->select($client ? $client->client_industry_id : '') }}
{{ Former::textarea('notes') }}
{{ Former::textarea('private_notes')->data_bind('value: private_notes') }}
</div>
<div class="col-md-6" style="margin-left:0px;margin-right:0px" >
{{ Former::legend('Organization') }}
{{ Former::text('name')->data_bind("value: name, valueUpdate: 'afterkeydown'") }}
{{ Former::text('website')->data_bind("value: website, valueUpdate: 'afterkeydown'") }}
{{ Former::text('work_phone')->data_bind("value: work_phone, valueUpdate: 'afterkeydown'")->label('Phone') }}
{{ Former::legend('Address') }}
{{ Former::text('address1')->label('Street')->data_bind("value: address1, valueUpdate: 'afterkeydown'") }}
{{ Former::text('address2')->label('Apt/Floor')->data_bind("value: address2, valueUpdate: 'afterkeydown'") }}
{{ Former::text('city')->data_bind("value: city, valueUpdate: 'afterkeydown'") }}
{{ Former::text('state')->data_bind("value: state, valueUpdate: 'afterkeydown'") }}
{{ Former::text('postal_code')->data_bind("value: postal_code, valueUpdate: 'afterkeydown'") }}
{{ Former::select('country_id')->addOption('','')->label('Country')->addGroupClass('country_select')
->fromQuery($countries, 'name', 'id')->data_bind("dropdown: country_id") }}
</div>
</div>
</div>
<div class="modal-footer" style="margin-top: 0px">
<span class="error-block" id="nameError" style="display:none;float:left">Please provide a value for the name field.</span><span>&nbsp;</span>
<span class="error-block" id="emailError" style="display:none;float:left">Please provide a valid email address.</span><span>&nbsp;</span>
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" data-bind="click: clientFormComplete">Done</button>
</div>
@ -316,7 +321,7 @@
$(function() {
$('form').change(refreshPDF);
//$('form').change(refreshPDF);
$('#country_id').combobox();
$('[rel=tooltip]').tooltip();
@ -344,8 +349,12 @@
} else {
model.client.public_id(0); // TODO_FIX
}
refreshPDF();
}).trigger('change');
$('#terms, #public_notes, #invoice_number, #invoice_date, #due_date, #po_number, #discout, #currency_id').change(function() {
refreshPDF();
});
$('.country_select input.form-control').on('change', function(e) {
var countryId = parseInt($('input[name=country_id]').val(), 10);
@ -360,7 +369,7 @@
@endif
$('#clientModal').on('shown.bs.modal', function () {
$('#name').focus();
$('#first_name').focus();
}).on('hidden.bs.modal', function () {
if (model.clientBackup) {
model.loadClient(model.clientBackup);
@ -521,6 +530,7 @@
self.frequency_id = ko.observable('');
self.currency_id = ko.observable({{ Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY) }});
self.terms = ko.observable('');
self.public_notes = ko.observable('');
self.po_number = ko.observable('');
self.invoice_date = ko.observable('');
self.invoice_number = ko.observable('');
@ -548,12 +558,26 @@
self.wrapped_terms = ko.computed({
read: function() {
$('#terms').height(this.terms().split('\n').length * 36);
return this.terms();
},
write: function(value) {
value = wordWrapText(value, 250);
value = wordWrapText(value, 340);
self.terms(value);
$('#terms').height(value.split('\n').length * 22);
$('#terms').height(value.split('\n').length * 36);
},
owner: this
});
self.wrapped_notes = ko.computed({
read: function() {
$('#public_notes').height(this.public_notes().split('\n').length * 36);
return this.public_notes();
},
write: function(value) {
value = wordWrapText(value, 340);
self.public_notes(value);
$('#public_notes').height(value.split('\n').length * 36);
},
owner: this
});
@ -584,14 +608,17 @@
$('#clientModal #country_id').val('');
}
$('#nameError').css( "display", "none" );
$('#emailError').css( "display", "none" );
$('#clientModal').modal('show');
}
self.clientFormComplete = function() {
var email = $('#email').val();
var firstName = $('#first_name').val();
var lastName = $('#last_name').val();
var name = $('#name').val();
if (!name) {
if (!name) $('#nameError').css( "display", "inline" );
if (!email || !isValidEmailAddress(email)) {
$('#emailError').css( "display", "inline" );
return;
}
@ -599,10 +626,19 @@
if (self.client.public_id() == 0) {
self.client.public_id(-1);
}
if (name) {
//
} else if (firstName || lastName) {
name = firstName + ' ' + lastName;
} else {
name = email;
}
$('.client_select input.form-control').val(name);
$('.client_select .combobox-container').addClass('combobox-selected');
$('#nameError').css( "display", "none" );
$('#emailError').css( "display", "none" );
$('.client_select input.form-control').focus();
refreshPDF();
@ -673,7 +709,7 @@
self.public_id = ko.observable(0);
self.name = ko.observable('');
self.work_phone = ko.observable('');
self.notes = ko.observable('');
self.private_notes = ko.observable('');
self.address1 = ko.observable('');
self.address2 = ko.observable('');
self.city = ko.observable('');
@ -711,6 +747,16 @@
self.contacts.remove(this);
}
self.placeholderName = ko.computed(function() {
if (self.contacts().length == 0) return;
var contact = self.contacts()[0];
if (contact.first_name() || contact.last_name()) {
return contact.first_name() + ' ' + contact.last_name();
} else {
return '';
}
});
if (data) {
ko.mapping.fromJS(data, {}, this);
} else {
@ -905,6 +951,7 @@
var products = {{ $products }};
var clients = {{ $clients }};
var clientMap = {};
var $clientSelect = $('select#client');
for (var i=0; i<clients.length; i++) {
var client = clients[i];
@ -913,9 +960,9 @@
contact.send_invoice = contact.is_primary;
}
clientMap[client.public_id] = client;
$clientSelect.append(new Option(getClientDisplayName(client), client.public_id));
}
window.model = new InvoiceModel();
@foreach ($taxRates as $taxRate)
model.addTaxRate({{ $taxRate }});
@ -932,8 +979,9 @@
contact.send_invoice = invitationContactIds.indexOf(contact.public_id) >= 0;
}
@else
model.invoice_date('{{ date('Y-m-d') }}');
model.invoice_number('{{ $invoiceNumber }}');
model.terms(wordWrapText('{{ $account->invoice_terms }}', 250));
model.terms(wordWrapText('{{ $account->invoice_terms }}', 340));
@endif
model.addItem();
ko.applyBindings(model);

View File

@ -10,11 +10,14 @@
{{ Former::open($url)->addClass('col-md-10 col-md-offset-1 main_form')->method($method)->rules(array(
'client' => 'required',
'invoice' => 'required',
'amount' => 'required',
)); }}
@if ($payment)
{{-- Former::populate($payment) --}}
@else
{{ Former::populateField('payment_date', date('Y-m-d')) }}
@endif
@ -29,10 +32,10 @@
{{ Former::select('client')->addOption('', '')->addGroupClass('client-select') }}
{{ Former::select('invoice')->addOption('', '')->addGroupClass('invoice-select') }}
{{ Former::select('currency_id')->addOption('','')->label('Currency')
->fromQuery($currencies, 'name', 'id')->select(Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY)) }}
{{ Former::text('amount') }}
{{ Former::text('payment_date')->data_date_format(DEFAULT_DATE_PICKER_FORMAT) }}
{{ Former::select('currency_id')->addOption('','')->label('Currency')
->fromQuery($currencies, 'name', 'id')->select(Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY)) }}
</div>
<div class="col-md-6">
@ -53,7 +56,7 @@
var clients = {{ $clients }};
var clientMap = {};
var invoiceMap = {};
var invoicesForClientMap = {};
/*
function compareClient(a,b) {
@ -73,23 +76,29 @@
var invoice = invoices[i];
var client = invoice.client;
if (!invoiceMap.hasOwnProperty(client.public_id)) {
invoiceMap[client.public_id] = [];
if (!invoicesForClientMap.hasOwnProperty(client.public_id)) {
invoicesForClientMap[client.public_id] = [];
}
invoiceMap[client.public_id].push(invoice);
clientMap[invoice.public_id] = invoice.client;
invoicesForClientMap[client.public_id].push(invoice);
invoiceMap[invoice.public_id] = invoice;
//clientMap[invoice.public_id] = invoice.client;
}
for (var i=0; i<clients.length; i++) {
var client = clients[i];
clientMap[client.public_id] = client;
}
//clients.sort(compareClient);
$input.append(new Option('', ''));
for (var i=0; i<clients.length; i++) {
var client = clients[i];
$input.append(new Option(client.name, client.public_id));
$input.append(new Option(getClientDisplayName(client), client.public_id));
}
@if ($client)
$('select#client').val({{ $client->public_id }});
@if ($clientPublicId)
$('select#client').val({{ $clientPublicId }});
@endif
$input.combobox();
@ -97,7 +106,8 @@
console.log('client change');
var clientId = $('input[name=client]').val();
var invoiceId = $('input[name=invoice]').val();
if (clientMap.hasOwnProperty(invoiceId) && clientMap[invoiceId].public_id == clientId) {
var invoice = invoiceMap[invoiceId];
if (invoice && invoice.client.public_id == clientId) {
console.log('values the same:' + $('select#client').prop('selected'))
e.preventDefault();
return;
@ -106,10 +116,11 @@
$invoiceCombobox = $('select#invoice');
$invoiceCombobox.find('option').remove().end().combobox('refresh');
$invoiceCombobox.append(new Option('', ''));
var list = clientId ? (invoiceMap.hasOwnProperty(clientId) ? invoiceMap[clientId] : []) : invoices;
var list = clientId ? (invoicesForClientMap.hasOwnProperty(clientId) ? invoicesForClientMap[clientId] : []) : invoices;
for (var i=0; i<list.length; i++) {
var invoice = list[i];
$invoiceCombobox.append(new Option(invoice.invoice_number + ' - ' + invoice.client.name, invoice.public_id));
var client = clientMap[invoice.client.public_id];
$invoiceCombobox.append(new Option(invoice.invoice_number + ' - ' + getClientDisplayName(client), invoice.public_id));
}
$('select#invoice').combobox('refresh');
}).trigger('change');
@ -118,8 +129,9 @@
$clientCombobox = $('select#client');
var invoiceId = $('input[name=invoice]').val();
if (invoiceId) {
var client = clientMap[invoiceId];
setComboboxValue($('.client-select'), client.public_id, client.name);
var invoice = invoiceMap[invoiceId];
var client = clientMap[invoice.client.public_id];
setComboboxValue($('.client-select'), client.public_id, getClientDisplayName(client));
}
});
$input.combobox();

View File

@ -9,6 +9,7 @@ function generatePDF(invoice) {
var headerLeft = 360;
var headerRight = 540;
var rowHeight = 15;
var tableRowHeight = 20;
var footerLeft = 420;
var tableTop = 240;
@ -20,16 +21,15 @@ function generatePDF(invoice) {
var lineTotalRight = 540;
var hasTaxes = true;
var hasTaxes = false;
for (var i=0; i<invoice.invoice_items.length; i++)
{
var item = invoice.invoice_items[i];
if (item.tax_rate > 0) {
var item = invoice.invoice_items[i];
if (item.tax && item.tax.rate > 0) {
hasTaxes = true;
break;
}
}
}
if (hasTaxes)
{
descriptionLeft -= 20;
@ -66,7 +66,7 @@ function generatePDF(invoice) {
doc.setFontType("normal");
if (invoice.client) {
var y = headerTop;
doc.text(marginLeft, y, invoice.client.name);
doc.text(marginLeft, y, getClientDisplayName(invoice.client));
y += rowHeight;
doc.text(marginLeft, y, invoice.client.address1);
if (invoice.client.address2) {
@ -126,6 +126,7 @@ function generatePDF(invoice) {
var line = 1;
var total = 0;
var shownItem = false;
doc.setDrawColor(220,220,220);
for (var i=0; i<invoice.invoice_items.length; i++) {
var item = invoice.invoice_items[i];
@ -158,7 +159,8 @@ function generatePDF(invoice) {
var qtyX = qtyRight - (doc.getStringUnitWidth(qty) * doc.internal.getFontSize());
var taxX = taxRight - (doc.getStringUnitWidth(tax) * doc.internal.getFontSize());
var totalX = lineTotalRight - (doc.getStringUnitWidth(lineTotal) * doc.internal.getFontSize());
var x = tableTop + (line * rowHeight) + 6;
var x = tableTop + (line * tableRowHeight) + 6;
if (i==0) x -= 4;
doc.text(tableLeft, x, productKey);
doc.text(descriptionLeft, x, notes);
@ -171,14 +173,21 @@ function generatePDF(invoice) {
}
line += doc.splitTextToSize(item.notes, 200).length;
if (i < invoice.invoice_items.length - 2) {
doc.lines([[0,0],[headerRight-tableLeft+5,0]],tableLeft - 8, tableTop + (line * tableRowHeight) - 8);
}
}
/* table footer */
var x = tableTop + (line * rowHeight);
doc.setDrawColor(200,200,200);
var x = tableTop + (line * tableRowHeight);
doc.lines([[0,0],[headerRight-tableLeft+5,0]],tableLeft - 8, x);
doc.text(tableLeft, x+16, invoice.terms);
doc.text(tableLeft, x+16 + (doc.splitTextToSize(invoice.terms, 340).length * rowHeight), invoice.public_notes);
x += 16;
doc.text(footerLeft, x, 'Subtotal');
@ -205,7 +214,7 @@ function generatePDF(invoice) {
x += 16;
doc.setFontType("bold");
doc.text(footerLeft, x, 'Total');
doc.text(footerLeft, x, 'Balance Due');
var total = formatMoney(total, currencyId);
var totalX = headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize());
@ -652,13 +661,34 @@ function wordWrapText(value, width)
while (j++ < lines[i].length) {
if (lines[i].charAt(j) === " ") space = j;
}
lines[i + 1] = lines[i].substring(space + 1) + (lines[i + 1] || "");
lines[i + 1] = lines[i].substring(space + 1) + ' ' + (lines[i + 1] || "");
lines[i] = lines[i].substring(0, space);
}
return lines.slice(0, 6).join("\n");
var newValue = (lines.join("\n")).trim();
if (value == newValue) {
return newValue;
} else {
return wordWrapText(newValue, width);
}
}
function getClientDisplayName(client)
{
var contact = client.contacts[0];
if (client.name) {
return client.name;
} else if (contact.first_name || contact.last_name) {
return contact.first_name + ' ' + contact.last_name;
} else {
return contact.email;
}
}
var CONSTS = {};
CONSTS.INVOICE_STATUS_DRAFT = 1;
CONSTS.INVOICE_STATUS_SENT = 2;