mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-09-20 08:21:34 +02:00
Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
commit
b4e9dc3063
2
LICENSE
2
LICENSE
@ -13,7 +13,7 @@ open-source software.
|
||||
|
||||
1. Redistributions of source code, in whole or part and with or without
|
||||
modification requires the express permission of the author and must prominently
|
||||
display "Powered by InvoiceNinja" or the Invoice Ninja logo in verifiable form
|
||||
display "Powered by InvoiceNinja" and the Invoice Ninja logo in verifiable form
|
||||
with hyperlink to said site.
|
||||
2. Neither the name nor any trademark of the Author may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
|
@ -137,8 +137,6 @@ class AccountController extends BaseController
|
||||
|
||||
if ($section == ACCOUNT_COMPANY_DETAILS) {
|
||||
return self::showCompanyDetails();
|
||||
} elseif ($section == ACCOUNT_USER_DETAILS) {
|
||||
return self::showUserDetails();
|
||||
} elseif ($section == ACCOUNT_LOCALIZATION) {
|
||||
return self::showLocalization();
|
||||
} elseif ($section == ACCOUNT_PAYMENTS) {
|
||||
@ -232,7 +230,7 @@ class AccountController extends BaseController
|
||||
return View::make('accounts.details', $data);
|
||||
}
|
||||
|
||||
private function showUserDetails()
|
||||
public function showUserDetails()
|
||||
{
|
||||
$oauthLoginUrls = [];
|
||||
foreach (AuthService::$providers as $provider) {
|
||||
@ -467,8 +465,6 @@ class AccountController extends BaseController
|
||||
{
|
||||
if ($section === ACCOUNT_COMPANY_DETAILS) {
|
||||
return AccountController::saveDetails();
|
||||
} elseif ($section === ACCOUNT_USER_DETAILS) {
|
||||
return AccountController::saveUserDetails();
|
||||
} elseif ($section === ACCOUNT_LOCALIZATION) {
|
||||
return AccountController::saveLocalization();
|
||||
} elseif ($section === ACCOUNT_NOTIFICATIONS) {
|
||||
@ -764,7 +760,7 @@ class AccountController extends BaseController
|
||||
}
|
||||
|
||||
$labels = [];
|
||||
foreach (['item', 'description', 'unit_cost', 'quantity', 'line_total', 'terms'] as $field) {
|
||||
foreach (['item', 'description', 'unit_cost', 'quantity', 'line_total', 'terms', 'balance_due', 'partial_due'] as $field) {
|
||||
$labels[$field] = Input::get("labels_{$field}");
|
||||
}
|
||||
$account->invoice_labels = json_encode($labels);
|
||||
@ -839,7 +835,7 @@ class AccountController extends BaseController
|
||||
return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS);
|
||||
}
|
||||
|
||||
private function saveUserDetails()
|
||||
public function saveUserDetails()
|
||||
{
|
||||
$user = Auth::user();
|
||||
$rules = ['email' => 'email|required|unique:users,email,'.$user->id.',id'];
|
||||
|
@ -1,10 +1,14 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Middleware\PermissionsRequired;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Auth;
|
||||
|
||||
class BaseController extends Controller
|
||||
{
|
||||
use DispatchesJobs;
|
||||
|
||||
protected $model = 'App\Models\EntityModel';
|
||||
|
||||
/**
|
||||
* Setup the layout used by the controller.
|
||||
@ -17,11 +21,40 @@ class BaseController extends Controller
|
||||
$this->layout = View::make($this->layout);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public function __construct()
|
||||
{
|
||||
$this->beforeFilter('csrf', array('on' => array('post', 'delete', 'put')));
|
||||
|
||||
protected function checkViewPermission($object, &$response = null){
|
||||
if(!$object->canView()){
|
||||
$response = response('Unauthorized.', 401);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function checkEditPermission($object, &$response = null){
|
||||
if(!$object->canEdit()){
|
||||
$response = response('Unauthorized.', 401);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function checkCreatePermission(&$response = null){
|
||||
if(!call_user_func(array($this->model, 'canCreate'))){
|
||||
$response = response('Unauthorized.', 401);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function checkUpdatePermission($input, &$response = null){
|
||||
$creating = empty($input['public_id']) || $input['public_id'] == '-1';
|
||||
|
||||
if($creating){
|
||||
return $this->checkCreatePermission($response);
|
||||
}
|
||||
else{
|
||||
$object = call_user_func(array($this->model, 'scope'), $input['public_id'])->firstOrFail();
|
||||
return $this->checkEditPermission($object, $response);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
@ -20,6 +20,9 @@ use App\Models\Size;
|
||||
use App\Models\PaymentTerm;
|
||||
use App\Models\Industry;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Country;
|
||||
use App\Models\Task;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
@ -32,6 +35,7 @@ class ClientController extends BaseController
|
||||
{
|
||||
protected $clientService;
|
||||
protected $clientRepo;
|
||||
protected $model = 'App\Models\Client';
|
||||
|
||||
public function __construct(ClientRepository $clientRepo, ClientService $clientService)
|
||||
{
|
||||
@ -77,7 +81,13 @@ class ClientController extends BaseController
|
||||
*/
|
||||
public function store(CreateClientRequest $request)
|
||||
{
|
||||
$client = $this->clientService->save($request->input());
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$client = $this->clientService->save($data);
|
||||
|
||||
Session::flash('message', trans('texts.created_client'));
|
||||
|
||||
@ -93,22 +103,36 @@ class ClientController extends BaseController
|
||||
public function show($publicId)
|
||||
{
|
||||
$client = Client::withTrashed()->scope($publicId)->with('contacts', 'size', 'industry')->firstOrFail();
|
||||
|
||||
if(!$this->checkViewPermission($client, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT);
|
||||
|
||||
$actionLinks = [
|
||||
['label' => trans('texts.new_task'), 'url' => '/tasks/create/'.$client->public_id]
|
||||
];
|
||||
|
||||
if (Utils::isPro()) {
|
||||
array_push($actionLinks, ['label' => trans('texts.new_quote'), 'url' => '/quotes/create/'.$client->public_id]);
|
||||
$actionLinks = [];
|
||||
if(Task::canCreate()){
|
||||
$actionLinks[] = ['label' => trans('texts.new_task'), 'url' => '/tasks/create/'.$client->public_id];
|
||||
}
|
||||
if (Utils::isPro() && Invoice::canCreate()) {
|
||||
$actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => '/quotes/create/'.$client->public_id];
|
||||
}
|
||||
|
||||
if(!empty($actionLinks)){
|
||||
$actionLinks[] = \DropdownButton::DIVIDER;
|
||||
}
|
||||
|
||||
if(Payment::canCreate()){
|
||||
$actionLinks[] = ['label' => trans('texts.enter_payment'), 'url' => '/payments/create/'.$client->public_id];
|
||||
}
|
||||
|
||||
if(Credit::canCreate()){
|
||||
$actionLinks[] = ['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id];
|
||||
}
|
||||
|
||||
if(Expense::canCreate()){
|
||||
$actionLinks[] = ['label' => trans('texts.enter_expense'), 'url' => '/expenses/create/0/'.$client->public_id];
|
||||
}
|
||||
|
||||
array_push($actionLinks,
|
||||
\DropdownButton::DIVIDER,
|
||||
['label' => trans('texts.enter_payment'), 'url' => '/payments/create/'.$client->public_id],
|
||||
['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id],
|
||||
['label' => trans('texts.enter_expense'), 'url' => '/expenses/create/0/'.$client->public_id]
|
||||
);
|
||||
|
||||
$data = array(
|
||||
'actionLinks' => $actionLinks,
|
||||
@ -132,6 +156,10 @@ class ClientController extends BaseController
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (Client::scope()->withTrashed()->count() > Auth::user()->getMaxNumClients()) {
|
||||
return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumClients()." clients"]);
|
||||
}
|
||||
@ -157,6 +185,11 @@ class ClientController extends BaseController
|
||||
public function edit($publicId)
|
||||
{
|
||||
$client = Client::scope($publicId)->with('contacts')->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($client, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'client' => $client,
|
||||
'method' => 'PUT',
|
||||
@ -199,7 +232,13 @@ class ClientController extends BaseController
|
||||
*/
|
||||
public function update(UpdateClientRequest $request)
|
||||
{
|
||||
$client = $this->clientService->save($request->input());
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$client = $this->clientService->save($data);
|
||||
|
||||
Session::flash('message', trans('texts.updated_client'));
|
||||
|
||||
|
@ -17,10 +17,11 @@ class CreditController extends BaseController
|
||||
{
|
||||
protected $creditRepo;
|
||||
protected $creditService;
|
||||
protected $model = 'App\Models\Credit';
|
||||
|
||||
public function __construct(CreditRepository $creditRepo, CreditService $creditService)
|
||||
{
|
||||
//parent::__construct();
|
||||
// parent::__construct();
|
||||
|
||||
$this->creditRepo = $creditRepo;
|
||||
$this->creditService = $creditService;
|
||||
@ -56,6 +57,10 @@ class CreditController extends BaseController
|
||||
|
||||
public function create($clientPublicId = 0)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId,
|
||||
//'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : $invoicePublicId,
|
||||
@ -72,6 +77,11 @@ class CreditController extends BaseController
|
||||
public function edit($publicId)
|
||||
{
|
||||
$credit = Credit::scope($publicId)->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($credit, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$credit->credit_date = Utils::fromSqlDate($credit->credit_date);
|
||||
|
||||
$data = array(
|
||||
|
@ -11,7 +11,9 @@ class DashboardController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
|
||||
$view_all = !Auth::user()->hasPermission('view_all');
|
||||
$user_id = Auth::user()->id;
|
||||
|
||||
// total_income, billed_clients, invoice_sent and active_clients
|
||||
$select = DB::raw('COUNT(DISTINCT CASE WHEN invoices.id IS NOT NULL THEN clients.id ELSE null END) billed_clients,
|
||||
SUM(CASE WHEN invoices.invoice_status_id >= '.INVOICE_STATUS_SENT.' THEN 1 ELSE 0 END) invoices_sent,
|
||||
@ -24,8 +26,19 @@ class DashboardController extends BaseController
|
||||
->where('clients.is_deleted', '=', false)
|
||||
->where('invoices.is_deleted', '=', false)
|
||||
->where('invoices.is_recurring', '=', false)
|
||||
->where('invoices.is_quote', '=', false)
|
||||
->groupBy('accounts.id')
|
||||
->where('invoices.is_quote', '=', false);
|
||||
|
||||
if(!$view_all){
|
||||
$metrics = $metrics->where(function($query) use($user_id){
|
||||
$query->where('invoices.user_id', '=', $user_id);
|
||||
$query->orwhere(function($query) use($user_id){
|
||||
$query->where('invoices.user_id', '=', null);
|
||||
$query->where('clients.user_id', '=', $user_id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$metrics = $metrics->groupBy('accounts.id')
|
||||
->first();
|
||||
|
||||
$select = DB::raw('SUM(clients.paid_to_date) as value, clients.currency_id as currency_id');
|
||||
@ -33,8 +46,13 @@ class DashboardController extends BaseController
|
||||
->select($select)
|
||||
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
|
||||
->where('accounts.id', '=', Auth::user()->account_id)
|
||||
->where('clients.is_deleted', '=', false)
|
||||
->groupBy('accounts.id')
|
||||
->where('clients.is_deleted', '=', false);
|
||||
|
||||
if(!$view_all){
|
||||
$paidToDate = $paidToDate->where('clients.user_id', '=', $user_id);
|
||||
}
|
||||
|
||||
$paidToDate = $paidToDate->groupBy('accounts.id')
|
||||
->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END'))
|
||||
->get();
|
||||
|
||||
@ -47,8 +65,13 @@ class DashboardController extends BaseController
|
||||
->where('clients.is_deleted', '=', false)
|
||||
->where('invoices.is_deleted', '=', false)
|
||||
->where('invoices.is_quote', '=', false)
|
||||
->where('invoices.is_recurring', '=', false)
|
||||
->groupBy('accounts.id')
|
||||
->where('invoices.is_recurring', '=', false);
|
||||
|
||||
if(!$view_all){
|
||||
$averageInvoice = $averageInvoice->where('invoices.user_id', '=', $user_id);
|
||||
}
|
||||
|
||||
$averageInvoice = $averageInvoice->groupBy('accounts.id')
|
||||
->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END'))
|
||||
->get();
|
||||
|
||||
@ -63,9 +86,14 @@ class DashboardController extends BaseController
|
||||
->get();
|
||||
|
||||
$activities = Activity::where('activities.account_id', '=', Auth::user()->account_id)
|
||||
->where('activities.activity_type_id', '>', 0);
|
||||
|
||||
if(!$view_all){
|
||||
$activities = $activities->where('activities.user_id', '=', $user_id);
|
||||
}
|
||||
|
||||
$activities = $activities->orderBy('activities.created_at', 'desc')
|
||||
->with('client.contacts', 'user', 'invoice', 'payment', 'credit', 'account')
|
||||
->where('activity_type_id', '>', 0)
|
||||
->orderBy('created_at', 'desc')
|
||||
->take(50)
|
||||
->get();
|
||||
|
||||
@ -81,8 +109,13 @@ class DashboardController extends BaseController
|
||||
->where('invoices.is_deleted', '=', false)
|
||||
->where('invoices.deleted_at', '=', null)
|
||||
->where('contacts.is_primary', '=', true)
|
||||
->where('invoices.due_date', '<', date('Y-m-d'))
|
||||
->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'is_quote'])
|
||||
->where('invoices.due_date', '<', date('Y-m-d'));
|
||||
|
||||
if(!$view_all){
|
||||
$pastDue = $pastDue->where('invoices.user_id', '=', $user_id);
|
||||
}
|
||||
|
||||
$pastDue = $pastDue->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote'])
|
||||
->orderBy('invoices.due_date', 'asc')
|
||||
->take(50)
|
||||
->get();
|
||||
@ -100,9 +133,14 @@ class DashboardController extends BaseController
|
||||
->where('invoices.is_deleted', '=', false)
|
||||
->where('contacts.is_primary', '=', true)
|
||||
->where('invoices.due_date', '>=', date('Y-m-d'))
|
||||
->orderBy('invoices.due_date', 'asc')
|
||||
->take(50)
|
||||
->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'is_quote'])
|
||||
->orderBy('invoices.due_date', 'asc');
|
||||
|
||||
if(!$view_all){
|
||||
$upcoming = $upcoming->where('invoices.user_id', '=', $user_id);
|
||||
}
|
||||
|
||||
$upcoming = $upcoming->take(50)
|
||||
->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote'])
|
||||
->get();
|
||||
|
||||
$payments = DB::table('payments')
|
||||
@ -114,8 +152,13 @@ class DashboardController extends BaseController
|
||||
->where('invoices.is_deleted', '=', false)
|
||||
->where('clients.is_deleted', '=', false)
|
||||
->where('contacts.deleted_at', '=', null)
|
||||
->where('contacts.is_primary', '=', true)
|
||||
->select(['payments.payment_date', 'payments.amount', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id'])
|
||||
->where('contacts.is_primary', '=', true);
|
||||
|
||||
if(!$view_all){
|
||||
$payments = $payments->where('payments.user_id', '=', $user_id);
|
||||
}
|
||||
|
||||
$payments = $payments->select(['payments.payment_date', 'payments.amount', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id'])
|
||||
->orderBy('payments.payment_date', 'desc')
|
||||
->take(50)
|
||||
->get();
|
||||
|
@ -25,10 +25,11 @@ class ExpenseController extends BaseController
|
||||
// Expenses
|
||||
protected $expenseRepo;
|
||||
protected $expenseService;
|
||||
protected $model = 'App\Models\Expense';
|
||||
|
||||
public function __construct(ExpenseRepository $expenseRepo, ExpenseService $expenseService)
|
||||
{
|
||||
//parent::__construct();
|
||||
// parent::__construct();
|
||||
|
||||
$this->expenseRepo = $expenseRepo;
|
||||
$this->expenseService = $expenseService;
|
||||
@ -44,7 +45,7 @@ class ExpenseController extends BaseController
|
||||
return View::make('list', array(
|
||||
'entityType' => ENTITY_EXPENSE,
|
||||
'title' => trans('texts.expenses'),
|
||||
'sortCol' => '1',
|
||||
'sortCol' => '3',
|
||||
'columns' => Utils::trans([
|
||||
'checkbox',
|
||||
'vendor',
|
||||
@ -70,6 +71,10 @@ class ExpenseController extends BaseController
|
||||
|
||||
public function create($vendorPublicId = null, $clientPublicId = null)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
if($vendorPublicId != 0) {
|
||||
$vendor = Vendor::scope($vendorPublicId)->with('vendorcontacts')->firstOrFail();
|
||||
} else {
|
||||
@ -95,6 +100,11 @@ class ExpenseController extends BaseController
|
||||
public function edit($publicId)
|
||||
{
|
||||
$expense = Expense::scope($publicId)->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($expense, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$expense->expense_date = Utils::fromSqlDate($expense->expense_date);
|
||||
|
||||
$actions = [];
|
||||
|
@ -34,10 +34,11 @@ class InvoiceController extends BaseController
|
||||
protected $clientRepo;
|
||||
protected $invoiceService;
|
||||
protected $recurringInvoiceService;
|
||||
protected $model = 'App\Models\Invoice';
|
||||
|
||||
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, RecurringInvoiceService $recurringInvoiceService)
|
||||
{
|
||||
//parent::__construct();
|
||||
// parent::__construct();
|
||||
|
||||
$this->mailer = $mailer;
|
||||
$this->invoiceRepo = $invoiceRepo;
|
||||
@ -51,6 +52,7 @@ class InvoiceController extends BaseController
|
||||
$data = [
|
||||
'title' => trans('texts.invoices'),
|
||||
'entityType' => ENTITY_INVOICE,
|
||||
'sortCol' => '3',
|
||||
'columns' => Utils::trans([
|
||||
'checkbox',
|
||||
'invoice_number',
|
||||
@ -90,6 +92,11 @@ class InvoiceController extends BaseController
|
||||
->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items')
|
||||
->withTrashed()
|
||||
->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($invoice, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$entityType = $invoice->getEntityType();
|
||||
|
||||
$contactIds = DB::table('invitations')
|
||||
@ -159,6 +166,10 @@ class InvoiceController extends BaseController
|
||||
|
||||
$lastSent = ($invoice->is_recurring && $invoice->last_sent_date) ? $invoice->recurring_invoices->last() : null;
|
||||
|
||||
if(!Auth::user()->hasPermission('view_all')){
|
||||
$clients = $clients->where('clients.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'clients' => $clients->get(),
|
||||
'entityType' => $entityType,
|
||||
@ -206,7 +217,11 @@ class InvoiceController extends BaseController
|
||||
|
||||
public function create($clientPublicId = 0, $isRecurring = false)
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$account = Auth::user()->account;
|
||||
$entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE;
|
||||
$clientId = null;
|
||||
|
||||
@ -217,8 +232,13 @@ class InvoiceController extends BaseController
|
||||
$invoice = $account->createInvoice($entityType, $clientId);
|
||||
$invoice->public_id = 0;
|
||||
|
||||
$clients = Client::scope()->with('contacts', 'country')->orderBy('name');
|
||||
if(!Auth::user()->hasPermission('view_all')){
|
||||
$clients = $clients->where('clients.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(),
|
||||
'clients' => $clients->get(),
|
||||
'entityType' => $invoice->getEntityType(),
|
||||
'invoice' => $invoice,
|
||||
'method' => 'POST',
|
||||
@ -335,10 +355,16 @@ class InvoiceController extends BaseController
|
||||
*/
|
||||
public function store(SaveInvoiceWithClientRequest $request)
|
||||
{
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$action = Input::get('action');
|
||||
$entityType = Input::get('entityType');
|
||||
|
||||
$invoice = $this->invoiceService->save($request->input());
|
||||
$invoice = $this->invoiceService->save($data, true);
|
||||
$entityType = $invoice->getEntityType();
|
||||
$message = trans("texts.created_{$entityType}");
|
||||
|
||||
@ -369,10 +395,16 @@ class InvoiceController extends BaseController
|
||||
*/
|
||||
public function update(SaveInvoiceWithClientRequest $request)
|
||||
{
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$action = Input::get('action');
|
||||
$entityType = Input::get('entityType');
|
||||
|
||||
$invoice = $this->invoiceService->save($request->input());
|
||||
$invoice = $this->invoiceService->save($data, true);
|
||||
$entityType = $invoice->getEntityType();
|
||||
$message = trans("texts.updated_{$entityType}");
|
||||
Session::flash('message', $message);
|
||||
|
@ -30,9 +30,11 @@ use App\Http\Requests\UpdatePaymentRequest;
|
||||
|
||||
class PaymentController extends BaseController
|
||||
{
|
||||
protected $model = 'App\Models\Payment';
|
||||
|
||||
public function __construct(PaymentRepository $paymentRepo, InvoiceRepository $invoiceRepo, AccountRepository $accountRepo, ContactMailer $contactMailer, PaymentService $paymentService)
|
||||
{
|
||||
//parent::__construct();
|
||||
// parent::__construct();
|
||||
|
||||
$this->paymentRepo = $paymentRepo;
|
||||
$this->invoiceRepo = $invoiceRepo;
|
||||
@ -46,6 +48,7 @@ class PaymentController extends BaseController
|
||||
return View::make('list', array(
|
||||
'entityType' => ENTITY_PAYMENT,
|
||||
'title' => trans('texts.payments'),
|
||||
'sortCol' => '6',
|
||||
'columns' => Utils::trans([
|
||||
'checkbox',
|
||||
'invoice',
|
||||
@ -66,6 +69,10 @@ class PaymentController extends BaseController
|
||||
|
||||
public function create($clientPublicId = 0, $invoicePublicId = 0)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$invoices = Invoice::scope()
|
||||
->where('is_recurring', '=', false)
|
||||
->where('is_quote', '=', false)
|
||||
@ -92,6 +99,11 @@ class PaymentController extends BaseController
|
||||
public function edit($publicId)
|
||||
{
|
||||
$payment = Payment::scope($publicId)->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($payment, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$payment->payment_date = Utils::fromSqlDate($payment->payment_date);
|
||||
|
||||
$data = array(
|
||||
@ -573,6 +585,11 @@ class PaymentController extends BaseController
|
||||
public function store(CreatePaymentRequest $request)
|
||||
{
|
||||
$input = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($input, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$input['invoice_id'] = Invoice::getPrivateId($input['invoice']);
|
||||
$input['client_id'] = Client::getPrivateId($input['client']);
|
||||
$payment = $this->paymentRepo->save($input);
|
||||
@ -590,6 +607,11 @@ class PaymentController extends BaseController
|
||||
public function update(UpdatePaymentRequest $request)
|
||||
{
|
||||
$input = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($input, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$payment = $this->paymentRepo->save($input);
|
||||
|
||||
Session::flash('message', trans('texts.updated_payment'));
|
||||
|
@ -33,10 +33,11 @@ class QuoteController extends BaseController
|
||||
protected $invoiceRepo;
|
||||
protected $clientRepo;
|
||||
protected $invoiceService;
|
||||
protected $model = 'App\Models\Invoice';
|
||||
|
||||
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService)
|
||||
{
|
||||
//parent::__construct();
|
||||
// parent::__construct();
|
||||
|
||||
$this->mailer = $mailer;
|
||||
$this->invoiceRepo = $invoiceRepo;
|
||||
@ -53,6 +54,7 @@ class QuoteController extends BaseController
|
||||
$data = [
|
||||
'title' => trans('texts.quotes'),
|
||||
'entityType' => ENTITY_QUOTE,
|
||||
'sortCol' => '3',
|
||||
'columns' => Utils::trans([
|
||||
'checkbox',
|
||||
'quote_number',
|
||||
@ -78,6 +80,10 @@ class QuoteController extends BaseController
|
||||
|
||||
public function create($clientPublicId = 0)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (!Utils::isPro()) {
|
||||
return Redirect::to('/invoices/create');
|
||||
}
|
||||
|
@ -22,10 +22,11 @@ class TaskController extends BaseController
|
||||
{
|
||||
protected $taskRepo;
|
||||
protected $taskService;
|
||||
protected $model = 'App\Models\Task';
|
||||
|
||||
public function __construct(TaskRepository $taskRepo, InvoiceRepository $invoiceRepo, TaskService $taskService)
|
||||
{
|
||||
//parent::__construct();
|
||||
// parent::__construct();
|
||||
|
||||
$this->taskRepo = $taskRepo;
|
||||
$this->invoiceRepo = $invoiceRepo;
|
||||
@ -84,6 +85,9 @@ class TaskController extends BaseController
|
||||
*/
|
||||
public function create($clientPublicId = 0)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
$this->checkTimezone();
|
||||
|
||||
$data = [
|
||||
@ -113,6 +117,10 @@ class TaskController extends BaseController
|
||||
|
||||
$task = Task::scope($publicId)->with('client', 'invoice')->withTrashed()->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($task, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$actions = [];
|
||||
if ($task->invoice) {
|
||||
$actions[] = ['url' => URL::to("invoices/{$task->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")];
|
||||
@ -175,6 +183,10 @@ class TaskController extends BaseController
|
||||
private function save($publicId = null)
|
||||
{
|
||||
$action = Input::get('action');
|
||||
|
||||
if(!$this->checkUpdatePermission(array('public_id'=>$publicId)/* Hacky, but works */, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (in_array($action, ['archive', 'delete', 'restore'])) {
|
||||
return self::bulk();
|
||||
|
@ -192,6 +192,8 @@ class UserController extends BaseController
|
||||
$user->last_name = trim(Input::get('last_name'));
|
||||
$user->username = trim(Input::get('email'));
|
||||
$user->email = trim(Input::get('email'));
|
||||
$user->is_admin = boolval(Input::get('is_admin'));
|
||||
$user->permissions = Input::get('permissions');
|
||||
} else {
|
||||
$lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id)
|
||||
->orderBy('public_id', 'DESC')->first();
|
||||
@ -202,10 +204,12 @@ class UserController extends BaseController
|
||||
$user->last_name = trim(Input::get('last_name'));
|
||||
$user->username = trim(Input::get('email'));
|
||||
$user->email = trim(Input::get('email'));
|
||||
$user->is_admin = boolval(Input::get('is_admin'));
|
||||
$user->registered = true;
|
||||
$user->password = str_random(RANDOM_KEY_LENGTH);
|
||||
$user->confirmation_code = str_random(RANDOM_KEY_LENGTH);
|
||||
$user->public_id = $lastUser->public_id + 1;
|
||||
$user->permissions = Input::get('permissions');
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
@ -30,6 +30,7 @@ class VendorController extends BaseController
|
||||
{
|
||||
protected $vendorService;
|
||||
protected $vendorRepo;
|
||||
protected $model = 'App\Models\Vendor';
|
||||
|
||||
public function __construct(VendorRepository $vendorRepo, VendorService $vendorService)
|
||||
{
|
||||
@ -76,7 +77,13 @@ class VendorController extends BaseController
|
||||
*/
|
||||
public function store(CreateVendorRequest $request)
|
||||
{
|
||||
$vendor = $this->vendorService->save($request->input());
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$vendor = $this->vendorService->save($data);
|
||||
|
||||
Session::flash('message', trans('texts.created_vendor'));
|
||||
|
||||
@ -92,6 +99,11 @@ class VendorController extends BaseController
|
||||
public function show($publicId)
|
||||
{
|
||||
$vendor = Vendor::withTrashed()->scope($publicId)->with('vendorcontacts', 'size', 'industry')->firstOrFail();
|
||||
|
||||
if(!$this->checkViewPermission($vendor, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
Utils::trackViewed($vendor->getDisplayName(), 'vendor');
|
||||
|
||||
$actionLinks = [
|
||||
@ -119,6 +131,10 @@ class VendorController extends BaseController
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (Vendor::scope()->count() > Auth::user()->getMaxNumVendors()) {
|
||||
return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumVendors()." vendors"]);
|
||||
}
|
||||
@ -144,6 +160,11 @@ class VendorController extends BaseController
|
||||
public function edit($publicId)
|
||||
{
|
||||
$vendor = Vendor::scope($publicId)->with('vendorcontacts')->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($vendor, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'vendor' => $vendor,
|
||||
'method' => 'PUT',
|
||||
@ -180,7 +201,13 @@ class VendorController extends BaseController
|
||||
*/
|
||||
public function update(UpdateVendorRequest $request)
|
||||
{
|
||||
$vendor = $this->vendorService->save($request->input());
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$vendor = $this->vendorService->save($data);
|
||||
|
||||
Session::flash('message', trans('texts.updated_vendor'));
|
||||
|
||||
|
@ -28,6 +28,7 @@ class Kernel extends HttpKernel {
|
||||
protected $routeMiddleware = [
|
||||
'auth' => 'App\Http\Middleware\Authenticate',
|
||||
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
|
||||
'permissions.required' => 'App\Http\Middleware\PermissionsRequired',
|
||||
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
|
||||
'api' => 'App\Http\Middleware\ApiCheck',
|
||||
];
|
||||
|
57
app/Http/Middleware/PermissionsRequired.php
Normal file
57
app/Http/Middleware/PermissionsRequired.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Auth;
|
||||
|
||||
class PermissionsRequired {
|
||||
/**
|
||||
* @var array of controller => [action => permission]
|
||||
*/
|
||||
static protected $actions = [];
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next, $guard = 'user')
|
||||
{
|
||||
// Get the current route.
|
||||
$route = $request->route();
|
||||
|
||||
// Get the current route actions.
|
||||
$actions = $route->getAction();
|
||||
|
||||
// Check if we have any permissions to check the user has.
|
||||
if ($permissions = !empty($actions['permissions']) ? $actions['permissions'] : null)
|
||||
{
|
||||
if(!Auth::user($guard)->hasPermission($permissions, !empty($actions['permissions_require_all']))){
|
||||
return response('Unauthorized.', 401);
|
||||
}
|
||||
}
|
||||
|
||||
// Check controller permissions
|
||||
$action = explode('@', $request->route()->getActionName());
|
||||
if(isset(static::$actions[$action[0]]) && isset(static::$actions[$action[0]][$action[1]])) {
|
||||
$controller_permissions = static::$actions[$action[0]][$action[1]];
|
||||
if(!Auth::user($guard)->hasPermission($controller_permissions)){
|
||||
return response('Unauthorized.', 401);
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* add a controller's action permission
|
||||
*
|
||||
* @param \App\Http\Controllers\Controller $controller
|
||||
* @param array $permissions
|
||||
*/
|
||||
public static function addPermission(\App\Http\Controllers\Controller $controller, $permissions)
|
||||
{
|
||||
static::$actions[get_class($controller)] = $permissions;
|
||||
}
|
||||
}
|
@ -104,62 +104,9 @@ Route::group(['middleware' => 'auth:user'], function() {
|
||||
Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible');
|
||||
Route::get('hide_message', 'HomeController@hideMessage');
|
||||
Route::get('force_inline_pdf', 'UserController@forcePDFJS');
|
||||
|
||||
Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable'));
|
||||
Route::resource('users', 'UserController');
|
||||
Route::post('users/bulk', 'UserController@bulk');
|
||||
Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation');
|
||||
Route::get('start_trial', 'AccountController@startTrial');
|
||||
Route::get('restore_user/{user_id}', 'UserController@restoreUser');
|
||||
Route::post('users/change_password', 'UserController@changePassword');
|
||||
Route::get('/switch_account/{user_id}', 'UserController@switchAccount');
|
||||
Route::get('/unlink_account/{user_account_id}/{user_id}', 'UserController@unlinkAccount');
|
||||
Route::get('/manage_companies', 'UserController@manageCompanies');
|
||||
|
||||
Route::get('api/tokens', array('as'=>'api.tokens', 'uses'=>'TokenController@getDatatable'));
|
||||
Route::resource('tokens', 'TokenController');
|
||||
Route::post('tokens/bulk', 'TokenController@bulk');
|
||||
|
||||
Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable'));
|
||||
Route::resource('products', 'ProductController');
|
||||
Route::post('products/bulk', 'ProductController@bulk');
|
||||
|
||||
Route::get('api/tax_rates', array('as'=>'api.tax_rates', 'uses'=>'TaxRateController@getDatatable'));
|
||||
Route::resource('tax_rates', 'TaxRateController');
|
||||
Route::post('tax_rates/bulk', 'TaxRateController@bulk');
|
||||
|
||||
Route::get('company/{section}/{subSection?}', 'AccountController@redirectLegacy');
|
||||
Route::get('settings/data_visualizations', 'ReportController@d3');
|
||||
Route::get('settings/charts_and_reports', 'ReportController@showReports');
|
||||
Route::post('settings/charts_and_reports', 'ReportController@showReports');
|
||||
|
||||
Route::post('settings/cancel_account', 'AccountController@cancelAccount');
|
||||
Route::post('settings/company_details', 'AccountController@updateDetails');
|
||||
Route::get('settings/{section?}', 'AccountController@showSection');
|
||||
Route::post('settings/{section?}', 'AccountController@doSection');
|
||||
|
||||
//Route::get('api/payment_terms', array('as'=>'api.payment_terms', 'uses'=>'PaymentTermController@getDatatable'));
|
||||
//Route::resource('payment_terms', 'PaymentTermController');
|
||||
//Route::post('payment_terms/bulk', 'PaymentTermController@bulk');
|
||||
|
||||
Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData'));
|
||||
Route::post('user/setTheme', 'UserController@setTheme');
|
||||
Route::post('remove_logo', 'AccountController@removeLogo');
|
||||
Route::post('account/go_pro', 'AccountController@enableProPlan');
|
||||
|
||||
Route::post('/export', 'ExportController@doExport');
|
||||
Route::post('/import', 'ImportController@doImport');
|
||||
Route::post('/import_csv', 'ImportController@doImportCSV');
|
||||
|
||||
Route::resource('gateways', 'AccountGatewayController');
|
||||
Route::get('api/gateways', array('as'=>'api.gateways', 'uses'=>'AccountGatewayController@getDatatable'));
|
||||
Route::post('account_gateways/bulk', 'AccountGatewayController@bulk');
|
||||
|
||||
Route::resource('bank_accounts', 'BankAccountController');
|
||||
Route::get('api/bank_accounts', array('as'=>'api.bank_accounts', 'uses'=>'BankAccountController@getDatatable'));
|
||||
Route::post('bank_accounts/bulk', 'BankAccountController@bulk');
|
||||
Route::post('bank_accounts/validate', 'BankAccountController@validateAccount');
|
||||
Route::post('bank_accounts/import_expenses/{bank_id}', 'BankAccountController@importExpenses');
|
||||
|
||||
Route::get('settings/user_details', 'AccountController@showUserDetails');
|
||||
Route::post('settings/user_details', 'AccountController@saveUserDetails');
|
||||
|
||||
Route::resource('clients', 'ClientController');
|
||||
Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable'));
|
||||
@ -222,6 +169,67 @@ Route::group(['middleware' => 'auth:user'], function() {
|
||||
Route::post('expenses/bulk', 'ExpenseController@bulk');
|
||||
});
|
||||
|
||||
Route::group([
|
||||
'middleware' => ['auth:user', 'permissions.required'],
|
||||
'permissions' => 'admin',
|
||||
], function() {
|
||||
Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable'));
|
||||
Route::resource('users', 'UserController');
|
||||
Route::post('users/bulk', 'UserController@bulk');
|
||||
Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation');
|
||||
Route::get('start_trial', 'AccountController@startTrial');
|
||||
Route::get('restore_user/{user_id}', 'UserController@restoreUser');
|
||||
Route::post('users/change_password', 'UserController@changePassword');
|
||||
Route::get('/switch_account/{user_id}', 'UserController@switchAccount');
|
||||
Route::get('/unlink_account/{user_account_id}/{user_id}', 'UserController@unlinkAccount');
|
||||
Route::get('/manage_companies', 'UserController@manageCompanies');
|
||||
|
||||
Route::get('api/tokens', array('as'=>'api.tokens', 'uses'=>'TokenController@getDatatable'));
|
||||
Route::resource('tokens', 'TokenController');
|
||||
Route::post('tokens/bulk', 'TokenController@bulk');
|
||||
|
||||
Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable'));
|
||||
Route::resource('products', 'ProductController');
|
||||
Route::post('products/bulk', 'ProductController@bulk');
|
||||
|
||||
Route::get('api/tax_rates', array('as'=>'api.tax_rates', 'uses'=>'TaxRateController@getDatatable'));
|
||||
Route::resource('tax_rates', 'TaxRateController');
|
||||
Route::post('tax_rates/bulk', 'TaxRateController@bulk');
|
||||
|
||||
Route::get('company/{section}/{subSection?}', 'AccountController@redirectLegacy');
|
||||
Route::get('settings/data_visualizations', 'ReportController@d3');
|
||||
Route::get('settings/charts_and_reports', 'ReportController@showReports');
|
||||
Route::post('settings/charts_and_reports', 'ReportController@showReports');
|
||||
|
||||
Route::post('settings/cancel_account', 'AccountController@cancelAccount');
|
||||
Route::post('settings/company_details', 'AccountController@updateDetails');
|
||||
Route::get('settings/{section?}', 'AccountController@showSection');
|
||||
Route::post('settings/{section?}', 'AccountController@doSection');
|
||||
|
||||
//Route::get('api/payment_terms', array('as'=>'api.payment_terms', 'uses'=>'PaymentTermController@getDatatable'));
|
||||
//Route::resource('payment_terms', 'PaymentTermController');
|
||||
//Route::post('payment_terms/bulk', 'PaymentTermController@bulk');
|
||||
|
||||
Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData'));
|
||||
Route::post('user/setTheme', 'UserController@setTheme');
|
||||
Route::post('remove_logo', 'AccountController@removeLogo');
|
||||
Route::post('account/go_pro', 'AccountController@enableProPlan');
|
||||
|
||||
Route::post('/export', 'ExportController@doExport');
|
||||
Route::post('/import', 'ImportController@doImport');
|
||||
Route::post('/import_csv', 'ImportController@doImportCSV');
|
||||
|
||||
Route::resource('gateways', 'AccountGatewayController');
|
||||
Route::get('api/gateways', array('as'=>'api.gateways', 'uses'=>'AccountGatewayController@getDatatable'));
|
||||
Route::post('account_gateways/bulk', 'AccountGatewayController@bulk');
|
||||
|
||||
Route::resource('bank_accounts', 'BankAccountController');
|
||||
Route::get('api/bank_accounts', array('as'=>'api.bank_accounts', 'uses'=>'BankAccountController@getDatatable'));
|
||||
Route::post('bank_accounts/bulk', 'BankAccountController@bulk');
|
||||
Route::post('bank_accounts/validate', 'BankAccountController@validateAccount');
|
||||
Route::post('bank_accounts/import_expenses/{bank_id}', 'BankAccountController@importExpenses');
|
||||
});
|
||||
|
||||
// Route groups for API
|
||||
Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
|
||||
{
|
||||
@ -500,6 +508,8 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('GATEWAY_PAYFAST', 13);
|
||||
define('GATEWAY_PAYPAL_EXPRESS', 17);
|
||||
define('GATEWAY_PAYPAL_PRO', 18);
|
||||
define('GATEWAY_SAGE_PAY_DIRECT', 20);
|
||||
define('GATEWAY_SAGE_PAY_SERVER', 21);
|
||||
define('GATEWAY_STRIPE', 23);
|
||||
define('GATEWAY_GOCARDLESS', 6);
|
||||
define('GATEWAY_TWO_CHECKOUT', 27);
|
||||
@ -604,6 +614,7 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('USER_STATE_PENDING', 'pending');
|
||||
define('USER_STATE_DISABLED', 'disabled');
|
||||
define('USER_STATE_ADMIN', 'admin');
|
||||
define('USER_STATE_OWNER', 'owner');
|
||||
|
||||
define('API_SERIALIZER_ARRAY', 'array');
|
||||
define('API_SERIALIZER_JSON', 'json');
|
||||
|
@ -118,6 +118,21 @@ class Utils
|
||||
return Auth::check() && Auth::user()->isPro();
|
||||
}
|
||||
|
||||
public static function isAdmin()
|
||||
{
|
||||
return Auth::check() && Auth::user()->is_admin;
|
||||
}
|
||||
|
||||
public static function hasPermission($permission, $requireAll = false)
|
||||
{
|
||||
return Auth::check() && Auth::user()->hasPermission($permission, $requireAll);
|
||||
}
|
||||
|
||||
public static function hasAllPermissions($permission)
|
||||
{
|
||||
return Auth::check() && Auth::user()->hasPermissions($permission);
|
||||
}
|
||||
|
||||
public static function isTrial()
|
||||
{
|
||||
return Auth::check() && Auth::user()->isTrial();
|
||||
|
@ -683,7 +683,7 @@ class Account extends Eloquent
|
||||
'subtotal',
|
||||
'paid_to_date',
|
||||
'balance_due',
|
||||
'amount_due',
|
||||
'partial_due',
|
||||
'terms',
|
||||
'your_invoice',
|
||||
'quote',
|
||||
|
@ -113,4 +113,56 @@ class EntityModel extends Eloquent
|
||||
$name = $parts[count($parts)-1];
|
||||
return strtolower($name) . '_id';
|
||||
}
|
||||
|
||||
public static function canCreate() {
|
||||
return Auth::user()->hasPermission('create_all');
|
||||
}
|
||||
|
||||
public function canEdit() {
|
||||
return static::canEditItem($this);
|
||||
}
|
||||
|
||||
public static function canEditItem($item) {
|
||||
return Auth::user()->hasPermission('edit_all') || (isset($item->user_id) && Auth::user()->id == $item->user_id);
|
||||
}
|
||||
|
||||
public static function canEditItemById($item_id) {
|
||||
if(Auth::user()->hasPermission('edit_all')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return static::whereId($item_id)->first()->user_id == Auth::user()->id;
|
||||
}
|
||||
|
||||
public static function canEditItemByOwner($user_id) {
|
||||
if(Auth::user()->hasPermission('edit_all')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Auth::user()->id == $user_id;
|
||||
}
|
||||
|
||||
public function canView() {
|
||||
return static::canViewItem($this);
|
||||
}
|
||||
|
||||
public static function canViewItem($item) {
|
||||
return Auth::user()->hasPermission('view_all') || (isset($item->user_id) && Auth::user()->id == $item->user_id);
|
||||
}
|
||||
|
||||
public static function canViewItemById($item_id) {
|
||||
if(Auth::user()->hasPermission('view_all')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return static::whereId($item_id)->first()->user_id == Auth::user()->id;
|
||||
}
|
||||
|
||||
public static function canViewItemByOwner($user_id) {
|
||||
if(Auth::user()->hasPermission('view_all')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Auth::user()->id == $user_id;
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +75,8 @@ class Gateway extends Eloquent
|
||||
$link = 'https://bitpay.com/dashboard/signup';
|
||||
} elseif ($this->id == GATEWAY_DWOLLA) {
|
||||
$link = 'https://www.dwolla.com/register';
|
||||
} elseif ($this->id == GATEWAY_SAGE_PAY_DIRECT || $this->id == GATEWAY_SAGE_PAY_SERVER) {
|
||||
$link = 'https://applications.sagepay.com/apply/2C02C252-0F8A-1B84-E10D-CF933EFCAA99';
|
||||
}
|
||||
|
||||
$key = 'texts.gateway_help_'.$this->id;
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php namespace App\Models;
|
||||
|
||||
use Auth;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Product extends EntityModel
|
||||
@ -21,4 +22,8 @@ class Product extends EntityModel
|
||||
{
|
||||
return $this->belongsTo('App\Models\TaxRate');
|
||||
}
|
||||
|
||||
public function canEdit() {
|
||||
return Auth::user()->hasPermission('admin');
|
||||
}
|
||||
}
|
||||
|
@ -16,4 +16,8 @@ class TaxRate extends EntityModel
|
||||
{
|
||||
return ENTITY_TAX_RATE;
|
||||
}
|
||||
|
||||
public function canEdit() {
|
||||
return Auth::user()->hasPermission('admin');
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,12 @@ use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
|
||||
|
||||
public static $all_permissions = array(
|
||||
'create_all' => 0b0001,
|
||||
'view_all' => 0b0010,
|
||||
'edit_all' => 0b0100,
|
||||
);
|
||||
|
||||
use Authenticatable, CanResetPassword;
|
||||
|
||||
/**
|
||||
@ -253,7 +258,69 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||
&& $this->email != $this->getOriginal('email')
|
||||
&& $this->getOriginal('confirmed');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the permissions attribute on the model.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return $this
|
||||
*/
|
||||
protected function setPermissionsAttribute($value){
|
||||
if(empty($value)) {
|
||||
$this->attributes['permissions'] = 0;
|
||||
} else {
|
||||
$bitmask = 0;
|
||||
foreach($value as $permission){
|
||||
$bitmask = $bitmask | static::$all_permissions[$permission];
|
||||
}
|
||||
|
||||
$this->attributes['permissions'] = $bitmask;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the value of the permissions attribute
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getPermissionsAttribute($value){
|
||||
$permissions = array();
|
||||
foreach(static::$all_permissions as $permission => $bitmask){
|
||||
if(($value & $bitmask) == $bitmask) {
|
||||
$permissions[$permission] = $permission;
|
||||
}
|
||||
}
|
||||
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the user has the required permission
|
||||
*
|
||||
* @param mixed $permission Either a single permission or an array of possible permissions
|
||||
* @param boolean True to require all permissions, false to require only one
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasPermission($permission, $requireAll = false){
|
||||
if ($this->is_admin) {
|
||||
return true;
|
||||
} else if(is_string($permission)){
|
||||
return !empty($this->permissions[$permission]);
|
||||
} else if(is_array($permission)) {
|
||||
if($requireAll){
|
||||
return count(array_diff($permission, $this->permissions)) == 0;
|
||||
} else {
|
||||
return count(array_intersect($permission, $this->permissions)) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
User::updating(function ($user) {
|
||||
|
@ -19,7 +19,7 @@ class InvoicePresenter extends Presenter {
|
||||
public function balanceDueLabel()
|
||||
{
|
||||
if ($this->entity->partial) {
|
||||
return 'amount_due';
|
||||
return 'partial_due';
|
||||
} elseif ($this->entity->is_quote) {
|
||||
return 'total';
|
||||
} else {
|
||||
|
@ -46,7 +46,8 @@ class ClientRepository extends BaseRepository
|
||||
'clients.work_phone',
|
||||
'contacts.email',
|
||||
'clients.deleted_at',
|
||||
'clients.is_deleted'
|
||||
'clients.is_deleted',
|
||||
'clients.user_id'
|
||||
);
|
||||
|
||||
if (!\Session::get('show_trash:client')) {
|
||||
|
@ -29,6 +29,7 @@ class CreditRepository extends BaseRepository
|
||||
'credits.public_id',
|
||||
'clients.name as client_name',
|
||||
'clients.public_id as client_public_id',
|
||||
'clients.user_id as client_user_id',
|
||||
'credits.amount',
|
||||
'credits.balance',
|
||||
'credits.credit_date',
|
||||
@ -37,7 +38,8 @@ class CreditRepository extends BaseRepository
|
||||
'contacts.email',
|
||||
'credits.private_notes',
|
||||
'credits.deleted_at',
|
||||
'credits.is_deleted'
|
||||
'credits.is_deleted',
|
||||
'credits.user_id'
|
||||
);
|
||||
|
||||
if ($clientPublicId) {
|
||||
|
@ -40,7 +40,8 @@ class ExpenseRepository extends BaseRepository
|
||||
'expenses.public_id',
|
||||
'expenses.deleted_at',
|
||||
'expenses.should_be_invoiced',
|
||||
'expenses.created_at'
|
||||
'expenses.created_at',
|
||||
'expenses.user_id'
|
||||
);
|
||||
|
||||
return $query;
|
||||
@ -80,11 +81,15 @@ class ExpenseRepository extends BaseRepository
|
||||
'expenses.vendor_id',
|
||||
'expenses.expense_currency_id',
|
||||
'expenses.invoice_currency_id',
|
||||
'expenses.user_id',
|
||||
'invoices.public_id as invoice_public_id',
|
||||
'invoices.user_id as invoice_user_id',
|
||||
'vendors.name as vendor_name',
|
||||
'vendors.public_id as vendor_public_id',
|
||||
'vendors.user_id as vendor_user_id',
|
||||
'clients.name as client_name',
|
||||
'clients.public_id as client_public_id',
|
||||
'clients.user_id as client_user_id',
|
||||
'contacts.first_name',
|
||||
'contacts.email',
|
||||
'contacts.last_name',
|
||||
|
@ -49,6 +49,7 @@ class InvoiceRepository extends BaseRepository
|
||||
DB::raw('COALESCE(clients.currency_id, accounts.currency_id) currency_id'),
|
||||
DB::raw('COALESCE(clients.country_id, accounts.country_id) country_id'),
|
||||
'clients.public_id as client_public_id',
|
||||
'clients.user_id as client_user_id',
|
||||
'invoice_number',
|
||||
'invoice_status_id',
|
||||
'clients.name as client_name',
|
||||
@ -65,7 +66,8 @@ class InvoiceRepository extends BaseRepository
|
||||
'invoices.quote_invoice_id',
|
||||
'invoices.deleted_at',
|
||||
'invoices.is_deleted',
|
||||
'invoices.partial'
|
||||
'invoices.partial',
|
||||
'invoices.user_id'
|
||||
);
|
||||
|
||||
if (!\Session::get('show_trash:'.$entityType)) {
|
||||
@ -189,7 +191,7 @@ class InvoiceRepository extends BaseRepository
|
||||
->make();
|
||||
}
|
||||
|
||||
public function save($data)
|
||||
public function save($data, $checkSubPermissions = false)
|
||||
{
|
||||
$account = \Auth::user()->account;
|
||||
$publicId = isset($data['public_id']) ? $data['public_id'] : false;
|
||||
@ -405,29 +407,40 @@ class InvoiceRepository extends BaseRepository
|
||||
$task = false;
|
||||
if (isset($item['task_public_id']) && $item['task_public_id']) {
|
||||
$task = Task::scope($item['task_public_id'])->where('invoice_id', '=', null)->firstOrFail();
|
||||
$task->invoice_id = $invoice->id;
|
||||
$task->client_id = $invoice->client_id;
|
||||
$task->save();
|
||||
if(!$checkSubPermissions || $task->canEdit()){
|
||||
$task->invoice_id = $invoice->id;
|
||||
$task->client_id = $invoice->client_id;
|
||||
$task->save();
|
||||
}
|
||||
}
|
||||
|
||||
$expense = false;
|
||||
if (isset($item['expense_public_id']) && $item['expense_public_id']) {
|
||||
$expense = Expense::scope($item['expense_public_id'])->where('invoice_id', '=', null)->firstOrFail();
|
||||
$expense->invoice_id = $invoice->id;
|
||||
$expense->client_id = $invoice->client_id;
|
||||
$expense->save();
|
||||
if(!$checkSubPermissions || $expense->canEdit()){
|
||||
$expense->invoice_id = $invoice->id;
|
||||
$expense->client_id = $invoice->client_id;
|
||||
$expense->save();
|
||||
}
|
||||
}
|
||||
|
||||
if ($productKey = trim($item['product_key'])) {
|
||||
if (\Auth::user()->account->update_products && ! strtotime($productKey)) {
|
||||
$product = Product::findProductByKey($productKey);
|
||||
if (!$product) {
|
||||
$product = Product::createNew();
|
||||
$product->product_key = trim($item['product_key']);
|
||||
if(!$checkSubPermissions || Product::canCreate()){
|
||||
$product = Product::createNew();
|
||||
$product->product_key = trim($item['product_key']);
|
||||
}
|
||||
else{
|
||||
$product = null;
|
||||
}
|
||||
}
|
||||
if($product && (!$checkSubPermissions || $product->canEdit())){
|
||||
$product->notes = ($task || $expense) ? '' : $item['notes'];
|
||||
$product->cost = $expense ? 0 : $item['cost'];
|
||||
$product->save();
|
||||
}
|
||||
$product->notes = ($task || $expense) ? '' : $item['notes'];
|
||||
$product->cost = $expense ? 0 : $item['cost'];
|
||||
$product->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,9 +36,11 @@ class PaymentRepository extends BaseRepository
|
||||
'payments.transaction_reference',
|
||||
'clients.name as client_name',
|
||||
'clients.public_id as client_public_id',
|
||||
'clients.user_id as client_user_id',
|
||||
'payments.amount',
|
||||
'payments.payment_date',
|
||||
'invoices.public_id as invoice_public_id',
|
||||
'invoices.user_id as invoice_user_id',
|
||||
'invoices.invoice_number',
|
||||
'contacts.first_name',
|
||||
'contacts.last_name',
|
||||
@ -47,6 +49,7 @@ class PaymentRepository extends BaseRepository
|
||||
'payments.account_gateway_id',
|
||||
'payments.deleted_at',
|
||||
'payments.is_deleted',
|
||||
'payments.user_id',
|
||||
'invoices.is_deleted as invoice_is_deleted',
|
||||
'gateways.name as gateway_name'
|
||||
);
|
||||
|
@ -27,6 +27,7 @@ class TaskRepository
|
||||
'tasks.public_id',
|
||||
'clients.name as client_name',
|
||||
'clients.public_id as client_public_id',
|
||||
'clients.user_id as client_user_id',
|
||||
'contacts.first_name',
|
||||
'contacts.email',
|
||||
'contacts.last_name',
|
||||
@ -36,9 +37,11 @@ class TaskRepository
|
||||
'tasks.deleted_at',
|
||||
'invoices.invoice_number',
|
||||
'invoices.public_id as invoice_public_id',
|
||||
'invoices.user_id as invoice_user_id',
|
||||
'tasks.is_running',
|
||||
'tasks.time_log',
|
||||
'tasks.created_at'
|
||||
'tasks.created_at',
|
||||
'tasks.user_id'
|
||||
);
|
||||
|
||||
if ($clientPublicId) {
|
||||
|
@ -22,7 +22,7 @@ class UserRepository extends BaseRepository
|
||||
$query->where('users.deleted_at', '=', null);
|
||||
}
|
||||
|
||||
$query->select('users.public_id', 'users.first_name', 'users.last_name', 'users.email', 'users.confirmed', 'users.public_id', 'users.deleted_at');
|
||||
$query->select('users.public_id', 'users.first_name', 'users.last_name', 'users.email', 'users.confirmed', 'users.public_id', 'users.deleted_at', 'users.is_admin', 'users.permissions');
|
||||
|
||||
return $query;
|
||||
}
|
||||
@ -34,5 +34,4 @@ class UserRepository extends BaseRepository
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,7 +42,8 @@ class VendorRepository extends BaseRepository
|
||||
'vendors.city',
|
||||
'vendor_contacts.email',
|
||||
'vendors.deleted_at',
|
||||
'vendors.is_deleted'
|
||||
'vendors.is_deleted',
|
||||
'vendors.user_id'
|
||||
);
|
||||
|
||||
if (!\Session::get('show_trash:vendor')) {
|
||||
|
@ -8,6 +8,9 @@ use Form;
|
||||
use URL;
|
||||
use Request;
|
||||
use Validator;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Vendor;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider {
|
||||
@ -46,31 +49,38 @@ class AppServiceProvider extends ServiceProvider {
|
||||
$class = ( Request::is($types) || Request::is('*'.$type.'*')) && !Request::is('*settings*') ? ' active' : '';
|
||||
|
||||
$str = '<li class="dropdown '.$class.'">
|
||||
<a href="'.URL::to($types).'" class="dropdown-toggle">'.trans("texts.$types").'</a>
|
||||
<ul class="dropdown-menu" id="menu1">
|
||||
<li><a href="'.URL::to($types.'/create').'">'.trans("texts.new_$type").'</a></li>';
|
||||
|
||||
<a href="'.URL::to($types).'" class="dropdown-toggle">'.trans("texts.$types").'</a>';
|
||||
|
||||
$items = [];
|
||||
|
||||
if(Auth::user()->hasPermission('create_all')){
|
||||
$items[] = '<li><a href="'.URL::to($types.'/create').'">'.trans("texts.new_$type").'</a></li>';
|
||||
}
|
||||
|
||||
if ($type == ENTITY_INVOICE) {
|
||||
$str .= '<li class="divider"></li>
|
||||
<li><a href="'.URL::to('recurring_invoices').'">'.trans("texts.recurring_invoices").'</a></li>
|
||||
<li><a href="'.URL::to('recurring_invoices/create').'">'.trans("texts.new_recurring_invoice").'</a></li>';
|
||||
if(!empty($items))$items[] = '<li class="divider"></li>';
|
||||
$items[] = '<li><a href="'.URL::to('recurring_invoices').'">'.trans("texts.recurring_invoices").'</a></li>';
|
||||
if(Invoice::canCreate())$items[] = '<li><a href="'.URL::to('recurring_invoices/create').'">'.trans("texts.new_recurring_invoice").'</a></li>';
|
||||
if (Auth::user()->isPro()) {
|
||||
$str .= '<li class="divider"></li>
|
||||
<li><a href="'.URL::to('quotes').'">'.trans("texts.quotes").'</a></li>
|
||||
<li><a href="'.URL::to('quotes/create').'">'.trans("texts.new_quote").'</a></li>';
|
||||
$items[] = '<li class="divider"></li>';
|
||||
$items[] = '<li><a href="'.URL::to('quotes').'">'.trans("texts.quotes").'</a></li>';
|
||||
if(Invoice::canCreate())$items[] = '<li><a href="'.URL::to('quotes/create').'">'.trans("texts.new_quote").'</a></li>';
|
||||
}
|
||||
} else if ($type == ENTITY_CLIENT) {
|
||||
$str .= '<li class="divider"></li>
|
||||
<li><a href="'.URL::to('credits').'">'.trans("texts.credits").'</a></li>
|
||||
<li><a href="'.URL::to('credits/create').'">'.trans("texts.new_credit").'</a></li>';
|
||||
if(!empty($items))$items[] = '<li class="divider"></li>';
|
||||
$items[] = '<li><a href="'.URL::to('credits').'">'.trans("texts.credits").'</a></li>';
|
||||
if(Credit::canCreate())$items[] = '<li><a href="'.URL::to('credits/create').'">'.trans("texts.new_credit").'</a></li>';
|
||||
} else if ($type == ENTITY_EXPENSE) {
|
||||
$str .= '<li class="divider"></li>
|
||||
<li><a href="'.URL::to('vendors').'">'.trans("texts.vendors").'</a></li>
|
||||
<li><a href="'.URL::to('vendors/create').'">'.trans("texts.new_vendor").'</a></li>';
|
||||
if(!empty($items))$items[] = '<li class="divider"></li>';
|
||||
$items[] = '<li><a href="'.URL::to('vendors').'">'.trans("texts.vendors").'</a></li>';
|
||||
if(Vendor::canCreate())$items[] = '<li><a href="'.URL::to('vendors/create').'">'.trans("texts.new_vendor").'</a></li>';
|
||||
}
|
||||
|
||||
if(!empty($items)){
|
||||
$str.= '<ul class="dropdown-menu" id="menu1">'.implode($items).'</ul>';
|
||||
}
|
||||
|
||||
$str .= '</ul>
|
||||
</li>';
|
||||
$str .= '</li>';
|
||||
|
||||
return $str;
|
||||
});
|
||||
|
@ -14,14 +14,16 @@ class BaseService
|
||||
|
||||
public function bulk($ids, $action)
|
||||
{
|
||||
if ( ! $ids) {
|
||||
if ( ! $ids ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$entities = $this->getRepo()->findByPublicIdsWithTrashed($ids);
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
$this->getRepo()->$action($entity);
|
||||
if($entity->canEdit()){
|
||||
$this->getRepo()->$action($entity);
|
||||
}
|
||||
}
|
||||
|
||||
return count($entities);
|
||||
|
@ -4,6 +4,12 @@ use Utils;
|
||||
use URL;
|
||||
use Auth;
|
||||
use App\Services\BaseService;
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Task;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Ninja\Repositories\NinjaRepository;
|
||||
|
||||
@ -37,6 +43,10 @@ class ClientService extends BaseService
|
||||
{
|
||||
$query = $this->clientRepo->find($search);
|
||||
|
||||
if(!Utils::hasPermission('view_all')){
|
||||
$query->where('clients.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
return $this->createDatatable(ENTITY_CLIENT, $query);
|
||||
}
|
||||
|
||||
@ -89,19 +99,33 @@ class ClientService extends BaseService
|
||||
trans('texts.edit_client'),
|
||||
function ($model) {
|
||||
return URL::to("clients/{$model->public_id}/edit");
|
||||
},
|
||||
function ($model) {
|
||||
return Client::canEditItem($model);
|
||||
}
|
||||
],
|
||||
[
|
||||
'--divider--', function(){return false;},
|
||||
function ($model) {
|
||||
return Client::canEditItem($model) && (Task::canCreate() || Invoice::canCreate());
|
||||
}
|
||||
],
|
||||
[],
|
||||
[
|
||||
trans('texts.new_task'),
|
||||
function ($model) {
|
||||
return URL::to("tasks/create/{$model->public_id}");
|
||||
},
|
||||
function ($model) {
|
||||
return Task::canCreate();
|
||||
}
|
||||
],
|
||||
[
|
||||
trans('texts.new_invoice'),
|
||||
function ($model) {
|
||||
return URL::to("invoices/create/{$model->public_id}");
|
||||
},
|
||||
function ($model) {
|
||||
return Invoice::canCreate();
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -110,26 +134,40 @@ class ClientService extends BaseService
|
||||
return URL::to("quotes/create/{$model->public_id}");
|
||||
},
|
||||
function ($model) {
|
||||
return Auth::user()->isPro();
|
||||
return Auth::user()->isPro() && Invoice::canCreate();
|
||||
}
|
||||
],
|
||||
[
|
||||
'--divider--', function(){return false;},
|
||||
function ($model) {
|
||||
return (Task::canCreate() || Invoice::canCreate()) && (Payment::canCreate() || Credit::canCreate() || Expense::canCreate());
|
||||
}
|
||||
],
|
||||
[],
|
||||
[
|
||||
trans('texts.enter_payment'),
|
||||
function ($model) {
|
||||
return URL::to("payments/create/{$model->public_id}");
|
||||
},
|
||||
function ($model) {
|
||||
return Payment::canCreate();
|
||||
}
|
||||
],
|
||||
[
|
||||
trans('texts.enter_credit'),
|
||||
function ($model) {
|
||||
return URL::to("credits/create/{$model->public_id}");
|
||||
},
|
||||
function ($model) {
|
||||
return Credit::canCreate();
|
||||
}
|
||||
],
|
||||
[
|
||||
trans('texts.enter_expense'),
|
||||
function ($model) {
|
||||
return URL::to("expenses/create/0/{$model->public_id}");
|
||||
},
|
||||
function ($model) {
|
||||
return Expense::canCreate();
|
||||
}
|
||||
]
|
||||
];
|
||||
|
@ -2,7 +2,10 @@
|
||||
|
||||
use Utils;
|
||||
use URL;
|
||||
use Auth;
|
||||
use App\Services\BaseService;
|
||||
use App\Models\Client;
|
||||
use App\Models\Payment;
|
||||
use App\Ninja\Repositories\CreditRepository;
|
||||
|
||||
|
||||
@ -30,6 +33,10 @@ class CreditService extends BaseService
|
||||
public function getDatatable($clientPublicId, $search)
|
||||
{
|
||||
$query = $this->creditRepo->find($clientPublicId, $search);
|
||||
|
||||
if(!Utils::hasPermission('view_all')){
|
||||
$query->where('credits.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
return $this->createDatatable(ENTITY_CREDIT, $query, !$clientPublicId);
|
||||
}
|
||||
@ -40,6 +47,10 @@ class CreditService extends BaseService
|
||||
[
|
||||
'client_name',
|
||||
function ($model) {
|
||||
if(!Client::canViewItemByOwner($model->client_user_id)){
|
||||
return Utils::getClientDisplayName($model);
|
||||
}
|
||||
|
||||
return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : '';
|
||||
},
|
||||
! $hideClient
|
||||
@ -78,6 +89,9 @@ class CreditService extends BaseService
|
||||
trans('texts.apply_credit'),
|
||||
function ($model) {
|
||||
return URL::to("payments/create/{$model->client_public_id}") . '?paymentTypeId=1';
|
||||
},
|
||||
function ($model) {
|
||||
return Payment::canCreate();
|
||||
}
|
||||
]
|
||||
];
|
||||
|
@ -3,6 +3,7 @@
|
||||
use HtmlString;
|
||||
use Utils;
|
||||
use Datatable;
|
||||
use Auth;
|
||||
|
||||
class DatatableService
|
||||
{
|
||||
@ -13,7 +14,9 @@ class DatatableService
|
||||
|
||||
if ($actions && $showCheckbox) {
|
||||
$table->addColumn('checkbox', function ($model) {
|
||||
return '<input type="checkbox" name="ids[]" value="' . $model->public_id
|
||||
$can_edit = Auth::user()->hasPermission('edit_all') || (isset($model->user_id) && Auth::user()->id == $model->user_id);
|
||||
|
||||
return !$can_edit?'':'<input type="checkbox" name="ids[]" value="' . $model->public_id
|
||||
. '" ' . Utils::getEntityRowClass($model) . '>';
|
||||
});
|
||||
}
|
||||
@ -45,6 +48,8 @@ class DatatableService
|
||||
$hasAction = false;
|
||||
$str = '<center style="min-width:100px">';
|
||||
|
||||
$can_edit = Auth::user()->hasPermission('edit_all') || (isset($model->user_id) && Auth::user()->id == $model->user_id);
|
||||
|
||||
if (property_exists($model, 'is_deleted') && $model->is_deleted) {
|
||||
$str .= '<button type="button" class="btn btn-sm btn-danger tr-status">'.trans('texts.deleted').'</button>';
|
||||
} elseif ($model->deleted_at && $model->deleted_at !== '0000-00-00') {
|
||||
@ -70,9 +75,15 @@ class DatatableService
|
||||
}
|
||||
list($value, $url, $visible) = $action;
|
||||
if ($visible($model)) {
|
||||
$str .= "<li><a href=\"{$url($model)}\">{$value}</a></li>";
|
||||
$lastIsDivider = false;
|
||||
$hasAction = true;
|
||||
if($value == '--divider--'){
|
||||
$str .= "<li class=\"divider\"></li>";
|
||||
$lastIsDivider = true;
|
||||
}
|
||||
else {
|
||||
$str .= "<li><a href=\"{$url($model)}\">{$value}</a></li>";
|
||||
$hasAction = true;
|
||||
$lastIsDivider = false;
|
||||
}
|
||||
}
|
||||
} elseif ( ! $lastIsDivider) {
|
||||
$str .= "<li class=\"divider\"></li>";
|
||||
@ -84,20 +95,20 @@ class DatatableService
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( ! $lastIsDivider) {
|
||||
if ( $can_edit && ! $lastIsDivider) {
|
||||
$str .= "<li class=\"divider\"></li>";
|
||||
}
|
||||
|
||||
if ($entityType != ENTITY_USER || $model->public_id) {
|
||||
if (($entityType != ENTITY_USER || $model->public_id) && $can_edit) {
|
||||
$str .= "<li><a href=\"javascript:archiveEntity({$model->public_id})\">"
|
||||
. trans("texts.archive_{$entityType}") . "</a></li>";
|
||||
}
|
||||
} else {
|
||||
} else if($can_edit) {
|
||||
$str .= "<li><a href=\"javascript:restoreEntity({$model->public_id})\">"
|
||||
. trans("texts.restore_{$entityType}") . "</a></li>";
|
||||
}
|
||||
|
||||
if (property_exists($model, 'is_deleted') && !$model->is_deleted) {
|
||||
if (property_exists($model, 'is_deleted') && !$model->is_deleted && $can_edit) {
|
||||
$str .= "<li><a href=\"javascript:deleteEntity({$model->public_id})\">"
|
||||
. trans("texts.delete_{$entityType}") . "</a></li>";
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
<?php namespace App\Services;
|
||||
|
||||
use Auth;
|
||||
use DB;
|
||||
use Utils;
|
||||
use URL;
|
||||
use App\Services\BaseService;
|
||||
use App\Ninja\Repositories\ExpenseRepository;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Client;
|
||||
use App\Models\Vendor;
|
||||
|
||||
@ -42,6 +45,10 @@ class ExpenseService extends BaseService
|
||||
{
|
||||
$query = $this->expenseRepo->find($search);
|
||||
|
||||
if(!Utils::hasPermission('view_all')){
|
||||
$query->where('expenses.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
return $this->createDatatable(ENTITY_EXPENSE, $query);
|
||||
}
|
||||
|
||||
@ -63,6 +70,10 @@ class ExpenseService extends BaseService
|
||||
function ($model)
|
||||
{
|
||||
if ($model->vendor_public_id) {
|
||||
if(!Vendor::canViewItemByOwner($model->vendor_user_id)){
|
||||
return $model->vendor_name;
|
||||
}
|
||||
|
||||
return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml();
|
||||
} else {
|
||||
return '';
|
||||
@ -74,6 +85,10 @@ class ExpenseService extends BaseService
|
||||
function ($model)
|
||||
{
|
||||
if ($model->client_public_id) {
|
||||
if(!Client::canViewItemByOwner($model->client_user_id)){
|
||||
return Utils::getClientDisplayName($model);
|
||||
}
|
||||
|
||||
return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
|
||||
} else {
|
||||
return '';
|
||||
@ -83,6 +98,10 @@ class ExpenseService extends BaseService
|
||||
[
|
||||
'expense_date',
|
||||
function ($model) {
|
||||
if(!Expense::canEditItemByOwner($model->user_id)){
|
||||
return Utils::fromSqlDate($model->expense_date);
|
||||
}
|
||||
|
||||
return link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date))->toHtml();
|
||||
}
|
||||
],
|
||||
@ -151,6 +170,9 @@ class ExpenseService extends BaseService
|
||||
trans('texts.edit_expense'),
|
||||
function ($model) {
|
||||
return URL::to("expenses/{$model->public_id}/edit") ;
|
||||
},
|
||||
function ($model) {
|
||||
return Expense::canEditItem($model);
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -159,7 +181,7 @@ class ExpenseService extends BaseService
|
||||
return URL::to("/invoices/{$model->invoice_public_id}/edit");
|
||||
},
|
||||
function ($model) {
|
||||
return $model->invoice_public_id;
|
||||
return $model->invoice_public_id && Invoice::canEditItemByOwner($model->invoice_user_id);
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -168,7 +190,7 @@ class ExpenseService extends BaseService
|
||||
return "javascript:invoiceEntity({$model->public_id})";
|
||||
},
|
||||
function ($model) {
|
||||
return ! $model->invoice_id && (!$model->deleted_at || $model->deleted_at == '0000-00-00');
|
||||
return ! $model->invoice_id && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Invoice::canCreate();
|
||||
}
|
||||
],
|
||||
];
|
||||
|
@ -8,6 +8,9 @@ use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Events\QuoteInvitationWasApproved;
|
||||
use App\Models\Invitation;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Client;
|
||||
use App\Models\Payment;
|
||||
|
||||
class InvoiceService extends BaseService
|
||||
{
|
||||
@ -27,14 +30,26 @@ class InvoiceService extends BaseService
|
||||
return $this->invoiceRepo;
|
||||
}
|
||||
|
||||
public function save($data)
|
||||
public function save($data, $checkSubPermissions = false)
|
||||
{
|
||||
if (isset($data['client'])) {
|
||||
$client = $this->clientRepo->save($data['client']);
|
||||
$data['client_id'] = $client->id;
|
||||
$can_save_client = !$checkSubPermissions;
|
||||
if(!$can_save_client){
|
||||
if(empty($data['client']['public_id']) || $data['client']['public_id']=='-1'){
|
||||
$can_save_client = Client::canCreate();
|
||||
}
|
||||
else{
|
||||
$can_save_client = Client::wherePublicId($data['client']['public_id'])->first()->canEdit();
|
||||
}
|
||||
}
|
||||
|
||||
if($can_save_client){
|
||||
$client = $this->clientRepo->save($data['client']);
|
||||
$data['client_id'] = $client->id;
|
||||
}
|
||||
}
|
||||
|
||||
$invoice = $this->invoiceRepo->save($data);
|
||||
$invoice = $this->invoiceRepo->save($data, $checkSubPermissions);
|
||||
|
||||
$client = $invoice->client;
|
||||
$client->load('contacts');
|
||||
@ -109,6 +124,10 @@ class InvoiceService extends BaseService
|
||||
$query = $this->invoiceRepo->getInvoices($accountId, $clientPublicId, $entityType, $search)
|
||||
->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE ? true : false);
|
||||
|
||||
if(!Utils::hasPermission('view_all')){
|
||||
$query->where('invoices.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
return $this->createDatatable($entityType, $query, !$clientPublicId);
|
||||
}
|
||||
|
||||
@ -118,12 +137,19 @@ class InvoiceService extends BaseService
|
||||
[
|
||||
'invoice_number',
|
||||
function ($model) use ($entityType) {
|
||||
if(!Invoice::canEditItem($model)){
|
||||
return $model->invoice_number;
|
||||
}
|
||||
|
||||
return link_to("{$entityType}s/{$model->public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml();
|
||||
}
|
||||
],
|
||||
[
|
||||
'client_name',
|
||||
function ($model) {
|
||||
if(!Client::canViewItemByOwner($model->client_user_id)){
|
||||
return Utils::getClientDisplayName($model);
|
||||
}
|
||||
return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
|
||||
},
|
||||
! $hideClient
|
||||
@ -174,12 +200,18 @@ class InvoiceService extends BaseService
|
||||
trans("texts.edit_{$entityType}"),
|
||||
function ($model) use ($entityType) {
|
||||
return URL::to("{$entityType}s/{$model->public_id}/edit");
|
||||
},
|
||||
function ($model) {
|
||||
return Invoice::canEditItem($model);
|
||||
}
|
||||
],
|
||||
[
|
||||
trans("texts.clone_{$entityType}"),
|
||||
function ($model) use ($entityType) {
|
||||
return URL::to("{$entityType}s/{$model->public_id}/clone");
|
||||
},
|
||||
function ($model) {
|
||||
return Invoice::canCreate();
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -188,14 +220,19 @@ class InvoiceService extends BaseService
|
||||
return URL::to("{$entityType}s/{$entityType}_history/{$model->public_id}");
|
||||
}
|
||||
],
|
||||
[],
|
||||
[
|
||||
'--divider--', function(){return false;},
|
||||
function ($model) {
|
||||
return Invoice::canEditItem($model) || Payment::canCreate();
|
||||
}
|
||||
],
|
||||
[
|
||||
trans("texts.mark_sent"),
|
||||
function ($model) {
|
||||
return "javascript:markEntity({$model->public_id})";
|
||||
},
|
||||
function ($model) {
|
||||
return $model->invoice_status_id < INVOICE_STATUS_SENT;
|
||||
return $model->invoice_status_id < INVOICE_STATUS_SENT && Invoice::canEditItem($model);
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -204,7 +241,7 @@ class InvoiceService extends BaseService
|
||||
return URL::to("payments/create/{$model->client_public_id}/{$model->public_id}");
|
||||
},
|
||||
function ($model) use ($entityType) {
|
||||
return $entityType == ENTITY_INVOICE && $model->balance > 0;
|
||||
return $entityType == ENTITY_INVOICE && $model->balance > 0 && Payment::canCreate();
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -213,7 +250,7 @@ class InvoiceService extends BaseService
|
||||
return URL::to("quotes/{$model->quote_id}/edit");
|
||||
},
|
||||
function ($model) use ($entityType) {
|
||||
return $entityType == ENTITY_INVOICE && $model->quote_id;
|
||||
return $entityType == ENTITY_INVOICE && $model->quote_id && Invoice::canEditItem($model);
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -222,7 +259,7 @@ class InvoiceService extends BaseService
|
||||
return URL::to("invoices/{$model->quote_invoice_id}/edit");
|
||||
},
|
||||
function ($model) use ($entityType) {
|
||||
return $entityType == ENTITY_QUOTE && $model->quote_invoice_id;
|
||||
return $entityType == ENTITY_QUOTE && $model->quote_invoice_id && Invoice::canEditItem($model);
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -231,7 +268,7 @@ class InvoiceService extends BaseService
|
||||
return "javascript:convertEntity({$model->public_id})";
|
||||
},
|
||||
function ($model) use ($entityType) {
|
||||
return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id;
|
||||
return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id && Invoice::canEditItem($model);
|
||||
}
|
||||
]
|
||||
];
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php namespace App\Services;
|
||||
|
||||
use Utils;
|
||||
use Auth;
|
||||
use URL;
|
||||
use DateTime;
|
||||
use Event;
|
||||
@ -10,6 +11,8 @@ use CreditCard;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Account;
|
||||
use App\Models\Country;
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\AccountGatewayToken;
|
||||
use App\Ninja\Repositories\PaymentRepository;
|
||||
use App\Ninja\Repositories\AccountRepository;
|
||||
@ -286,6 +289,10 @@ class PaymentService extends BaseService
|
||||
{
|
||||
$query = $this->paymentRepo->find($clientPublicId, $search);
|
||||
|
||||
if(!Utils::hasPermission('view_all')){
|
||||
$query->where('payments.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
return $this->createDatatable(ENTITY_PAYMENT, $query, !$clientPublicId);
|
||||
}
|
||||
|
||||
@ -295,12 +302,20 @@ class PaymentService extends BaseService
|
||||
[
|
||||
'invoice_number',
|
||||
function ($model) {
|
||||
if(!Invoice::canEditItemByOwner($model->invoice_user_id)){
|
||||
return $model->invoice_number;
|
||||
}
|
||||
|
||||
return link_to("invoices/{$model->invoice_public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml();
|
||||
}
|
||||
],
|
||||
[
|
||||
'client_name',
|
||||
function ($model) {
|
||||
if(!Client::canViewItemByOwner($model->client_user_id)){
|
||||
return Utils::getClientDisplayName($model);
|
||||
}
|
||||
|
||||
return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : '';
|
||||
},
|
||||
! $hideClient
|
||||
@ -339,6 +354,9 @@ class PaymentService extends BaseService
|
||||
trans('texts.edit_payment'),
|
||||
function ($model) {
|
||||
return URL::to("payments/{$model->public_id}/edit");
|
||||
},
|
||||
function ($model) {
|
||||
return Payment::canEditItem($model);
|
||||
}
|
||||
]
|
||||
];
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php namespace App\Services;
|
||||
|
||||
use URL;
|
||||
use Auth;
|
||||
use Utils;
|
||||
use App\Models\Invoice;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
|
||||
class RecurringInvoiceService extends BaseService
|
||||
@ -19,6 +21,10 @@ class RecurringInvoiceService extends BaseService
|
||||
{
|
||||
$query = $this->invoiceRepo->getRecurringInvoices($accountId, $clientPublicId, $search);
|
||||
|
||||
if(!Utils::hasPermission('view_all')){
|
||||
$query->where('invoices.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
return $this->createDatatable(ENTITY_RECURRING_INVOICE, $query, !$clientPublicId);
|
||||
}
|
||||
|
||||
@ -66,6 +72,9 @@ class RecurringInvoiceService extends BaseService
|
||||
trans('texts.edit_invoice'),
|
||||
function ($model) {
|
||||
return URL::to("invoices/{$model->public_id}/edit");
|
||||
},
|
||||
function ($model) {
|
||||
return Invoice::canEditItem($model);
|
||||
}
|
||||
]
|
||||
];
|
||||
|
@ -1,8 +1,11 @@
|
||||
<?php namespace App\Services;
|
||||
|
||||
use Auth;
|
||||
use URL;
|
||||
use Utils;
|
||||
use App\Models\Task;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Client;
|
||||
use App\Ninja\Repositories\TaskRepository;
|
||||
use App\Services\BaseService;
|
||||
|
||||
@ -33,6 +36,10 @@ class TaskService extends BaseService
|
||||
{
|
||||
$query = $this->taskRepo->find($clientPublicId, $search);
|
||||
|
||||
if(!Utils::hasPermission('view_all')){
|
||||
$query->where('tasks.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
return $this->createDatatable(ENTITY_TASK, $query, !$clientPublicId);
|
||||
}
|
||||
|
||||
@ -42,6 +49,10 @@ class TaskService extends BaseService
|
||||
[
|
||||
'client_name',
|
||||
function ($model) {
|
||||
if(!Client::canViewItemByOwner($model->client_user_id)){
|
||||
return Utils::getClientDisplayName($model);
|
||||
}
|
||||
|
||||
return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : '';
|
||||
},
|
||||
! $hideClient
|
||||
@ -82,7 +93,7 @@ class TaskService extends BaseService
|
||||
return URL::to('tasks/'.$model->public_id.'/edit');
|
||||
},
|
||||
function ($model) {
|
||||
return !$model->deleted_at || $model->deleted_at == '0000-00-00';
|
||||
return (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Task::canEditItem($model);
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -91,7 +102,7 @@ class TaskService extends BaseService
|
||||
return URL::to("/invoices/{$model->invoice_public_id}/edit");
|
||||
},
|
||||
function ($model) {
|
||||
return $model->invoice_number;
|
||||
return $model->invoice_number && Invoice::canEditItemByOwner($model->invoice_user_id);
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -100,7 +111,7 @@ class TaskService extends BaseService
|
||||
return "javascript:stopTask({$model->public_id})";
|
||||
},
|
||||
function ($model) {
|
||||
return $model->is_running;
|
||||
return $model->is_running && Task::canEditItem($model);
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -109,7 +120,7 @@ class TaskService extends BaseService
|
||||
return "javascript:invoiceEntity({$model->public_id})";
|
||||
},
|
||||
function ($model) {
|
||||
return ! $model->invoice_number && (!$model->deleted_at || $model->deleted_at == '0000-00-00');
|
||||
return ! $model->invoice_number && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Invoice::canCreate();
|
||||
}
|
||||
]
|
||||
];
|
||||
|
@ -53,11 +53,15 @@ class UserService extends BaseService
|
||||
'confirmed',
|
||||
function ($model) {
|
||||
if (!$model->public_id) {
|
||||
return self::getStatusLabel(USER_STATE_ADMIN);
|
||||
return self::getStatusLabel(USER_STATE_OWNER);
|
||||
} elseif ($model->deleted_at) {
|
||||
return self::getStatusLabel(USER_STATE_DISABLED);
|
||||
} elseif ($model->confirmed) {
|
||||
return self::getStatusLabel(USER_STATE_ACTIVE);
|
||||
if($model->is_admin){
|
||||
return self::getStatusLabel(USER_STATE_ADMIN);
|
||||
} else {
|
||||
return self::getStatusLabel(USER_STATE_ACTIVE);
|
||||
}
|
||||
} else {
|
||||
return self::getStatusLabel(USER_STATE_PENDING);
|
||||
}
|
||||
@ -96,17 +100,20 @@ class UserService extends BaseService
|
||||
$class = 'default';
|
||||
switch ($state) {
|
||||
case USER_STATE_PENDING:
|
||||
$class = 'info';
|
||||
$class = 'default';
|
||||
break;
|
||||
case USER_STATE_ACTIVE:
|
||||
$class = 'primary';
|
||||
$class = 'info';
|
||||
break;
|
||||
case USER_STATE_DISABLED:
|
||||
$class = 'warning';
|
||||
break;
|
||||
case USER_STATE_ADMIN:
|
||||
case USER_STATE_OWNER:
|
||||
$class = 'success';
|
||||
break;
|
||||
case USER_STATE_ADMIN:
|
||||
$class = 'primary';
|
||||
break;
|
||||
}
|
||||
return "<h4><div class=\"label label-{$class}\">$label</div></h4>";
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
use Utils;
|
||||
use URL;
|
||||
use Auth;
|
||||
use App\Models\Vendor;
|
||||
use App\Models\Expense;
|
||||
use App\Services\BaseService;
|
||||
use App\Ninja\Repositories\VendorRepository;
|
||||
use App\Ninja\Repositories\NinjaRepository;
|
||||
@ -36,6 +38,10 @@ class VendorService extends BaseService
|
||||
public function getDatatable($search)
|
||||
{
|
||||
$query = $this->vendorRepo->find($search);
|
||||
|
||||
if(!Utils::hasPermission('view_all')){
|
||||
$query->where('vendors.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
return $this->createDatatable(ENTITY_VENDOR, $query);
|
||||
}
|
||||
@ -83,13 +89,25 @@ class VendorService extends BaseService
|
||||
trans('texts.edit_vendor'),
|
||||
function ($model) {
|
||||
return URL::to("vendors/{$model->public_id}/edit");
|
||||
},
|
||||
function ($model) {
|
||||
return Vendor::canEditItem($model);
|
||||
}
|
||||
],
|
||||
[],
|
||||
[
|
||||
'--divider--', function(){return false;},
|
||||
function ($model) {
|
||||
return Vendor::canEditItem($model) && Expense::canCreate();
|
||||
}
|
||||
|
||||
],
|
||||
[
|
||||
trans('texts.enter_expense'),
|
||||
function ($model) {
|
||||
return URL::to("expenses/create/{$model->public_id}");
|
||||
},
|
||||
function ($model) {
|
||||
return Expense::canCreate();
|
||||
}
|
||||
]
|
||||
];
|
||||
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddUserPermissions extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function($table) {
|
||||
$table->boolean('is_admin')->default(true);
|
||||
$table->unsignedInteger('permissions')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function($table) {
|
||||
$table->dropColumn('is_admin');
|
||||
$table->dropColumn('permissions');
|
||||
});
|
||||
}
|
||||
}
|
@ -54,6 +54,7 @@ class CurrenciesSeeder extends Seeder
|
||||
['name' => 'Croatian Kuna', 'code' => 'HKR', 'symbol' => 'kn', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
|
||||
['name' => 'Saudi Riyal', 'code' => 'SAR', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
['name' => 'Japanese Yen', 'code' => 'JPY', 'symbol' => '¥', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
['name' => 'Maldivian Rufiyaa', 'code' => 'MVR', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
];
|
||||
|
||||
foreach ($currencies as $currency) {
|
||||
|
@ -30487,6 +30487,7 @@ function calculateAmounts(invoice) {
|
||||
for (var i=0; i<invoice.invoice_items.length; i++) {
|
||||
var item = invoice.invoice_items[i];
|
||||
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
|
||||
lineTotal = roundToTwo(lineTotal);
|
||||
if (lineTotal) {
|
||||
total += lineTotal;
|
||||
}
|
||||
@ -31182,7 +31183,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
|
||||
var value = getDescendantProp(invoice, field);
|
||||
if (match.indexOf('?') < 0 || value) {
|
||||
if (invoice.partial && field == 'balance_due') {
|
||||
field = 'amount_due';
|
||||
field = 'partial_due';
|
||||
} else if (invoice.is_quote) {
|
||||
field = field.replace('invoice', 'quote');
|
||||
}
|
||||
@ -31439,12 +31440,22 @@ NINJA.subtotals = function(invoice, hideBalance)
|
||||
data.push([{text:invoiceLabels.paid_to_date}, {text:formatMoneyInvoice(paid, invoice)}]);
|
||||
}
|
||||
|
||||
if (!hideBalance) {
|
||||
var isPartial = NINJA.parseFloat(invoice.partial);
|
||||
var isPartial = NINJA.parseFloat(invoice.partial);
|
||||
|
||||
if (!hideBalance || isPartial) {
|
||||
data.push([
|
||||
{text: isPartial ? invoiceLabels.amount_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
|
||||
{text: formatMoneyInvoice(invoice.balance_amount, invoice), style:['balanceDue']}
|
||||
{ text: invoiceLabels.balance_due, style: [isPartial ? '' : 'balanceDueLabel'] },
|
||||
{ text: formatMoneyInvoice(invoice.total_amount, invoice), style: [isPartial ? '' : 'balanceDue'] }
|
||||
]);
|
||||
}
|
||||
|
||||
if (!hideBalance) {
|
||||
if (isPartial) {
|
||||
data.push([
|
||||
{ text: invoiceLabels.partial_due, style: ['balanceDueLabel'] },
|
||||
{ text: formatMoneyInvoice(invoice.balance_amount, invoice), style: ['balanceDue'] }
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return NINJA.prepareDataPairs(data, 'subtotals');
|
||||
@ -31453,7 +31464,7 @@ NINJA.subtotals = function(invoice, hideBalance)
|
||||
NINJA.subtotalsBalance = function(invoice) {
|
||||
var isPartial = NINJA.parseFloat(invoice.partial);
|
||||
return [[
|
||||
{text: isPartial ? invoiceLabels.amount_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
|
||||
{text: isPartial ? invoiceLabels.partial_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
|
||||
{text: formatMoneyInvoice(invoice.balance_amount, invoice), style:['balanceDue']}
|
||||
]];
|
||||
}
|
||||
@ -31531,18 +31542,18 @@ NINJA.invoiceDetails = function(invoice) {
|
||||
|
||||
if (NINJA.parseFloat(invoice.balance) < NINJA.parseFloat(invoice.amount)) {
|
||||
data.push([
|
||||
{text: invoiceLabels.total},
|
||||
{text: invoiceLabels.balance_due},
|
||||
{text: formatMoneyInvoice(invoice.amount, invoice)}
|
||||
]);
|
||||
} else if (isPartial) {
|
||||
data.push([
|
||||
{text: invoiceLabels.total},
|
||||
{text: invoiceLabels.balance_due},
|
||||
{text: formatMoneyInvoice(invoice.total_amount, invoice)}
|
||||
]);
|
||||
}
|
||||
|
||||
data.push([
|
||||
{text: isPartial ? invoiceLabels.amount_due : invoiceLabels.balance_due, style: ['invoiceDetailBalanceDueLabel']},
|
||||
{text: isPartial ? invoiceLabels.partial_due : invoiceLabels.balance_due, style: ['invoiceDetailBalanceDueLabel']},
|
||||
{text: formatMoneyInvoice(invoice.balance_amount, invoice), style: ['invoiceDetailBalanceDue']}
|
||||
])
|
||||
|
||||
|
@ -190,7 +190,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
|
||||
var value = getDescendantProp(invoice, field);
|
||||
if (match.indexOf('?') < 0 || value) {
|
||||
if (invoice.partial && field == 'balance_due') {
|
||||
field = 'amount_due';
|
||||
field = 'partial_due';
|
||||
} else if (invoice.is_quote) {
|
||||
field = field.replace('invoice', 'quote');
|
||||
}
|
||||
@ -447,12 +447,22 @@ NINJA.subtotals = function(invoice, hideBalance)
|
||||
data.push([{text:invoiceLabels.paid_to_date}, {text:formatMoneyInvoice(paid, invoice)}]);
|
||||
}
|
||||
|
||||
if (!hideBalance) {
|
||||
var isPartial = NINJA.parseFloat(invoice.partial);
|
||||
var isPartial = NINJA.parseFloat(invoice.partial);
|
||||
|
||||
if (!hideBalance || isPartial) {
|
||||
data.push([
|
||||
{text: isPartial ? invoiceLabels.amount_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
|
||||
{text: formatMoneyInvoice(invoice.balance_amount, invoice), style:['balanceDue']}
|
||||
{ text: invoiceLabels.balance_due, style: [isPartial ? '' : 'balanceDueLabel'] },
|
||||
{ text: formatMoneyInvoice(invoice.total_amount, invoice), style: [isPartial ? '' : 'balanceDue'] }
|
||||
]);
|
||||
}
|
||||
|
||||
if (!hideBalance) {
|
||||
if (isPartial) {
|
||||
data.push([
|
||||
{ text: invoiceLabels.partial_due, style: ['balanceDueLabel'] },
|
||||
{ text: formatMoneyInvoice(invoice.balance_amount, invoice), style: ['balanceDue'] }
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return NINJA.prepareDataPairs(data, 'subtotals');
|
||||
@ -461,7 +471,7 @@ NINJA.subtotals = function(invoice, hideBalance)
|
||||
NINJA.subtotalsBalance = function(invoice) {
|
||||
var isPartial = NINJA.parseFloat(invoice.partial);
|
||||
return [[
|
||||
{text: isPartial ? invoiceLabels.amount_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
|
||||
{text: isPartial ? invoiceLabels.partial_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
|
||||
{text: formatMoneyInvoice(invoice.balance_amount, invoice), style:['balanceDue']}
|
||||
]];
|
||||
}
|
||||
@ -539,18 +549,18 @@ NINJA.invoiceDetails = function(invoice) {
|
||||
|
||||
if (NINJA.parseFloat(invoice.balance) < NINJA.parseFloat(invoice.amount)) {
|
||||
data.push([
|
||||
{text: invoiceLabels.total},
|
||||
{text: invoiceLabels.balance_due},
|
||||
{text: formatMoneyInvoice(invoice.amount, invoice)}
|
||||
]);
|
||||
} else if (isPartial) {
|
||||
data.push([
|
||||
{text: invoiceLabels.total},
|
||||
{text: invoiceLabels.balance_due},
|
||||
{text: formatMoneyInvoice(invoice.total_amount, invoice)}
|
||||
]);
|
||||
}
|
||||
|
||||
data.push([
|
||||
{text: isPartial ? invoiceLabels.amount_due : invoiceLabels.balance_due, style: ['invoiceDetailBalanceDueLabel']},
|
||||
{text: isPartial ? invoiceLabels.partial_due : invoiceLabels.balance_due, style: ['invoiceDetailBalanceDueLabel']},
|
||||
{text: formatMoneyInvoice(invoice.balance_amount, invoice), style: ['invoiceDetailBalanceDue']}
|
||||
])
|
||||
|
||||
|
@ -595,6 +595,7 @@ function calculateAmounts(invoice) {
|
||||
for (var i=0; i<invoice.invoice_items.length; i++) {
|
||||
var item = invoice.invoice_items[i];
|
||||
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
|
||||
lineTotal = roundToTwo(lineTotal);
|
||||
if (lineTotal) {
|
||||
total += lineTotal;
|
||||
}
|
||||
|
@ -1065,6 +1065,17 @@ $LANG = array(
|
||||
'cost' => 'Cost',
|
||||
'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.',
|
||||
|
||||
// User Permissions
|
||||
'owner' => 'Owner',
|
||||
'administrator' => 'Administrator',
|
||||
'administrator_help' => 'Allow user to manage users, change settings, and view and modify all data',
|
||||
'user_create_all' => 'Create clients, invoices, etc.',
|
||||
'user_view_all' => 'View all clients, invoices, etc.',
|
||||
'user_edit_all' => 'Edit all clients, invoices, etc.',
|
||||
'gateway_help_20' => ':link to sign up for Sage Pay.',
|
||||
'gateway_help_21' => ':link to sign up for Sage Pay.',
|
||||
'partial_due' => 'Partial Due',
|
||||
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
@ -52,6 +52,15 @@
|
||||
@foreach ($gateways as $gateway)
|
||||
|
||||
<div id="gateway_{{ $gateway->id }}_div" class='gateway-fields' style="display: none">
|
||||
@if ($gateway->getHelp())
|
||||
<div class="form-group">
|
||||
<label class="control-label col-lg-4 col-sm-4"></label>
|
||||
<div class="col-lg-8 col-sm-8 help-block">
|
||||
{!! $gateway->getHelp() !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@foreach ($gateway->fields as $field => $details)
|
||||
|
||||
@if ($details && !$accountGateway)
|
||||
@ -73,15 +82,6 @@
|
||||
|
||||
@endforeach
|
||||
|
||||
@if ($gateway->getHelp())
|
||||
<div class="form-group">
|
||||
<label class="control-label col-lg-4 col-sm-4"></label>
|
||||
<div class="col-lg-8 col-sm-8 help-block">
|
||||
{!! $gateway->getHelp() !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($gateway->id == GATEWAY_STRIPE)
|
||||
{!! Former::text('publishable_key') !!}
|
||||
|
||||
|
@ -60,7 +60,16 @@
|
||||
@else
|
||||
NINJA.headerFont = NINJA.bodyFont = 'Roboto';
|
||||
@endif
|
||||
var fields = ['item', 'description', 'unit_cost', 'quantity', 'line_total', 'terms'];
|
||||
var fields = [
|
||||
'item',
|
||||
'description',
|
||||
'unit_cost',
|
||||
'quantity',
|
||||
'line_total',
|
||||
'terms',
|
||||
'balance_due',
|
||||
'partial_due'
|
||||
];
|
||||
invoiceLabels.old = {};
|
||||
for (var i=0; i<fields.length; i++) {
|
||||
var field = fields[i];
|
||||
@ -181,11 +190,13 @@
|
||||
{!! Former::text('labels_item')->label(trans('texts.item')) !!}
|
||||
{!! Former::text('labels_description')->label(trans('texts.description')) !!}
|
||||
{!! Former::text('labels_unit_cost')->label(trans('texts.unit_cost')) !!}
|
||||
{!! Former::text('labels_quantity')->label(trans('texts.quantity')) !!}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{!! Former::text('labels_quantity')->label(trans('texts.quantity')) !!}
|
||||
{!! Former::text('labels_line_total')->label(trans('texts.line_total')) !!}
|
||||
{!! Former::text('labels_terms')->label(trans('texts.terms')) !!}
|
||||
{!! Former::text('labels_balance_due')->label(trans('texts.balance_due')) !!}
|
||||
{!! Former::text('labels_partial_due')->label(trans('texts.partial_due')) !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -21,7 +21,9 @@
|
||||
{{ Former::populateField('referral_code', true) }}
|
||||
@endif
|
||||
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_USER_DETAILS])
|
||||
@if (Utils::isAdmin())
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_USER_DETAILS])
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
@ -43,8 +43,11 @@
|
||||
@endif
|
||||
|
||||
@if ($client->trashed())
|
||||
{!! Button::primary(trans('texts.restore_client'))->withAttributes(['onclick' => 'onRestoreClick()']) !!}
|
||||
@if ($client->canEdit())
|
||||
{!! Button::primary(trans('texts.restore_client'))->withAttributes(['onclick' => 'onRestoreClick()']) !!}
|
||||
@endif
|
||||
@else
|
||||
@if ($client->canEdit())
|
||||
{!! DropdownButton::normal(trans('texts.edit_client'))
|
||||
->withAttributes(['class'=>'normalDropDown'])
|
||||
->withContents([
|
||||
@ -52,10 +55,12 @@
|
||||
['label' => trans('texts.delete_client'), 'url' => "javascript:onDeleteClick()"],
|
||||
]
|
||||
)->split() !!}
|
||||
|
||||
{!! DropdownButton::primary(trans('texts.new_invoice'))
|
||||
->withAttributes(['class'=>'primaryDropDown'])
|
||||
->withContents($actionLinks)->split() !!}
|
||||
@endif
|
||||
@if (\App\Models\Invoice::canCreate())
|
||||
{!! DropdownButton::primary(trans('texts.new_invoice'))
|
||||
->withAttributes(['class'=>'primaryDropDown'])
|
||||
->withContents($actionLinks)->split() !!}
|
||||
@endif
|
||||
@endif
|
||||
{!! Former::close() !!}
|
||||
|
||||
|
@ -116,7 +116,11 @@
|
||||
@foreach ($payments as $payment)
|
||||
<tr>
|
||||
<td>{!! \App\Models\Invoice::calcLink($payment) !!}</td>
|
||||
<td>{!! link_to('/clients/'.$payment->client_public_id, trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email)) !!}</td>
|
||||
@if (\App\Models\Client::canViewItemByOwner($payment->client_user_id))
|
||||
<td>{!! link_to('/clients/'.$payment->client_public_id, trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email)) !!}</td>
|
||||
@else
|
||||
<td>{{ trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email) }}</td>
|
||||
@endif
|
||||
<td>{{ Utils::fromSqlDate($payment->payment_date) }}</td>
|
||||
<td>{{ Utils::formatMoney($payment->amount, $payment->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }}</td>
|
||||
</tr>
|
||||
@ -149,7 +153,11 @@
|
||||
@if (!$invoice->is_quote)
|
||||
<tr>
|
||||
<td>{!! \App\Models\Invoice::calcLink($invoice) !!}</td>
|
||||
<td>{!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!}</td>
|
||||
@if (\App\Models\Client::canViewItemByOwner($payment->client_user_id))
|
||||
<td>{!! link_to('/clients/'.$payment->client_public_id, trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email)) !!}</td>
|
||||
@else
|
||||
<td>{{ trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email) }}</td>
|
||||
@endif
|
||||
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
|
||||
<td>{{ Utils::formatMoney($invoice->balance, $invoice->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }}</td>
|
||||
</tr>
|
||||
@ -160,7 +168,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default dashboard" style="height:320px">
|
||||
<div class="panel-heading" style="background-color:#e37329 !important">
|
||||
<h3 class="panel-title in-bold-white">
|
||||
@ -180,7 +188,11 @@
|
||||
@if (!$invoice->is_quote)
|
||||
<tr>
|
||||
<td>{!! \App\Models\Invoice::calcLink($invoice) !!}</td>
|
||||
<td>{!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!}</td>
|
||||
@if (\App\Models\Client::canViewItemByOwner($payment->client_user_id))
|
||||
<td>{!! link_to('/clients/'.$payment->client_public_id, trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email)) !!}</td>
|
||||
@else
|
||||
<td>{{ trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email) }}</td>
|
||||
@endif
|
||||
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
|
||||
<td>{{ Utils::formatMoney($invoice->balance, $invoice->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }}</td>
|
||||
</tr>
|
||||
|
@ -401,6 +401,7 @@
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a href="{{ URL::to(NINJA_WEB_URL) }}" class='navbar-brand' target="_blank">
|
||||
{{-- Per our license, please do not remove or modify this link. --}}
|
||||
<img src="{{ asset('images/invoiceninja-logo.png') }}" style="height:20px;width:auto;padding-right:10px"/>
|
||||
</a>
|
||||
</div>
|
||||
@ -472,11 +473,13 @@
|
||||
'selected' => true,
|
||||
])
|
||||
@endif
|
||||
<li class="divider"></li>
|
||||
@if (count(session(SESSION_USER_ACCOUNTS)) > 1)
|
||||
<li>{!! link_to('/manage_companies', trans('texts.manage_companies')) !!}</li>
|
||||
@elseif (!session(SESSION_USER_ACCOUNTS) || count(session(SESSION_USER_ACCOUNTS)) < 5)
|
||||
<li>{!! link_to('/login?new_company=true', trans('texts.add_company')) !!}</li>
|
||||
<li class="divider"></li>
|
||||
@if (Utils::isAdmin())
|
||||
@if (count(session(SESSION_USER_ACCOUNTS)) > 1)
|
||||
<li>{!! link_to('/manage_companies', trans('texts.manage_companies')) !!}</li>
|
||||
@elseif (!session(SESSION_USER_ACCOUNTS) || count(session(SESSION_USER_ACCOUNTS)) < 5)
|
||||
<li>{!! link_to('/login?new_company=true', trans('texts.add_company')) !!}</li>
|
||||
@endif
|
||||
@endif
|
||||
<li>{!! link_to('#', trans('texts.logout'), array('onclick'=>'logout()')) !!}</li>
|
||||
</ul>
|
||||
@ -486,15 +489,21 @@
|
||||
|
||||
<ul class="nav navbar-nav navbar-right navbar-settings">
|
||||
<li class="dropdown">
|
||||
<a href="{{ URL::to('/settings') }}" class="dropdown-toggle">
|
||||
<span class="glyphicon glyphicon-cog" title="{{ trans('texts.settings') }}"/>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
@foreach (\App\Models\Account::$basicSettings as $setting)
|
||||
<li>{!! link_to('settings/' . $setting, uctrans("texts.{$setting}")) !!}</li>
|
||||
@endforeach
|
||||
<li><a href="{{ url('settings/' . ACCOUNT_INVOICE_SETTINGS) }}">{!! uctrans('texts.advanced_settings') . Utils::getProLabel(ACCOUNT_ADVANCED_SETTINGS) !!}</a></li>
|
||||
</ul>
|
||||
@if (Utils::isAdmin())
|
||||
<a href="{{ URL::to('/settings') }}" class="dropdown-toggle">
|
||||
<span class="glyphicon glyphicon-cog" title="{{ trans('texts.settings') }}"/>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
@foreach (\App\Models\Account::$basicSettings as $setting)
|
||||
<li>{!! link_to('settings/' . $setting, uctrans("texts.{$setting}")) !!}</li>
|
||||
@endforeach
|
||||
<li><a href="{{ url('settings/' . ACCOUNT_INVOICE_SETTINGS) }}">{!! uctrans('texts.advanced_settings') . Utils::getProLabel(ACCOUNT_ADVANCED_SETTINGS) !!}</a></li>
|
||||
</ul>
|
||||
@else
|
||||
<a href="{{ URL::to('/settings/user_details') }}" class="dropdown-toggle">
|
||||
<span class="glyphicon glyphicon-user" title="{{ trans('texts.settings') }}"/>
|
||||
</a>
|
||||
@endif
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -63,14 +63,19 @@
|
||||
<label for="client" class="control-label col-lg-4 col-sm-4">{{ trans('texts.client') }}</label>
|
||||
<div class="col-lg-8 col-sm-8">
|
||||
<h4><div data-bind="text: getClientDisplayName(ko.toJS(client()))"></div></h4>
|
||||
<a id="editClientLink" class="pointer" data-bind="click: $root.showClientForm">{{ trans('texts.edit_client') }}</a> |
|
||||
{!! link_to('/clients/'.$invoice->client->public_id, trans('texts.view_client'), ['target' => '_blank']) !!}
|
||||
|
||||
@if($invoice->client->canView())
|
||||
@if ($invoice->client->canEdit())
|
||||
<a id="editClientLink" class="pointer" data-bind="click: $root.showClientForm">{{ trans('texts.edit_client') }}</a> |
|
||||
@endif
|
||||
{!! link_to('/clients/'.$invoice->client->public_id, trans('texts.view_client'), ['target' => '_blank']) !!}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:none">
|
||||
@endif
|
||||
|
||||
{!! Former::select('client')->addOption('', '')->data_bind("dropdown: client")->addClass('client-input')->addGroupClass('client_select closer-row') !!}
|
||||
|
||||
{!! Former::select('client')->addOption('', '')->data_bind("dropdown: client")->addClass('client-input')->addGroupClass('client_select closer-row') !!}
|
||||
|
||||
<div class="form-group" style="margin-bottom: 8px">
|
||||
<div class="col-lg-8 col-sm-8 col-lg-offset-4 col-sm-offset-4">
|
||||
@ -380,11 +385,18 @@
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
<tr style="font-size:1.05em">
|
||||
<tr data-bind="style: { 'font-weight': partial() ? 'normal' : 'bold', 'font-size': partial() ? '1em' : '1.05em' }">
|
||||
<td class="hide-border" colspan="3"/>
|
||||
<td class="hide-border" style="display:none" data-bind="visible: $root.invoice_item_taxes.show"/>
|
||||
<td class="hide-border" colspan="{{ $account->hide_quantity ? 1 : 2 }}"><b>{{ trans($entityType == ENTITY_INVOICE ? 'texts.balance_due' : 'texts.total') }}</b></td>
|
||||
<td class="hide-border" style="text-align: right"><span data-bind="text: totals.total"></span></td>
|
||||
<td class="hide-border" data-bind="css: {'hide-border': !partial()}" colspan="{{ $account->hide_quantity ? 1 : 2 }}">{{ $entityType == ENTITY_INVOICE ? $invoiceLabels['balance_due'] : trans('texts.total') }}</td>
|
||||
<td class="hide-border" data-bind="css: {'hide-border': !partial()}" style="text-align: right"><span data-bind="text: totals.total"></span></td>
|
||||
</tr>
|
||||
|
||||
<tr style="font-size:1.05em; display:none; font-weight:bold" data-bind="visible: partial">
|
||||
<td class="hide-border" colspan="3"/>
|
||||
<td class="hide-border" style="display:none" data-bind="visible: $root.invoice_item_taxes.show"/>
|
||||
<td class="hide-border" colspan="{{ $account->hide_quantity ? 1 : 2 }}">{{ $invoiceLabels['partial_due'] }}</td>
|
||||
<td class="hide-border" style="text-align: right"><span data-bind="text: totals.partial"></span></td>
|
||||
</tr>
|
||||
|
||||
</tfoot>
|
||||
|
@ -512,7 +512,11 @@ function InvoiceModel(data) {
|
||||
});
|
||||
|
||||
self.totals.total = ko.computed(function() {
|
||||
return self.formatMoney(self.partial() ? self.partial() : self.totals.rawTotal());
|
||||
return self.formatMoney(self.totals.rawTotal());
|
||||
});
|
||||
|
||||
self.totals.partial = ko.computed(function() {
|
||||
return self.formatMoney(self.partial());
|
||||
});
|
||||
|
||||
self.onDragged = function(item) {
|
||||
|
@ -9,12 +9,14 @@
|
||||
{!! Former::text('public_id') !!}
|
||||
</div>
|
||||
|
||||
@if ($entityType == ENTITY_TASK)
|
||||
{!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm("invoice")'])->appendIcon(Icon::create('check')) !!}
|
||||
@endif
|
||||
@if ($entityType == ENTITY_EXPENSE)
|
||||
{!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm("invoice")'])->appendIcon(Icon::create('check')) !!}
|
||||
@endif
|
||||
@if (\App\Models\Invoice::canCreate())
|
||||
@if ($entityType == ENTITY_TASK)
|
||||
{!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm("invoice")'])->appendIcon(Icon::create('check')) !!}
|
||||
@endif
|
||||
@if ($entityType == ENTITY_EXPENSE)
|
||||
{!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm("invoice")'])->appendIcon(Icon::create('check')) !!}
|
||||
@endif
|
||||
@endif
|
||||
|
||||
{!! DropdownButton::normal(trans('texts.archive'))->withContents([
|
||||
['label' => trans('texts.archive_'.$entityType), 'url' => 'javascript:submitForm("archive")'],
|
||||
@ -38,7 +40,9 @@
|
||||
{!! Button::normal(trans('texts.credits'))->asLinkTo(URL::to('/credits'))->appendIcon(Icon::create('list')) !!}
|
||||
@endif
|
||||
|
||||
{!! Button::primary(trans("texts.new_$entityType"))->asLinkTo(URL::to("/{$entityType}s/create"))->appendIcon(Icon::create('plus-sign')) !!}
|
||||
@if (Auth::user()->hasPermission('create_all'))
|
||||
{!! Button::primary(trans("texts.new_$entityType"))->asLinkTo(URL::to("/{$entityType}s/create"))->appendIcon(Icon::create('plus-sign')) !!}
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
<li style="margin-top: 4px; margin-bottom: 4px; min-width: 220px; cursor: pointer">
|
||||
@if (isset($user_id) && $user_id != Auth::user()->id)
|
||||
<a href="{{ URL::to("/switch_account/{$user_id}") }}">
|
||||
@else
|
||||
<a href="{{ URL::to("/settings/company_details") }}">
|
||||
@if (Utils::isAdmin())
|
||||
@if (isset($user_id) && $user_id != Auth::user()->id)
|
||||
<a href="{{ URL::to("/switch_account/{$user_id}") }}">
|
||||
@else
|
||||
<a href="{{ URL::to("/settings/company_details") }}">
|
||||
@endif
|
||||
@else
|
||||
<a href="{{ URL::to("/settings/user_details") }}">
|
||||
@endif
|
||||
|
||||
@if (file_exists($logo_path))
|
||||
@ -23,7 +27,6 @@
|
||||
@if (isset($selected) && $selected)
|
||||
</b>
|
||||
@endif
|
||||
|
||||
</a>
|
||||
|
||||
</li>
|
@ -23,7 +23,26 @@
|
||||
{!! Former::text('first_name') !!}
|
||||
{!! Former::text('last_name') !!}
|
||||
{!! Former::text('email') !!}
|
||||
|
||||
{!! Former::checkbox('is_admin')
|
||||
->label(' ')
|
||||
->text(trans('texts.administrator'))
|
||||
->help(trans('texts.administrator_help')) !!}
|
||||
{!! Former::checkbox('permissions[create_all]')
|
||||
->value('create_all')
|
||||
->label(' ')
|
||||
->id('permissions_create_all')
|
||||
->text(trans('texts.user_create_all')) !!}
|
||||
{!! Former::checkbox('permissions[view_all]')
|
||||
->value('view_all')
|
||||
->label(' ')
|
||||
->id('permissions_view_all')
|
||||
->text(trans('texts.user_view_all')) !!}
|
||||
{!! Former::checkbox('permissions[edit_all]')
|
||||
->value('edit_all')
|
||||
->label(' ')
|
||||
->id('permissions_edit_all')
|
||||
->text(trans('texts.user_edit_all')) !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -38,4 +57,15 @@
|
||||
|
||||
@section('onReady')
|
||||
$('#first_name').focus();
|
||||
$('#is_admin, #permissions_view_all').change(fixCheckboxes);
|
||||
function fixCheckboxes(){
|
||||
var adminChecked = $('#is_admin').is(':checked');
|
||||
var viewChecked = $('#permissions_view_all').is(':checked');
|
||||
|
||||
$('#permissions_view_all').prop('disabled', adminChecked);
|
||||
$('#permissions_create_all').prop('disabled', adminChecked);
|
||||
$('#permissions_edit_all').prop('disabled', adminChecked || !viewChecked);
|
||||
if(!viewChecked)$('#permissions_edit_all').prop('checked',false)
|
||||
}
|
||||
fixCheckboxes();
|
||||
@stop
|
Loading…
Reference in New Issue
Block a user