1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-09 12:42:36 +01:00

Working on adding bulk actions to client page

This commit is contained in:
Hillel Coren 2016-11-24 11:22:37 +02:00
parent 1cc5795aa8
commit 8bac6b6c27
55 changed files with 463 additions and 193813 deletions

View File

@ -19,6 +19,7 @@ use App\Services\ClientService;
use App\Http\Requests\ClientRequest;
use App\Http\Requests\CreateClientRequest;
use App\Http\Requests\UpdateClientRequest;
use App\Ninja\Datatables\ClientDatatable;
class ClientController extends BaseController
{
@ -40,22 +41,13 @@ class ClientController extends BaseController
* @return Response
*/
public function index()
{
return View::make('list', [
{
return View::make('list_wrapper', [
'entityType' => ENTITY_CLIENT,
'datatable' => new ClientDatatable(),
'title' => trans('texts.clients'),
'sortCol' => '4',
'statuses' => Client::getStatuses(),
'columns' => Utils::trans([
'checkbox',
'client',
'contact',
'email',
'date_created',
'last_login',
'balance',
''
]),
]);
}

View File

@ -11,6 +11,7 @@ use App\Services\CreditService;
use App\Ninja\Repositories\CreditRepository;
use App\Http\Requests\CreateCreditRequest;
use App\Http\Requests\CreditRequest;
use App\Ninja\Datatables\CreditDatatable;
class CreditController extends BaseController
{
@ -33,19 +34,11 @@ class CreditController extends BaseController
*/
public function index()
{
return View::make('list', [
return View::make('list_wrapper', [
'entityType' => ENTITY_CREDIT,
'datatable' => new CreditDatatable(),
'title' => trans('texts.credits'),
'sortCol' => '4',
'columns' => Utils::trans([
'checkbox',
'client',
'credit_amount',
'credit_balance',
'credit_date',
'private_notes',
''
]),
]);
}
@ -62,7 +55,7 @@ class CreditController extends BaseController
'method' => 'POST',
'url' => 'credits',
'title' => trans('texts.new_credit'),
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
];
return View::make('credits.edit', $data);

View File

@ -19,6 +19,7 @@ use App\Ninja\Repositories\ExpenseRepository;
use App\Http\Requests\ExpenseRequest;
use App\Http\Requests\CreateExpenseRequest;
use App\Http\Requests\UpdateExpenseRequest;
use App\Ninja\Datatables\ExpenseDatatable;
class ExpenseController extends BaseController
{
@ -48,21 +49,11 @@ class ExpenseController extends BaseController
*/
public function index()
{
return View::make('list', [
return View::make('list_wrapper', [
'entityType' => ENTITY_EXPENSE,
'datatable' => new ExpenseDatatable(),
'title' => trans('texts.expenses'),
'sortCol' => '3',
'columns' => Utils::trans([
'checkbox',
'vendor',
'client',
'expense_date',
'amount',
'category',
'public_notes',
'status',
''
]),
]);
}

View File

@ -22,6 +22,7 @@ use App\Ninja\Mailers\ContactMailer as Mailer;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\ClientRepository;
use App\Ninja\Repositories\DocumentRepository;
use App\Ninja\Datatables\InvoiceDatatable;
use App\Services\InvoiceService;
use App\Services\PaymentService;
use App\Services\RecurringInvoiceService;
@ -59,20 +60,10 @@ class InvoiceController extends BaseController
'entityType' => ENTITY_INVOICE,
'sortCol' => '3',
'statuses' => Invoice::getStatuses(),
'columns' => Utils::trans([
'checkbox',
'invoice_number',
'client',
'invoice_date',
'invoice_total',
'balance_due',
'due_date',
'status',
''
]),
'datatable' => new InvoiceDatatable(),
];
return response()->view('list', $data);
return response()->view('list_wrapper', $data);
}
public function getDatatable($clientPublicId = null)

View File

@ -13,6 +13,7 @@ use App\Services\PaymentService;
use App\Http\Requests\PaymentRequest;
use App\Http\Requests\CreatePaymentRequest;
use App\Http\Requests\UpdatePaymentRequest;
use App\Ninja\Datatables\PaymentDatatable;
class PaymentController extends BaseController
{
@ -59,22 +60,11 @@ class PaymentController extends BaseController
*/
public function index()
{
return View::make('list', [
return View::make('list_wrapper', [
'entityType' => ENTITY_PAYMENT,
'datatable' => new PaymentDatatable(),
'title' => trans('texts.payments'),
'sortCol' => '7',
'columns' => Utils::trans([
'checkbox',
'invoice',
'client',
'transaction_reference',
'method',
'source',
'payment_amount',
'payment_date',
'status',
''
]),
]);
}

View File

@ -10,6 +10,7 @@ use Redirect;
use App\Models\Product;
use App\Models\TaxRate;
use App\Services\ProductService;
use App\Ninja\Datatables\ProductDatatable;
/**
* Class ProductController
@ -38,24 +39,12 @@ class ProductController extends BaseController
*/
public function index()
{
$columns = [
'checkbox',
'product',
'description',
'unit_cost'
];
if (Auth::user()->account->invoice_item_taxes) {
$columns[] = 'tax_rate';
}
$columns[] = 'action';
return View::make('list', [
return View::make('list_wrapper', [
'entityType' => ENTITY_PRODUCT,
'datatable' => new ProductDatatable(),
'title' => trans('texts.products'),
'statuses' => Product::getStatuses(),
'sortCol' => '4',
'columns' => Utils::trans($columns),
]);
}

View File

@ -20,6 +20,7 @@ use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\ClientRepository;
use App\Services\InvoiceService;
use App\Http\Requests\InvoiceRequest;
use App\Ninja\Datatables\InvoiceDatatable;
class QuoteController extends BaseController
{
@ -41,23 +42,17 @@ class QuoteController extends BaseController
public function index()
{
$datatable = new InvoiceDatatable();
$datatable->entityType = ENTITY_QUOTE;
$data = [
'title' => trans('texts.quotes'),
'entityType' => ENTITY_QUOTE,
'datatable' => $datatable,
'sortCol' => '3',
'columns' => Utils::trans([
'checkbox',
'quote_number',
'client',
'quote_date',
'quote_total',
'valid_until',
'status',
'action'
]),
];
return response()->view('list', $data);
return response()->view('list_wrapper', $data);
}
public function getDatatable($clientPublicId = null)

View File

@ -2,6 +2,7 @@
use Utils;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Datatables\RecurringInvoiceDatatable;
/**
* Class RecurringInvoiceController
@ -32,18 +33,10 @@ class RecurringInvoiceController extends BaseController
$data = [
'title' => trans('texts.recurring_invoices'),
'entityType' => ENTITY_RECURRING_INVOICE,
'columns' => Utils::trans([
'checkbox',
'frequency',
'client',
'start_date',
'end_date',
'invoice_total',
'action'
])
'datatable' => new RecurringInvoiceDatatable(),
];
return response()->view('list', $data);
return response()->view('list_wrapper', $data);
}
}
}

View File

@ -16,6 +16,7 @@ use App\Services\TaskService;
use App\Http\Requests\TaskRequest;
use App\Http\Requests\CreateTaskRequest;
use App\Http\Requests\UpdateTaskRequest;
use App\Ninja\Datatables\TaskDatatable;
/**
* Class TaskController
@ -66,19 +67,11 @@ class TaskController extends BaseController
*/
public function index()
{
return View::make('list', [
return View::make('list_wrapper', [
'entityType' => ENTITY_TASK,
'datatable' => new TaskDatatable(),
'title' => trans('texts.tasks'),
'sortCol' => '2',
'columns' => Utils::trans([
'checkbox',
'client',
'date',
'duration',
'description',
'status',
''
]),
]);
}

View File

@ -15,6 +15,7 @@ use App\Services\VendorService;
use App\Http\Requests\VendorRequest;
use App\Http\Requests\CreateVendorRequest;
use App\Http\Requests\UpdateVendorRequest;
use App\Ninja\Datatables\VendorDatatable;
class VendorController extends BaseController
{
@ -37,19 +38,11 @@ class VendorController extends BaseController
*/
public function index()
{
return View::make('list', [
return View::make('list_wrapper', [
'entityType' => 'vendor',
'datatable' => new VendorDatatable(),
'title' => trans('texts.vendors'),
'sortCol' => '4',
'columns' => Utils::trans([
'checkbox',
'vendor',
'city',
'phone',
'email',
'date_created',
''
]),
]);
}

View File

@ -324,5 +324,4 @@ class EntityModel extends Eloquent
return $class::getStatuses($entityType);
}
}

View File

@ -30,7 +30,7 @@ class ClientDatatable extends EntityDatatable
}
],
[
'clients.created_at',
'client_created_at',
function ($model) {
return Utils::timestampToDateString(strtotime($model->created_at));
}

View File

@ -6,10 +6,14 @@ class EntityDatatable
public $isBulkEdit;
public $hideClient;
public function __construct($isBulkEdit = true, $hideClient = false)
public function __construct($isBulkEdit = true, $hideClient = false, $entityType = false)
{
$this->isBulkEdit = $isBulkEdit;
$this->hideClient = $hideClient;
if ($entityType) {
$this->entityType = $entityType;
}
}
public function columns()
@ -21,4 +25,28 @@ class EntityDatatable
{
return [];
}
public function columnFields()
{
$data = [];
$columns = $this->columns();
if ($this->isBulkEdit) {
$data[] = 'checkbox';
}
foreach ($columns as $column) {
if (count($column) == 3) {
// third column is optionally used to determine visibility
if (!$column[2]) {
continue;
}
}
$data[] = $column[0];
}
$data[] = '';
return $data;
}
}

View File

@ -81,7 +81,7 @@ class ExpenseDatatable extends EntityDatatable
}
],
[
'expense_status_id',
'status',
function ($model) {
return self::getStatusLabel($model->invoice_id, $model->should_be_invoiced, $model->balance);
}

View File

@ -14,7 +14,7 @@ class InvoiceDatatable extends EntityDatatable
return [
[
'invoice_number',
$entityType == ENTITY_INVOICE ? 'invoice_number' : 'quote_number',
function ($model) use ($entityType) {
if(!Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->user_id])){
return $model->invoice_number;
@ -34,9 +34,9 @@ class InvoiceDatatable extends EntityDatatable
! $this->hideClient
],
[
'invoice_date',
'date',
function ($model) {
return Utils::fromSqlDate($model->invoice_date);
return Utils::fromSqlDate($model->date);
}
],
[
@ -58,13 +58,13 @@ class InvoiceDatatable extends EntityDatatable
$entityType == ENTITY_INVOICE
],
[
'due_date',
$entityType == ENTITY_INVOICE ? 'due_date' : 'valid_until',
function ($model) {
return Utils::fromSqlDate($model->due_date);
},
],
[
'invoice_status_name',
'status',
function ($model) use ($entityType) {
return $model->quote_invoice_id ? link_to("invoices/{$model->quote_invoice_id}/edit", trans('texts.converted'))->toHtml() : self::getStatusLabel($model);
}
@ -189,5 +189,4 @@ class InvoiceDatatable extends EntityDatatable
return "<h4><div class=\"label label-{$class}\">$label</div></h4>";
}
}

View File

@ -24,7 +24,7 @@ class TaskDatatable extends EntityDatatable
! $this->hideClient
],
[
'created_at',
'date',
function ($model) {
if(!Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id])){
return Task::calcStartTime($model);
@ -33,7 +33,7 @@ class TaskDatatable extends EntityDatatable
}
],
[
'time_log',
'duration',
function($model) {
return Utils::formatTime(Task::calcDuration($model));
}
@ -45,7 +45,7 @@ class TaskDatatable extends EntityDatatable
}
],
[
'invoice_number',
'status',
function ($model) {
return self::getStatusLabel($model);
}

View File

@ -36,7 +36,7 @@ class VendorDatatable extends EntityDatatable
}
],
[
'vendors.created_at',
'date',
function ($model) {
return Utils::timestampToDateString(strtotime($model->created_at));
}

View File

@ -13,7 +13,8 @@ class AccountGatewayRepository extends BaseRepository
{
$query = DB::table('account_gateways')
->join('gateways', 'gateways.id', '=', 'account_gateways.gateway_id')
->where('account_gateways.account_id', '=', $accountId);
->where('account_gateways.account_id', '=', $accountId)
->whereNull('account_gateways.deleted_at');
return $query->select('account_gateways.id', 'account_gateways.public_id', 'gateways.name', 'account_gateways.deleted_at', 'account_gateways.gateway_id');
}

View File

@ -119,7 +119,7 @@ class BaseRepository
protected function applyFilters($query, $entityType, $table = false)
{
$table = Utils::pluralizeEntityType($table ?: $entityType);
if ($filter = session('entity_state_filter:' . $entityType, STATUS_ACTIVE)) {
$filters = explode(',', $filter);
$query->where(function ($query) use ($filters, $table) {
@ -130,8 +130,11 @@ class BaseRepository
}
if (in_array(STATUS_ARCHIVED, $filters)) {
$query->orWhere(function ($query) use ($table) {
$query->whereNotNull($table . '.deleted_at')
->where($table . '.is_deleted', '=', 0);
$query->whereNotNull($table . '.deleted_at');
if ( ! in_array($table, ['users'])) {
$query->where($table . '.is_deleted', '=', 0);
}
});
}
if (in_array(STATUS_DELETED, $filters)) {

View File

@ -42,6 +42,7 @@ class ClientRepository extends BaseRepository
'clients.balance',
'clients.last_login',
'clients.created_at',
'clients.created_at as client_created_at',
'clients.work_phone',
'contacts.email',
'clients.deleted_at',

View File

@ -59,7 +59,7 @@ class ExpenseRepository extends BaseRepository
->orWhere('contacts.is_primary', '=', null);
})
->select(
DB::raw('COALESCE(expenses.invoice_id, expenses.should_be_invoiced) expense_status_id'),
DB::raw('COALESCE(expenses.invoice_id, expenses.should_be_invoiced) status'),
'expenses.account_id',
'expenses.amount',
'expenses.deleted_at',

View File

@ -57,13 +57,16 @@ class InvoiceRepository extends BaseRepository
'clients.public_id as client_public_id',
'clients.user_id as client_user_id',
'invoice_number',
'invoice_number as quote_number',
'invoice_status_id',
DB::raw("COALESCE(NULLIF(clients.name,''), NULLIF(CONCAT(contacts.first_name, ' ', contacts.last_name),''), NULLIF(contacts.email,'')) client_name"),
'invoices.public_id',
'invoices.amount',
'invoices.balance',
'invoices.invoice_date',
'invoices.invoice_date as date',
'invoices.due_date',
'invoices.due_date as valid_until',
'invoice_statuses.name as status',
'invoice_statuses.name as invoice_status_name',
'contacts.first_name',
'contacts.last_name',

View File

@ -38,12 +38,15 @@ class TaskRepository extends BaseRepository
'tasks.is_deleted',
'tasks.deleted_at',
'invoices.invoice_number',
'invoices.invoice_number as status',
'invoices.public_id as invoice_public_id',
'invoices.user_id as invoice_user_id',
'invoices.balance',
'tasks.is_running',
'tasks.time_log',
'tasks.time_log as duration',
'tasks.created_at',
'tasks.created_at as date',
'tasks.user_id'
);

View File

@ -14,7 +14,8 @@ class TokenRepository extends BaseRepository
public function find($userId)
{
$query = DB::table('account_tokens')
->where('account_tokens.user_id', '=', $userId);
->where('account_tokens.user_id', '=', $userId)
->whereNull('account_tokens.deleted_at');;
return $query->select('account_tokens.public_id', 'account_tokens.name', 'account_tokens.token', 'account_tokens.public_id', 'account_tokens.deleted_at');
}

View File

@ -37,6 +37,7 @@ class VendorRepository extends BaseRepository
'vendor_contacts.first_name',
'vendor_contacts.last_name',
'vendors.created_at',
'vendors.created_at as date',
'vendors.work_phone',
'vendors.city',
'vendor_contacts.email',

View File

@ -57,7 +57,7 @@ class CreditService extends BaseService
public function getDatatable($clientPublicId, $search)
{
// we don't support bulk edit and hide the client on the individual client page
$datatable = new CreditDatatable( ! $clientPublicId, $clientPublicId);
$datatable = new CreditDatatable(true, $clientPublicId);
$query = $this->creditRepo->find($clientPublicId, $search);
if(!Utils::hasPermission('view_all')){

View File

@ -155,7 +155,7 @@ class InvoiceService extends BaseService
public function getDatatable($accountId, $clientPublicId = null, $entityType, $search)
{
$datatable = new InvoiceDatatable( ! $clientPublicId, $clientPublicId);
$datatable = new InvoiceDatatable(true, $clientPublicId);
$datatable->entityType = $entityType;
$query = $this->invoiceRepo->getInvoices($accountId, $clientPublicId, $entityType, $search)

View File

@ -125,13 +125,13 @@ class PaymentService extends BaseService
public function getDatatable($clientPublicId, $search)
{
$datatable = new PaymentDatatable( ! $clientPublicId, $clientPublicId);
$datatable = new PaymentDatatable(true, $clientPublicId);
$query = $this->paymentRepo->find($clientPublicId, $search);
if(!Utils::hasPermission('view_all')){
$query->where('payments.user_id', '=', Auth::user()->id);
}
return $this->datatableService->createDatatable($datatable, $query);
}

View File

@ -18,7 +18,7 @@ class RecurringInvoiceService extends BaseService
public function getDatatable($accountId, $clientPublicId = null, $entityType, $search)
{
$datatable = new RecurringInvoiceDatatable( ! $clientPublicId, $clientPublicId);
$datatable = new RecurringInvoiceDatatable(true, $clientPublicId);
$query = $this->invoiceRepo->getRecurringInvoices($accountId, $clientPublicId, $search);
if(!Utils::hasPermission('view_all')){

View File

@ -40,7 +40,7 @@ class TaskService extends BaseService
*/
public function getDatatable($clientPublicId, $search)
{
$datatable = new TaskDatatable( ! $clientPublicId, $clientPublicId);
$datatable = new TaskDatatable(true, $clientPublicId);
$query = $this->taskRepo->find($clientPublicId, $search);
if(!Utils::hasPermission('view_all')){

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

13519
public/css/built.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

486
public/css/select2.css vendored

File diff suppressed because one or more lines are too long

10530
public/js/Chart.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

9559
public/js/d3.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

5882
public/js/select2.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1248,3 +1248,9 @@ div.panel-body div.panel-body {
.bluevine-quote .row{
text-align: right;
}
.select2-selection {
border: 1px solid #dfe0e1 !important;
border-radius: 2px;
padding: 2px;
}

View File

@ -511,7 +511,7 @@ $LANG = array(
'partial_remaining' => ':partial of :balance',
'more_fields' => 'More Fields',
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'client_name' => 'Client',
'pdf_settings' => 'PDF Settings',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
@ -2223,8 +2223,10 @@ $LANG = array(
'bluevine_continue' => 'Continue to BlueVine',
'bluevine_completed' => 'BlueVine signup completed',
'vendor_name' => 'Vendor',
'entity_state' => 'State',
'payment_status_name' => 'Status',
'client_created_at' => 'Created At',
);
return $LANG;

View File

@ -3,6 +3,9 @@
@section('head')
@parent
<script src="{{ asset('js/select2.min.js') }}" type="text/javascript"></script>
<link href="{{ asset('css/select2.css') }}" rel="stylesheet" type="text/css"/>
@if ($client->hasAddress())
<style>
#map {
@ -196,15 +199,17 @@
@if ($hasQuotes && Utils::isPro())
{!! Form::tab_link('#quotes', trans('texts.quotes')) !!}
@endif
@if ($hasRecurringInvoices)
{!! Form::tab_link('#recurring_invoices', trans('texts.recurring')) !!}
@endif
{!! Form::tab_link('#invoices', trans('texts.invoices')) !!}
{!! Form::tab_link('#payments', trans('texts.payments')) !!}
{!! Form::tab_link('#credits', trans('texts.credits')) !!}
</ul>
</ul><br/>
<div class="tab-content">
<div class="tab-pane active" id="activity">
{!! Datatable::table()
->addColumn(
trans('texts.date'),
@ -217,117 +222,63 @@
->setOptions('bFilter', false)
->setOptions('aaSorting', [['0', 'desc']])
->render('datatable') !!}
</div>
@if ($hasTasks)
<div class="tab-pane" id="tasks">
{!! Datatable::table()
->addColumn(
trans('texts.date'),
trans('texts.duration'),
trans('texts.description'),
trans('texts.status'))
->setUrl(url('api/tasks/'. $client->public_id))
->setCustomValues('entityType', 'tasks')
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->setOptions('aaSorting', [['0', 'desc']])
->render('datatable') !!}
@include('list', [
'entityType' => ENTITY_TASK,
'datatable' => new \App\Ninja\Datatables\TaskDatatable(true, true),
'clientId' => $client->public_id,
])
</div>
@endif
@if (Utils::hasFeature(FEATURE_QUOTES) && $hasQuotes)
<div class="tab-pane" id="quotes">
@include('list', [
'entityType' => ENTITY_QUOTE,
'datatable' => new \App\Ninja\Datatables\InvoiceDatatable(true, true, ENTITY_QUOTE),
'clientId' => $client->public_id,
])
</div>
@endif
{!! Datatable::table()
->addColumn(
trans('texts.quote_number'),
trans('texts.quote_date'),
trans('texts.total'),
trans('texts.valid_until'),
trans('texts.status'))
->setUrl(url('api/quotes/'. $client->public_id))
->setCustomValues('entityType', 'quotes')
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->setOptions('aaSorting', [['0', 'desc']])
->render('datatable') !!}
@if ($hasRecurringInvoices)
<div class="tab-pane" id="recurring_invoices">
@include('list', [
'entityType' => ENTITY_RECURRING_INVOICE,
'datatable' => new \App\Ninja\Datatables\RecurringInvoiceDatatable(true, true),
'clientId' => $client->public_id,
])
</div>
@endif
<div class="tab-pane" id="invoices">
@if ($hasRecurringInvoices)
{!! Datatable::table()
->addColumn(
trans('texts.frequency_id'),
trans('texts.start_date'),
trans('texts.end_date'),
trans('texts.invoice_total'))
->setUrl(url('api/recurring_invoices/' . $client->public_id))
->setCustomValues('entityType', 'recurring_invoices')
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->setOptions('aaSorting', [['0', 'asc']])
->render('datatable') !!}
@endif
{!! Datatable::table()
->addColumn(
trans('texts.invoice_number'),
trans('texts.invoice_date'),
trans('texts.invoice_total'),
trans('texts.balance_due'),
trans('texts.due_date'),
trans('texts.status'))
->setUrl(url('api/invoices/' . $client->public_id))
->setCustomValues('entityType', 'invoices')
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->setOptions('aaSorting', [['0', 'desc']])
->render('datatable') !!}
@include('list', [
'entityType' => ENTITY_INVOICE,
'datatable' => new \App\Ninja\Datatables\InvoiceDatatable(true, true),
'clientId' => $client->public_id,
])
</div>
<div class="tab-pane" id="payments">
{!! Datatable::table()
->addColumn(
trans('texts.invoice'),
trans('texts.transaction_reference'),
trans('texts.method'),
trans('texts.source'),
trans('texts.payment_amount'),
trans('texts.payment_date'),
trans('texts.status'))
->setUrl(url('api/payments/' . $client->public_id))
->setCustomValues('entityType', 'payments')
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->setOptions('aaSorting', [['0', 'desc']])
->render('datatable') !!}
@include('list', [
'entityType' => ENTITY_PAYMENT,
'datatable' => new \App\Ninja\Datatables\PaymentDatatable(true, true),
'clientId' => $client->public_id,
])
</div>
<div class="tab-pane" id="credits">
{!! Datatable::table()
->addColumn(
trans('texts.credit_amount'),
trans('texts.credit_balance'),
trans('texts.credit_date'),
trans('texts.private_notes'))
->setUrl(url('api/credits/' . $client->public_id))
->setCustomValues('entityType', 'credits')
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->setOptions('aaSorting', [['0', 'asc']])
->render('datatable') !!}
@include('list', [
'entityType' => ENTITY_CREDIT,
'datatable' => new \App\Ninja\Datatables\CreditDatatable(true, true),
'clientId' => $client->public_id,
])
</div>
</div>
<script type="text/javascript">
@ -350,9 +301,6 @@
if (!loadedTabs.hasOwnProperty(target)) {
loadedTabs[target] = true;
window['load_' + target]();
if (target == 'invoices' && window.hasOwnProperty('load_recurring_invoices')) {
window['load_recurring_invoices']();
}
}
});
var tab = localStorage.getItem('client_tab') || '';

View File

@ -32,7 +32,7 @@
</tbody>
</table>
<script type="text/javascript">
@if (isset($values['entityType']))
@if (isset($values['clientId']) && $values['clientId'])
window.load_{{ $values['entityType'] }} = function load_{{ $values['entityType'] }}() {
load_{{ $class }}();
}

View File

@ -1,31 +1,12 @@
@extends('header')
{!! Former::open(Utils::pluralizeEntityType($entityType) . '/bulk')->addClass('listForm') !!}
@section('head')
@parent
<script src="{{ asset('js/select2.min.js') }}" type="text/javascript"></script>
<link href="{{ asset('css/select2.css') }}" rel="stylesheet" type="text/css"/>
<style type="text/css">
.select2-selection {
border: 1px solid #dfe0e1 !important;
border-radius: 2px;
padding: 2px;
}
</style>
@stop
@section('content')
{!! Former::open(Utils::pluralizeEntityType($entityType) . '/bulk')->addClass('listForm') !!}
<div style="display:none">
{!! Former::text('action') !!}
{!! Former::text('public_id') !!}
{!! Former::text('datatable')->value('true') !!}
</div>
<div style="display:none">
{!! Former::text('action') !!}
{!! Former::text('public_id') !!}
{!! Former::text('datatable')->value('true') !!}
</div>
<div class="pull-left">
@can('create', 'invoice')
@if ($entityType == ENTITY_TASK)
{!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm("invoice")'])->appendIcon(Icon::create('check')) !!}
@ -35,18 +16,18 @@
@endif
@endcan
@if (in_array($entityType, [ENTITY_EXPENSE_CATEGORY, ENTITY_PRODUCT]))
{!! Button::normal(trans('texts.archive'))->asLinkTo('javascript:submitForm("archive")')->appendIcon(Icon::create('trash')) !!}
@else
{!! DropdownButton::normal(trans('texts.archive'))->withContents([
['label' => trans('texts.archive_'.$entityType), 'url' => 'javascript:submitForm("archive")'],
['label' => trans('texts.delete_'.$entityType), 'url' => 'javascript:submitForm("delete")'],
])->withAttributes(['class'=>'archive'])->split() !!}
@endif
@if (in_array($entityType, [ENTITY_EXPENSE_CATEGORY, ENTITY_PRODUCT]))
{!! Button::normal(trans('texts.archive'))->asLinkTo('javascript:submitForm("archive")')->appendIcon(Icon::create('trash')) !!}
@else
{!! DropdownButton::normal(trans('texts.archive'))->withContents([
['label' => trans('texts.archive_'.$entityType), 'url' => 'javascript:submitForm("archive")'],
['label' => trans('texts.delete_'.$entityType), 'url' => 'javascript:submitForm("delete")'],
])->withAttributes(['class'=>'archive'])->split() !!}
@endif
&nbsp;
<span id="statusWrapper" style="display:none">
<select class="form-control" style="width: 220px" id="statuses" multiple="true">
<span id="statusWrapper_{{ $entityType }}" style="display:none">
<select class="form-control" style="width: 220px" id="statuses_{{ $entityType }}" multiple="true">
@if (count(\App\Models\EntityModel::getStatusesFor($entityType)))
<optgroup label="{{ trans('texts.entity_state') }}">
@foreach (\App\Models\EntityModel::getStatesFor($entityType) as $key => $value)
@ -65,228 +46,232 @@
@endif
</select>
</span>
</div>
<div id="top_right_buttons" class="pull-right">
<input id="tableFilter" type="text" style="width:140px;margin-right:17px;background-color: white !important"
class="form-control pull-left" placeholder="{{ trans('texts.filter') }}" value="{{ Input::get('filter') }}"/>
@if ($entityType == ENTITY_EXPENSE)
{!! Button::normal(trans('texts.categories'))->asLinkTo(URL::to('/expense_categories'))->appendIcon(Icon::create('list')) !!}
@endif
<div id="top_right_buttons" class="pull-right">
<input id="tableFilter" type="text" style="width:140px;margin-right:17px;background-color: white !important"
class="form-control pull-left" placeholder="{{ trans('texts.filter') }}" value="{{ Input::get('filter') }}"/>
@if (empty($clientId))
@if ($entityType == ENTITY_EXPENSE)
{!! Button::normal(trans('texts.categories'))->asLinkTo(URL::to('/expense_categories'))->appendIcon(Icon::create('list')) !!}
@endif
@if (Auth::user()->can('create', $entityType))
{!! Button::primary(trans("texts.new_{$entityType}"))->asLinkTo(url(Utils::pluralizeEntityType($entityType) . '/create'))->appendIcon(Icon::create('plus-sign')) !!}
{!! Button::primary(trans("texts.new_{$entityType}"))->asLinkTo(url(Utils::pluralizeEntityType($entityType) . '/create'))->appendIcon(Icon::create('plus-sign')) !!}
@endif
@endif
</div>
</div>
{!! Datatable::table()
->addColumn($columns)
->setUrl(route('api.' . Utils::pluralizeEntityType($entityType)))
->setCustomValues('rightAlign', isset($rightAlign) ? $rightAlign : [])
->setOptions('sPaginationType', 'bootstrap')
->setOptions('aaSorting', [[isset($sortCol) ? $sortCol : '1', 'desc']])
->render('datatable') !!}
{!! Datatable::table()
->addColumn(Utils::trans($datatable->columnFields()))
->setUrl(url('api/' . Utils::pluralizeEntityType($entityType) . '/' . (isset($clientId) ? $clientId : '')))
->setCustomValues('rightAlign', isset($rightAlign) ? $rightAlign : [])
->setCustomValues('entityType', Utils::pluralizeEntityType($entityType))
->setCustomValues('clientId', isset($clientId) && $clientId)
->setOptions('sPaginationType', 'bootstrap')
->setOptions('aaSorting', [[isset($sortCol) ? $sortCol : '1', 'desc']])
->render('datatable') !!}
@if ($entityType == ENTITY_PAYMENT)
<div class="modal fade" id="paymentRefundModal" tabindex="-1" role="dialog" aria-labelledby="paymentRefundModalLabel" aria-hidden="true">
<div class="modal-dialog" style="min-width:150px">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="paymentRefundModalLabel">{{ trans('texts.refund_payment') }}</h4>
</div>
<div class="modal-body">
<div class="form-horizontal">
<div class="form-group">
<label for="refundAmount" class="col-sm-offset-2 col-sm-2 control-label">{{ trans('texts.amount') }}</label>
<div class="col-sm-4">
<div class="input-group">
<span class="input-group-addon" id="refundCurrencySymbol"></span>
<input type="number" class="form-control" id="refundAmount" name="amount" step="0.01" min="0.01" placeholder="{{ trans('texts.amount') }}">
</div>
<div class="help-block">{{ trans('texts.refund_max') }} <span id="refundMax"></span></div>
</div>
</div>
</div>
</div>
<div class="modal-footer" style="margin-top: 0px">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.cancel') }}</button>
<button type="button" class="btn btn-primary" id="completeRefundButton">{{ trans('texts.refund') }}</button>
</div>
</div>
@if ($entityType == ENTITY_PAYMENT)
<div class="modal fade" id="paymentRefundModal" tabindex="-1" role="dialog" aria-labelledby="paymentRefundModalLabel" aria-hidden="true">
<div class="modal-dialog" style="min-width:150px">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="paymentRefundModalLabel">{{ trans('texts.refund_payment') }}</h4>
</div>
<div class="modal-body">
<div class="form-horizontal">
<div class="form-group">
<label for="refundAmount" class="col-sm-offset-2 col-sm-2 control-label">{{ trans('texts.amount') }}</label>
<div class="col-sm-4">
<div class="input-group">
<span class="input-group-addon" id="refundCurrencySymbol"></span>
<input type="number" class="form-control" id="refundAmount" name="amount" step="0.01" min="0.01" placeholder="{{ trans('texts.amount') }}">
</div>
<div class="help-block">{{ trans('texts.refund_max') }} <span id="refundMax"></span></div>
</div>
</div>
</div>
</div>
<div class="modal-footer" style="margin-top: 0px">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.cancel') }}</button>
<button type="button" class="btn btn-primary" id="completeRefundButton">{{ trans('texts.refund') }}</button>
</div>
</div>
@endif
</div>
</div>
@endif
{!! Former::close() !!}
{!! Former::close() !!}
<script type="text/javascript">
<script type="text/javascript">
function submitForm(action) {
if (action == 'delete') {
sweetConfirm(function() {
$('#action').val(action);
$('form.listForm').submit();
});
} else {
$('#action').val(action);
function submitForm(action) {
if (action == 'delete') {
sweetConfirm(function() {
$('#action').val(action);
$('form.listForm').submit();
});
} else {
$('#action').val(action);
$('form.listForm').submit();
}
}
function deleteEntity(id) {
$('#public_id').val(id);
submitForm('delete');
}
function archiveEntity(id) {
$('#public_id').val(id);
submitForm('archive');
}
function restoreEntity(id) {
$('#public_id').val(id);
submitForm('restore');
}
function convertEntity(id) {
$('#public_id').val(id);
submitForm('convert');
}
function markEntity(id) {
$('#public_id').val(id);
submitForm('markSent');
}
function stopTask(id) {
$('#public_id').val(id);
submitForm('stop');
}
function invoiceEntity(id) {
$('#public_id').val(id);
submitForm('invoice');
}
@if ($entityType == ENTITY_PAYMENT)
var paymentId = null;
function showRefundModal(id, amount, formatted, symbol){
paymentId = id;
$('#refundCurrencySymbol').text(symbol);
$('#refundMax').text(formatted);
$('#refundAmount').val(amount).attr('max', amount);
$('#paymentRefundModal').modal('show');
}
function handleRefundClicked(){
$('#public_id').val(paymentId);
submitForm('refund');
}
@endif
/*
function setTrashVisible() {
var checked = $('#trashed').is(':checked');
var url = '{{ URL::to('set_entity_filter/' . $entityType) }}' + (checked ? '/true' : '/false');
$.get(url, function(data) {
refreshDatatable();
})
}
*/
$(function() {
var tableFilter = '';
var searchTimeout = false;
var oTable0 = $('#DataTables_Table_0').dataTable();
var oTable1 = $('#DataTables_Table_1').dataTable();
function filterTable(val) {
if (val == tableFilter) {
return;
}
}
function deleteEntity(id) {
$('#public_id').val(id);
submitForm('delete');
}
function archiveEntity(id) {
$('#public_id').val(id);
submitForm('archive');
}
function restoreEntity(id) {
$('#public_id').val(id);
submitForm('restore');
}
function convertEntity(id) {
$('#public_id').val(id);
submitForm('convert');
tableFilter = val;
oTable0.fnFilter(val);
}
function markEntity(id) {
$('#public_id').val(id);
submitForm('markSent');
}
$('#tableFilter').on('keyup', function(){
if (searchTimeout) {
window.clearTimeout(searchTimeout);
}
function stopTask(id) {
$('#public_id').val(id);
submitForm('stop');
searchTimeout = setTimeout(function() {
filterTable($('#tableFilter').val());
}, 500);
})
if ($('#tableFilter').val()) {
filterTable($('#tableFilter').val());
}
function invoiceEntity(id) {
$('#public_id').val(id);
submitForm('invoice');
window.onDatatableReady = function() {
$(':checkbox').click(function() {
setBulkActionsEnabled();
});
$('tbody tr').unbind('click').click(function(event) {
if (event.target.type !== 'checkbox' && event.target.type !== 'button' && event.target.tagName.toLowerCase() !== 'a') {
$checkbox = $(this).closest('tr').find(':checkbox:not(:disabled)');
var checked = $checkbox.prop('checked');
$checkbox.prop('checked', !checked);
setBulkActionsEnabled();
}
});
actionListHandler();
}
@if ($entityType == ENTITY_PAYMENT)
var paymentId = null;
function showRefundModal(id, amount, formatted, symbol){
paymentId = id;
$('#refundCurrencySymbol').text(symbol);
$('#refundMax').text(formatted);
$('#refundAmount').val(amount).attr('max', amount);
$('#paymentRefundModal').modal('show');
}
function handleRefundClicked(){
$('#public_id').val(paymentId);
submitForm('refund');
}
$('#completeRefundButton').click(handleRefundClicked)
@endif
/*
function setTrashVisible() {
var checked = $('#trashed').is(':checked');
var url = '{{ URL::to('set_entity_filter/' . $entityType) }}' + (checked ? '/true' : '/false');
$('.archive, .invoice').prop('disabled', true);
$('.archive:not(.dropdown-toggle)').click(function() {
submitForm('archive');
});
$('.selectAll').click(function() {
$(this).closest('table').find(':checkbox:not(:disabled)').prop('checked', this.checked);
});
function setBulkActionsEnabled() {
var buttonLabel = "{{ trans('texts.archive') }}";
var count = $('tbody :checkbox:checked').length;
$('button.archive, button.invoice').prop('disabled', !count);
if (count) {
buttonLabel += ' (' + count + ')';
}
$('button.archive').not('.dropdown-toggle').text(buttonLabel);
}
$('#statuses_{{ $entityType }}').select2({
placeholder: "{{ trans('texts.status') }}",
}).val('{{ session('entity_state_filter:' . $entityType, STATUS_ACTIVE) . ',' . session('entity_status_filter:' . $entityType) }}'.split(','))
.trigger('change')
.on('change', function() {
var filter = $('#statuses_{{ $entityType }}').val();
if (filter) {
filter = filter.join(',');
} else {
filter = '';
}
var url = '{{ URL::to('set_entity_filter/' . $entityType) }}' + '/' + filter;
$.get(url, function(data) {
refreshDatatable();
})
}
*/
}).maximizeSelect2Height();
$(function() {
var tableFilter = '';
var searchTimeout = false;
$('#statusWrapper_{{ $entityType }}').show();
var oTable0 = $('#DataTables_Table_0').dataTable();
var oTable1 = $('#DataTables_Table_1').dataTable();
function filterTable(val) {
if (val == tableFilter) {
return;
}
tableFilter = val;
oTable0.fnFilter(val);
}
});
$('#tableFilter').on('keyup', function(){
if (searchTimeout) {
window.clearTimeout(searchTimeout);
}
searchTimeout = setTimeout(function() {
filterTable($('#tableFilter').val());
}, 500);
})
if ($('#tableFilter').val()) {
filterTable($('#tableFilter').val());
}
window.onDatatableReady = function() {
$(':checkbox').click(function() {
setBulkActionsEnabled();
});
$('tbody tr').unbind('click').click(function(event) {
if (event.target.type !== 'checkbox' && event.target.type !== 'button' && event.target.tagName.toLowerCase() !== 'a') {
$checkbox = $(this).closest('tr').find(':checkbox:not(:disabled)');
var checked = $checkbox.prop('checked');
$checkbox.prop('checked', !checked);
setBulkActionsEnabled();
}
});
actionListHandler();
}
@if ($entityType == ENTITY_PAYMENT)
$('#completeRefundButton').click(handleRefundClicked)
@endif
$('.archive, .invoice').prop('disabled', true);
$('.archive:not(.dropdown-toggle)').click(function() {
submitForm('archive');
});
$('.selectAll').click(function() {
$(this).closest('table').find(':checkbox:not(:disabled)').prop('checked', this.checked);
});
function setBulkActionsEnabled() {
var buttonLabel = "{{ trans('texts.archive') }}";
var count = $('tbody :checkbox:checked').length;
$('button.archive, button.invoice').prop('disabled', !count);
if (count) {
buttonLabel += ' (' + count + ')';
}
$('button.archive').not('.dropdown-toggle').text(buttonLabel);
}
$('#statuses').select2({
placeholder: "{{ trans('texts.status') }}",
}).val('{{ session('entity_state_filter:' . $entityType, STATUS_ACTIVE) . ',' . session('entity_status_filter:' . $entityType) }}'.split(','))
.trigger('change')
.on('change', function() {
var filter = $('#statuses').val();
if (filter) {
filter = filter.join(',');
} else {
filter = '';
}
var url = '{{ URL::to('set_entity_filter/' . $entityType) }}' + '/' + filter;
$.get(url, function(data) {
refreshDatatable();
})
}).maximizeSelect2Height();
$('#statusWrapper').show();
});
</script>
@stop
</script>

View File

@ -0,0 +1,15 @@
@extends('header')
@section('head')
@parent
<script src="{{ asset('js/select2.min.js') }}" type="text/javascript"></script>
<link href="{{ asset('css/select2.css') }}" rel="stylesheet" type="text/css"/>
@stop
@section('content')
@include('list')
@stop