mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 05:02:36 +01:00
bug fixes
This commit is contained in:
parent
ef24ac2c36
commit
2b5f42e5ac
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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');
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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';
|
||||
|
@ -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 == ' ')
|
||||
|
@ -18,9 +18,4 @@ class Invitation extends EntityModel
|
||||
{
|
||||
return $this->belongsTo('User');
|
||||
}
|
||||
}
|
||||
|
||||
Invitation::created(function($invitation)
|
||||
{
|
||||
Activity::emailInvoice($invitation);
|
||||
});
|
||||
}
|
@ -95,4 +95,9 @@ class Invoice extends EntityModel
|
||||
Invoice::created(function($invoice)
|
||||
{
|
||||
Activity::createInvoice($invoice);
|
||||
});
|
||||
|
||||
Invoice::updating(function($invoice)
|
||||
{
|
||||
Activity::updateInvoice($invoice);
|
||||
});
|
@ -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;
|
||||
|
@ -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')
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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({
|
||||
|
@ -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,
|
||||
|
@ -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> </span>
|
||||
<span class="error-block" id="emailError" style="display:none;float:left">Please provide a valid email address.</span><span> </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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user