1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-09-20 00:11:35 +02:00

Working on quotes

This commit is contained in:
Hillel Coren 2014-05-17 22:29:57 +03:00
parent a14e00d520
commit aa3a3f174f
9 changed files with 244 additions and 46 deletions

View File

@ -40,42 +40,12 @@ class InvoiceController extends \BaseController {
}
public function getDatatable($clientPublicId = null)
{
$query = $this->invoiceRepo->getInvoices(Auth::user()->account_id, $clientPublicId, Input::get('sSearch'));
$table = Datatable::query($query);
{
$accountId = Auth::user()->account_id;
$search = Input::get('sSearch');
if (!$clientPublicId) {
$table->addColumn('checkbox', function($model) { return '<input type="checkbox" name="ids[]" value="' . $model->public_id . '">'; });
}
$table->addColumn('invoice_number', function($model) { return link_to('invoices/' . $model->public_id . '/edit', $model->invoice_number); });
if (!$clientPublicId) {
$table->addColumn('client_name', 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); })
->addColumn('amount', function($model) { return Utils::formatMoney($model->amount, $model->currency_id); })
->addColumn('balance', function($model) { return Utils::formatMoney($model->balance, $model->currency_id); })
->addColumn('due_date', function($model) { return Utils::fromSqlDate($model->due_date); })
->addColumn('invoice_status_name', function($model) { return $model->invoice_status_name; })
->addColumn('dropdown', function($model)
{
return '<div class="btn-group tr-action" style="visibility:hidden;">
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
'.trans('texts.select').' <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="' . URL::to('invoices/'.$model->public_id.'/edit') . '">'.trans('texts.edit_invoice').'</a></li>
<li><a href="' . URL::to('payments/create/' . $model->client_public_id . '/' . $model->public_id ) . '">'.trans('texts.enter_payment').'</a></li>
<li class="divider"></li>
<li><a href="javascript:archiveEntity(' . $model->public_id . ')">'.trans('texts.archive_invoice').'</a></li>
<li><a href="javascript:deleteEntity(' . $model->public_id . ')">'.trans('texts.delete_invoice').'</a></li>
</ul>
</div>';
})
->make();
}
return $this->invoiceRepo->getDatatable($accountId, $clientPublicId, ENTITY_INVOICE, $search);
}
public function getRecurringDatatable($clientPublicId = null)
{
@ -236,6 +206,7 @@ class InvoiceController extends \BaseController {
private static function getViewModel()
{
return [
'entityType' => ENTITY_INVOICE,
'account' => Auth::user()->account,
'products' => Product::scope()->orderBy('id')->get(array('product_key','notes','cost','qty')),
'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(),

View File

@ -0,0 +1,94 @@
<?php
use ninja\mailers\ContactMailer as Mailer;
use ninja\repositories\InvoiceRepository;
use ninja\repositories\ClientRepository;
use ninja\repositories\TaxRateRepository;
class QuoteController extends \BaseController {
protected $mailer;
protected $invoiceRepo;
protected $clientRepo;
protected $taxRateRepo;
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, TaxRateRepository $taxRateRepo)
{
parent::__construct();
$this->mailer = $mailer;
$this->invoiceRepo = $invoiceRepo;
$this->clientRepo = $clientRepo;
$this->taxRateRepo = $taxRateRepo;
}
public function index()
{
$data = [
'title' => '- Quotes',
'entityType'=>ENTITY_QUOTE,
'columns'=>Utils::trans(['checkbox', 'quote_number', 'client', 'quote_date', 'quote_total', 'due_date', 'status', 'action'])
];
if (Invoice::scope()->where('is_recurring', '=', true)->count() > 0)
{
$data['secEntityType'] = ENTITY_RECURRING_INVOICE;
$data['secColumns'] = Utils::trans(['checkbox', 'frequency', 'client', 'start_date', 'end_date', 'quote_total', 'action']);
}
return View::make('list', $data);
}
public function getDatatable($clientPublicId = null)
{
$accountId = Auth::user()->account_id;
$search = Input::get('sSearch');
return $this->invoiceRepo->getDatatable($accountId, $clientPublicId, ENTITY_QUOTE, $search);
}
public function create($clientPublicId = 0)
{
$client = null;
$invoiceNumber = Auth::user()->account->getNextInvoiceNumber();
$account = Account::with('country')->findOrFail(Auth::user()->account_id);
if ($clientPublicId)
{
$client = Client::scope($clientPublicId)->firstOrFail();
}
$data = array(
'account' => $account,
'invoice' => null,
'data' => Input::old('data'),
'invoiceNumber' => $invoiceNumber,
'method' => 'POST',
'url' => 'quotes',
'title' => '- New Quote',
'client' => $client);
$data = array_merge($data, self::getViewModel());
return View::make('invoices.edit', $data);
}
private static function getViewModel()
{
return [
'entityType' => ENTITY_QUOTE,
'account' => Auth::user()->account,
'products' => Product::scope()->orderBy('id')->get(array('product_key','notes','cost','qty')),
'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(),
'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(),
'taxRates' => TaxRate::scope()->orderBy('name')->get(),
'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(),
'sizes' => Size::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(),
'paymentTerms' => PaymentTerm::remember(DEFAULT_QUERY_CACHE)->orderBy('num_days')->get(['name', 'num_days']),
'industries' => Industry::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(),
'invoiceDesigns' => InvoiceDesign::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(),
'invoiceLabels' => Auth::user()->account->getInvoiceLabels()
];
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddQuotes extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('invoices', function($table)
{
$table->boolean('is_quote');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('invoices', function($table)
{
$table->dropColumn('is_quote');
});
}
}

View File

@ -351,5 +351,25 @@ return array(
'chart_builder' => 'Chart Builder',
'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!',
'quote' => 'Quote',
'quotes' => 'Quotes',
'quote_number' => 'Quote Number',
'quote_date' => 'Quote Date',
'quote_total' => 'Quote Total',
'new_quote' => 'New Quote',
'edit_quote' => 'Edit Quote',
'archive_quote' => 'Archive Quote',
'delete_quote' => 'Delete Quote',
'updated_quote' => 'Successfully updated quote',
'created_quote' => 'Successfully created quote',
'cloned_quote' => 'Successfully cloned quote',
'emailed_quote' => 'Successfully emailed quote',
'archived_quote' => 'Successfully archived quote',
'archived_quotes' => 'Successfully archived :count quotes',
'deleted_quote' => 'Successfully deleted quote',
'deleted_quotes' => 'Successfully deleted :count quotes',
);

View File

@ -32,6 +32,11 @@ class Utils
return isset($_ENV['NINJA_DEV']) && $_ENV['NINJA_DEV'];
}
public static function isPro()
{
return Auth::check() && Auth::user()->isPro();
}
public static function getProLabel($feature)
{
if (Auth::check()

View File

@ -80,6 +80,67 @@ class InvoiceRepository
return $query;
}
public function getDatatable($accountId, $clientPublicId = null, $entityType, $search)
{
$query = $this->getInvoices($accountId, $clientPublicId, $search);
if ($entityType == ENTITY_QUOTE)
{
$query->where('invoices.is_quote', '=', true);
}
$table = \Datatable::query($query);
if (!$clientPublicId)
{
$table->addColumn('checkbox', function($model) { return '<input type="checkbox" name="ids[]" value="' . $model->public_id . '">'; });
}
$table->addColumn("invoice_number", function($model) use ($entityType) { return link_to("{$entityType}s/" . $model->public_id . '/edit', $model->invoice_number); });
if (!$clientPublicId)
{
$table->addColumn('client_name', function($model) { return link_to('clients/' . $model->client_public_id, Utils::getClientDisplayName($model)); });
}
$table->addColumn("invoice_date", function($model) { return Utils::fromSqlDate($model->invoice_date); })
->addColumn('amount', function($model) { return Utils::formatMoney($model->amount, $model->currency_id); });
if ($entityType == ENTITY_INVOICE)
{
$table->addColumn('balance', function($model) { return Utils::formatMoney($model->balance, $model->currency_id); });
}
return $table->addColumn('due_date', function($model) { return Utils::fromSqlDate($model->due_date); })
->addColumn('invoice_status_name', function($model) { return $model->invoice_status_name; })
->addColumn('dropdown', function($model) use ($entityType)
{
$str = '<div class="btn-group tr-action" style="visibility:hidden;">
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
'.trans('texts.select').' <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="' . \URL::to("{$entityType}s/".$model->public_id.'/edit') . '">'.trans("texts.edit_{$entityType}").'</a></li>';
if ($entityType == ENTITY_INVOICE)
{
$str .= '<li><a href="' . \URL::to('payments/create/' . $model->client_public_id . '/' . $model->public_id ) . '">'.trans('texts.enter_payment').'</a></li>';
}
else
{
$str .= '';
}
return $str . '<li class="divider"></li>
<li><a href="javascript:archiveEntity(' . $model->public_id . ')">'.trans("texts.archive_{$entityType}").'</a></li>
<li><a href="javascript:deleteEntity(' . $model->public_id . ')">'.trans("texts.delete_{$entityType}").'</a></li>
</ul>
</div>';
})
->make();
}
public function getErrors($input)
{
$contact = (array) $input->client->contacts[0];

View File

@ -91,10 +91,17 @@ Route::group(array('before' => 'auth'), function()
Route::get('recurring_invoices', 'InvoiceController@recurringIndex');
Route::get('api/recurring_invoices/{client_id?}', array('as'=>'api.recurring_invoices', 'uses'=>'InvoiceController@getRecurringDatatable'));
Route::resource('invoices', 'InvoiceController');
Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable'));
Route::get('invoices/create/{client_id?}', 'InvoiceController@create');
Route::post('invoices/bulk', 'InvoiceController@bulk');
Route::resource('invoices', 'InvoiceController');
Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable'));
Route::get('invoices/create/{client_id?}', 'InvoiceController@create');
Route::post('invoices/bulk', 'InvoiceController@bulk');
Route::resource('quotes', 'QuoteController');
Route::get('api/quotes/{client_id?}', array('as'=>'api.quotes', 'uses'=>'QuoteController@getDatatable'));
/*
Route::get('invoices/create/{client_id?}', 'InvoiceController@create');
Route::post('invoices/bulk', 'InvoiceController@bulk');
*/
Route::get('payments/{id}/edit', function() { return View::make('header'); });
Route::resource('payments', 'PaymentController');
@ -132,6 +139,7 @@ define('ENTITY_INVOICE', 'invoice');
define('ENTITY_RECURRING_INVOICE', 'recurring_invoice');
define('ENTITY_PAYMENT', 'payment');
define('ENTITY_CREDIT', 'credit');
define('ENTITY_QUOTE', 'quote');
define('PERSON_CONTACT', 'contact');
define('PERSON_USER', 'user');

View File

@ -89,6 +89,9 @@
<ul class="nav navbar-nav" style="font-weight: bold">
{{ HTML::nav_link('dashboard', 'dashboard') }}
{{ HTML::menu_link('client') }}
@if (Utils::isPro())
{{ HTML::menu_link('quote') }}
@endif
{{ HTML::menu_link('invoice') }}
{{ HTML::menu_link('payment') }}
{{ HTML::menu_link('credit') }}

View File

@ -69,13 +69,15 @@
{{ Former::text('due_date')->data_bind("datePicker: due_date, valueUpdate: 'afterkeydown'")
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'due_date\')"></i>') }}
</div>
<div data-bind="visible: is_recurring" style="display: none">
{{ Former::select('frequency_id')->options($frequencies)->data_bind("value: frequency_id") }}
{{ Former::text('start_date')->data_bind("datePicker: start_date, valueUpdate: 'afterkeydown'")
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'start_date\')"></i>') }}
{{ Former::text('end_date')->data_bind("datePicker: end_date, valueUpdate: 'afterkeydown'")
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'end_date\')"></i>') }}
</div>
@if ($entityType == ENTITY_INVOICE)
<div data-bind="visible: is_recurring" style="display: none">
{{ Former::select('frequency_id')->options($frequencies)->data_bind("value: frequency_id") }}
{{ Former::text('start_date')->data_bind("datePicker: start_date, valueUpdate: 'afterkeydown'")
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'start_date\')"></i>') }}
{{ Former::text('end_date')->data_bind("datePicker: end_date, valueUpdate: 'afterkeydown'")
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'end_date\')"></i>') }}
</div>
@endif
@if ($invoice && $invoice->recurring_invoice_id)
<div class="pull-right" style="padding-top: 6px">
Created by a {{ link_to('/invoices/'.$invoice->recurring_invoice_id, 'recurring invoice') }}