diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 60ac1176aa10..c271968668be 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -7,4 +7,4 @@ We welcome contributions! We'll improve this guide over time...
Guidelines
* Try to follow [PSR-2 guidlines](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
* Create pull requests against the develop branch
-* Submit translations through [Transifex](https://www.transifex.com/invoice-ninja/)
+* Submit translations through [Transifex](https://www.transifex.com/invoice-ninja/invoice-ninja/)
diff --git a/README.md b/README.md
index 03362f3a6e6f..a3133c4c1010 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@
### Pull Requests
* Please create pull requests against the develop branch
-* Submit translations through [Transifex](https://www.transifex.com/invoice-ninja/)
+* Submit translations through [Transifex](https://www.transifex.com/invoice-ninja/invoice-ninja/)
### Contributors
* [Troels Liebe Bentsen](https://github.com/tlbdk)
diff --git a/app/Http/Controllers/AppController.php b/app/Http/Controllers/AppController.php
index a602ae7ecb85..b6f779b9379f 100644
--- a/app/Http/Controllers/AppController.php
+++ b/app/Http/Controllers/AppController.php
@@ -268,7 +268,12 @@ class AppController extends BaseController
Artisan::call('migrate', array('--force' => true));
Artisan::call('db:seed', array('--force' => true, '--class' => "UpdateSeeder"));
Event::fire(new UserSettingsChanged());
- Session::flash('message', trans('texts.processed_updates'));
+
+ // show message with link to Trello board
+ $message = trans('texts.see_whats_new', ['version' => NINJA_VERSION]);
+ $message = link_to(RELEASES_URL, $message, ['target' => '_blank']);
+ $message = sprintf('%s - %s', trans('texts.processed_updates'), $message);
+ Session::flash('warning', $message);
} catch (Exception $e) {
Utils::logError($e);
return Response::make($e->getMessage(), 500);
diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php
index e5b6fd432b1a..d2a0633e5c73 100644
--- a/app/Http/Controllers/ClientController.php
+++ b/app/Http/Controllers/ClientController.php
@@ -72,7 +72,10 @@ class ClientController extends BaseController
public function getDatatable()
{
- return $this->clientService->getDatatable(Input::get('sSearch'));
+ $search = Input::get('sSearch');
+ $userId = Auth::user()->filterId();
+
+ return $this->clientService->getDatatable($search, $userId);
}
/**
@@ -97,8 +100,8 @@ class ClientController extends BaseController
*/
public function show(ClientRequest $request)
{
- $client = $request->entity();
-
+ $client = $request->entity();
+
$user = Auth::user();
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT);
@@ -109,19 +112,19 @@ class ClientController extends BaseController
if (Utils::hasFeature(FEATURE_QUOTES) && $user->can('create', ENTITY_INVOICE)) {
$actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => URL::to('/quotes/create/'.$client->public_id)];
}
-
+
if(!empty($actionLinks)){
$actionLinks[] = \DropdownButton::DIVIDER;
}
-
+
if($user->can('create', ENTITY_PAYMENT)){
$actionLinks[] = ['label' => trans('texts.enter_payment'), 'url' => URL::to('/payments/create/'.$client->public_id)];
}
-
+
if($user->can('create', ENTITY_CREDIT)){
$actionLinks[] = ['label' => trans('texts.enter_credit'), 'url' => URL::to('/credits/create/'.$client->public_id)];
}
-
+
if($user->can('create', ENTITY_EXPENSE)){
$actionLinks[] = ['label' => trans('texts.enter_expense'), 'url' => URL::to('/expenses/create/0/'.$client->public_id)];
}
@@ -174,7 +177,7 @@ class ClientController extends BaseController
public function edit(ClientRequest $request)
{
$client = $request->entity();
-
+
$data = [
'client' => $client,
'method' => 'PUT',
diff --git a/app/Http/Controllers/PublicClientController.php b/app/Http/Controllers/ClientPortalController.php
similarity index 99%
rename from app/Http/Controllers/PublicClientController.php
rename to app/Http/Controllers/ClientPortalController.php
index 79e236d70fc6..56dd183b19fe 100644
--- a/app/Http/Controllers/PublicClientController.php
+++ b/app/Http/Controllers/ClientPortalController.php
@@ -26,7 +26,7 @@ use App\Events\QuoteInvitationWasViewed;
use App\Services\PaymentService;
use Barracuda\ArchiveStream\ZipArchive;
-class PublicClientController extends BaseController
+class ClientPortalController extends BaseController
{
private $invoiceRepo;
private $paymentRepo;
@@ -323,7 +323,7 @@ class PublicClientController extends BaseController
->addColumn('activity_type_id', function ($model) {
$data = [
'client' => Utils::getClientDisplayName($model),
- 'user' => $model->is_system ? ('' . trans('texts.system') . '') : ($model->user_first_name . ' ' . $model->user_last_name),
+ 'user' => $model->is_system ? ('' . trans('texts.system') . '') : ($model->account_name),
'invoice' => $model->invoice,
'contact' => Utils::getClientDisplayName($model),
'payment' => $model->payment ? ' ' . $model->payment : '',
diff --git a/app/Http/Controllers/DashboardApiController.php b/app/Http/Controllers/DashboardApiController.php
index dc837adb9a94..1170812b8356 100644
--- a/app/Http/Controllers/DashboardApiController.php
+++ b/app/Http/Controllers/DashboardApiController.php
@@ -80,8 +80,13 @@ class DashboardApiController extends BaseAPIController
->where('accounts.id', '=', Auth::user()->account_id)
->where('clients.is_deleted', '=', false)
->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();
+ ->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'));
+
+ if (!$view_all) {
+ $balances->where('clients.user_id', '=', $user_id);
+ }
+
+ $balances = $balances->get();
$pastDue = DB::table('invoices')
->leftJoin('clients', 'clients.id', '=', 'invoices.client_id')
diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php
index 5daa8827883a..718d73c67d42 100644
--- a/app/Http/Controllers/DashboardController.php
+++ b/app/Http/Controllers/DashboardController.php
@@ -13,7 +13,7 @@ class DashboardController extends BaseController
{
$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,
@@ -27,17 +27,17 @@ class DashboardController extends BaseController
->where('invoices.is_deleted', '=', false)
->where('invoices.is_recurring', '=', false)
->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('invoices.user_id', '=', null);
$query->where('clients.user_id', '=', $user_id);
});
});
}
-
+
$metrics = $metrics->groupBy('accounts.id')
->first();
@@ -47,11 +47,11 @@ class DashboardController extends BaseController
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
->where('accounts.id', '=', Auth::user()->account_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();
@@ -66,11 +66,11 @@ class DashboardController extends BaseController
->where('invoices.is_deleted', '=', false)
->where('invoices.is_quote', '=', false)
->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();
@@ -82,16 +82,21 @@ class DashboardController extends BaseController
->where('accounts.id', '=', Auth::user()->account_id)
->where('clients.is_deleted', '=', false)
->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();
+ ->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'));
+
+ if (!$view_all) {
+ $balances->where('clients.user_id', '=', $user_id);
+ }
+
+ $balances = $balances->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')
->take(50)
@@ -111,11 +116,11 @@ class DashboardController extends BaseController
->where('invoices.deleted_at', '=', null)
->where('contacts.is_primary', '=', true)
->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)
@@ -136,11 +141,11 @@ class DashboardController extends BaseController
->where('contacts.is_primary', '=', true)
->where('invoices.due_date', '>=', date('Y-m-d'))
->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();
@@ -155,11 +160,11 @@ class DashboardController extends BaseController
->where('clients.is_deleted', '=', false)
->where('contacts.deleted_at', '=', null)
->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)
diff --git a/app/Http/Controllers/ExportController.php b/app/Http/Controllers/ExportController.php
index ebaaa1f6c306..c7f30b03be29 100644
--- a/app/Http/Controllers/ExportController.php
+++ b/app/Http/Controllers/ExportController.php
@@ -84,13 +84,14 @@ class ExportController extends BaseController
if ($key === 'account' || $key === 'title' || $key === 'multiUser') {
continue;
}
+ if ($key === 'recurringInvoices') {
+ $key = 'recurring_invoices';
+ }
$label = trans("texts.{$key}");
$excel->sheet($label, function($sheet) use ($key, $data) {
if ($key === 'quotes') {
$key = 'invoices';
$data['entityType'] = ENTITY_QUOTE;
- } elseif ($key === 'recurringInvoices') {
- $key = 'recurring_invoices';
}
$sheet->loadView("export.{$key}", $data);
});
@@ -107,7 +108,7 @@ class ExportController extends BaseController
'title' => 'Invoice Ninja v' . NINJA_VERSION . ' - ' . $account->formatDateTime($account->getDateTime()),
'multiUser' => $account->users->count() > 1
];
-
+
if ($request->input(ENTITY_CLIENT)) {
$data['clients'] = Client::scope()
->with('user', 'contacts', 'country')
@@ -123,14 +124,14 @@ class ExportController extends BaseController
->with('user', 'client.contacts')
->get();
}
-
+
if ($request->input(ENTITY_TASK)) {
$data['tasks'] = Task::scope()
->with('user', 'client.contacts')
->withArchived()
->get();
}
-
+
if ($request->input(ENTITY_INVOICE)) {
$data['invoices'] = Invoice::scope()
->with('user', 'client.contacts', 'invoice_status')
@@ -138,7 +139,7 @@ class ExportController extends BaseController
->where('is_quote', '=', false)
->where('is_recurring', '=', false)
->get();
-
+
$data['quotes'] = Invoice::scope()
->with('user', 'client.contacts', 'invoice_status')
->withArchived()
@@ -153,7 +154,7 @@ class ExportController extends BaseController
->where('is_recurring', '=', true)
->get();
}
-
+
if ($request->input(ENTITY_PAYMENT)) {
$data['payments'] = Payment::scope()
->withArchived()
@@ -161,7 +162,7 @@ class ExportController extends BaseController
->get();
}
-
+
if ($request->input(ENTITY_VENDOR)) {
$data['clients'] = Vendor::scope()
->with('user', 'vendor_contacts', 'country')
@@ -172,14 +173,14 @@ class ExportController extends BaseController
->with('user', 'vendor.vendor_contacts')
->withTrashed()
->get();
-
+
/*
$data['expenses'] = Credit::scope()
->with('user', 'client.contacts')
->get();
*/
}
-
+
return $data;
}
-}
\ No newline at end of file
+}
diff --git a/app/Http/routes.php b/app/Http/routes.php
index e4e06f76617e..8b52f1fc2ae6 100644
--- a/app/Http/routes.php
+++ b/app/Http/routes.php
@@ -37,36 +37,36 @@ Route::post('/get_started', 'AccountController@getStarted');
// Client visible pages
Route::group(['middleware' => 'auth:client'], function() {
- Route::get('view/{invitation_key}', 'PublicClientController@view');
- Route::get('download/{invitation_key}', 'PublicClientController@download');
+ Route::get('view/{invitation_key}', 'ClientPortalController@view');
+ Route::get('download/{invitation_key}', 'ClientPortalController@download');
Route::get('view', 'HomeController@viewLogo');
Route::get('approve/{invitation_key}', 'QuoteController@approve');
Route::get('payment/{invitation_key}/{payment_type?}/{source_id?}', 'PaymentController@show_payment');
Route::post('payment/{invitation_key}', 'PaymentController@do_payment');
Route::match(['GET', 'POST'], 'complete', 'PaymentController@offsite_payment');
- Route::get('client/paymentmethods', 'PublicClientController@paymentMethods');
- Route::post('client/paymentmethods/verify', 'PublicClientController@verifyPaymentMethod');
- Route::get('client/paymentmethods/add/{payment_type}/{source_id?}', 'PublicClientController@addPaymentMethod');
- Route::post('client/paymentmethods/add/{payment_type}', 'PublicClientController@postAddPaymentMethod');
- Route::post('client/paymentmethods/default', 'PublicClientController@setDefaultPaymentMethod');
- Route::post('client/paymentmethods/{source_id}/remove', 'PublicClientController@removePaymentMethod');
- Route::get('client/quotes', 'PublicClientController@quoteIndex');
- Route::get('client/invoices', 'PublicClientController@invoiceIndex');
- Route::get('client/invoices/recurring', 'PublicClientController@recurringInvoiceIndex');
- Route::post('client/invoices/auto_bill', 'PublicClientController@setAutoBill');
- Route::get('client/documents', 'PublicClientController@documentIndex');
- Route::get('client/payments', 'PublicClientController@paymentIndex');
- Route::get('client/dashboard', 'PublicClientController@dashboard');
- Route::get('client/documents/js/{documents}/{filename}', 'PublicClientController@getDocumentVFSJS');
- Route::get('client/documents/{invitation_key}/{documents}/{filename?}', 'PublicClientController@getDocument');
- Route::get('client/documents/{invitation_key}/{filename?}', 'PublicClientController@getInvoiceDocumentsZip');
+ Route::get('client/paymentmethods', 'ClientPortalController@paymentMethods');
+ Route::post('client/paymentmethods/verify', 'ClientPortalController@verifyPaymentMethod');
+ Route::get('client/paymentmethods/add/{payment_type}/{source_id?}', 'ClientPortalController@addPaymentMethod');
+ Route::post('client/paymentmethods/add/{payment_type}', 'ClientPortalController@postAddPaymentMethod');
+ Route::post('client/paymentmethods/default', 'ClientPortalController@setDefaultPaymentMethod');
+ Route::post('client/paymentmethods/{source_id}/remove', 'ClientPortalController@removePaymentMethod');
+ Route::get('client/quotes', 'ClientPortalController@quoteIndex');
+ Route::get('client/invoices', 'ClientPortalController@invoiceIndex');
+ Route::get('client/invoices/recurring', 'ClientPortalController@recurringInvoiceIndex');
+ Route::post('client/invoices/auto_bill', 'ClientPortalController@setAutoBill');
+ Route::get('client/documents', 'ClientPortalController@documentIndex');
+ Route::get('client/payments', 'ClientPortalController@paymentIndex');
+ Route::get('client/dashboard', 'ClientPortalController@dashboard');
+ Route::get('client/documents/js/{documents}/{filename}', 'ClientPortalController@getDocumentVFSJS');
+ Route::get('client/documents/{invitation_key}/{documents}/{filename?}', 'ClientPortalController@getDocument');
+ Route::get('client/documents/{invitation_key}/{filename?}', 'ClientPortalController@getInvoiceDocumentsZip');
- Route::get('api/client.quotes', array('as'=>'api.client.quotes', 'uses'=>'PublicClientController@quoteDatatable'));
- Route::get('api/client.invoices', array('as'=>'api.client.invoices', 'uses'=>'PublicClientController@invoiceDatatable'));
- Route::get('api/client.recurring_invoices', array('as'=>'api.client.recurring_invoices', 'uses'=>'PublicClientController@recurringInvoiceDatatable'));
- Route::get('api/client.documents', array('as'=>'api.client.documents', 'uses'=>'PublicClientController@documentDatatable'));
- Route::get('api/client.payments', array('as'=>'api.client.payments', 'uses'=>'PublicClientController@paymentDatatable'));
- Route::get('api/client.activity', array('as'=>'api.client.activity', 'uses'=>'PublicClientController@activityDatatable'));
+ Route::get('api/client.quotes', array('as'=>'api.client.quotes', 'uses'=>'ClientPortalController@quoteDatatable'));
+ Route::get('api/client.invoices', array('as'=>'api.client.invoices', 'uses'=>'ClientPortalController@invoiceDatatable'));
+ Route::get('api/client.recurring_invoices', array('as'=>'api.client.recurring_invoices', 'uses'=>'ClientPortalController@recurringInvoiceDatatable'));
+ Route::get('api/client.documents', array('as'=>'api.client.documents', 'uses'=>'ClientPortalController@documentDatatable'));
+ Route::get('api/client.payments', array('as'=>'api.client.payments', 'uses'=>'ClientPortalController@paymentDatatable'));
+ Route::get('api/client.activity', array('as'=>'api.client.activity', 'uses'=>'ClientPortalController@activityDatatable'));
});
@@ -190,7 +190,7 @@ Route::group(['middleware' => 'auth:user'], function() {
Route::resource('expenses', 'ExpenseController');
Route::get('expenses/create/{vendor_id?}/{client_id?}', 'ExpenseController@create');
Route::get('api/expense', array('as'=>'api.expenses', 'uses'=>'ExpenseController@getDatatable'));
- Route::get('api/expenseVendor/{id}', array('as'=>'api.expense', 'uses'=>'ExpenseController@getDatatableVendor'));
+ Route::get('api/vendor_expense/{id}', array('as'=>'api.expense', 'uses'=>'ExpenseController@getDatatableVendor'));
Route::post('expenses/bulk', 'ExpenseController@bulk');
});
diff --git a/app/Models/DateFormat.php b/app/Models/DateFormat.php
index b343fd422657..47afafb4cc76 100644
--- a/app/Models/DateFormat.php
+++ b/app/Models/DateFormat.php
@@ -5,4 +5,11 @@ use Eloquent;
class DateFormat extends Eloquent
{
public $timestamps = false;
+
+ public function __toString()
+ {
+ $date = mktime(0, 0, 0, 12, 31, date('Y'));
+
+ return date($this->format, $date);
+ }
}
diff --git a/app/Models/DatetimeFormat.php b/app/Models/DatetimeFormat.php
index 1d7ba8b93657..6b7edf85ec63 100644
--- a/app/Models/DatetimeFormat.php
+++ b/app/Models/DatetimeFormat.php
@@ -5,4 +5,11 @@ use Eloquent;
class DatetimeFormat extends Eloquent
{
public $timestamps = false;
+
+ public function __toString()
+ {
+ $date = mktime(0, 0, 0, 12, 31, date('Y'));
+
+ return date($this->format, $date);
+ }
}
diff --git a/app/Models/User.php b/app/Models/User.php
index 71069d25821c..9dab5e759a15 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -20,8 +20,8 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
'create_all' => 0b0001,
'view_all' => 0b0010,
'edit_all' => 0b0100,
- );
-
+ );
+
use Authenticatable, Authorizable, CanResetPassword;
/**
@@ -168,7 +168,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
{
return Session::get(SESSION_COUNTER, 0);
}
-
+
public function afterSave($success = true, $forced = false)
{
if ($this->email) {
@@ -199,8 +199,8 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
return MAX_NUM_VENDORS;
}
-
-
+
+
public function getRememberToken()
{
return $this->remember_token;
@@ -265,9 +265,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
&& $this->email != $this->getOriginal('email')
&& $this->getOriginal('confirmed');
}
-
-
-
+
+
+
/**
* Set the permissions attribute on the model.
*
@@ -277,7 +277,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
protected function setPermissionsAttribute($value){
if(empty($value)) {
$this->attributes['permissions'] = 0;
- } else {
+ } else {
$bitmask = 0;
foreach($value as $permission){
$bitmask = $bitmask | static::$all_permissions[$permission];
@@ -285,10 +285,10 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
$this->attributes['permissions'] = $bitmask;
}
-
+
return $this;
}
-
+
/**
* Expands the value of the permissions attribute
*
@@ -302,10 +302,10 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
$permissions[$permission] = $permission;
}
}
-
+
return $permissions;
}
-
+
/**
* Checks to see if the user has the required permission
*
@@ -325,13 +325,17 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
return count(array_intersect($permission, $this->permissions)) > 0;
}
}
-
+
return false;
}
-
+
public function owns($entity) {
return !empty($entity->user_id) && $entity->user_id == $this->id;
}
+
+ public function filterId() {
+ return $this->hasPermission('view_all') ? false : $this->id;
+ }
}
User::updating(function ($user) {
diff --git a/app/Ninja/Datatables/AccountGatewayDatatable.php b/app/Ninja/Datatables/AccountGatewayDatatable.php
new file mode 100644
index 000000000000..ad16fc39878a
--- /dev/null
+++ b/app/Ninja/Datatables/AccountGatewayDatatable.php
@@ -0,0 +1,110 @@
+deleted_at) {
+ return $model->name;
+ } elseif ($model->gateway_id != GATEWAY_WEPAY) {
+ return link_to("gateways/{$model->public_id}/edit", $model->name)->toHtml();
+ } else {
+ $accountGateway = AccountGateway::find($model->id);
+ $config = $accountGateway->getConfig();
+ $endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
+ $wepayAccountId = $config->accountId;
+ $wepayState = isset($config->state)?$config->state:null;
+ $linkText = $model->name;
+ $url = $endpoint.'account/'.$wepayAccountId;
+ $wepay = \Utils::setupWepay($accountGateway);
+ $html = link_to($url, $linkText, array('target'=>'_blank'))->toHtml();
+
+ try {
+ if ($wepayState == 'action_required') {
+ $updateUri = $wepay->request('/account/get_update_uri', array(
+ 'account_id' => $wepayAccountId,
+ 'redirect_uri' => URL::to('gateways'),
+ ));
+
+ $linkText .= ' ('.trans('texts.action_required').')';
+ $url = $updateUri->uri;
+ $html = "{$linkText}";
+ $model->setupUrl = $url;
+ } elseif ($wepayState == 'pending') {
+ $linkText .= ' ('.trans('texts.resend_confirmation_email').')';
+ $model->resendConfirmationUrl = $url = URL::to("gateways/{$accountGateway->public_id}/resend_confirmation");
+ $html = link_to($url, $linkText)->toHtml();
+ }
+ } catch(\WePayException $ex){}
+
+ return $html;
+ }
+ }
+ ],
+ [
+ 'payment_type',
+ function ($model) {
+ return Gateway::getPrettyPaymentType($model->gateway_id);
+ }
+ ],
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ uctrans('texts.resend_confirmation_email'),
+ function ($model) {
+ return $model->resendConfirmationUrl;
+ },
+ function($model) {
+ return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY && !empty($model->resendConfirmationUrl);
+ }
+ ], [
+ uctrans('texts.finish_setup'),
+ function ($model) {
+ return $model->setupUrl;
+ },
+ function($model) {
+ return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY && !empty($model->setupUrl);
+ }
+ ] , [
+ uctrans('texts.edit_gateway'),
+ function ($model) {
+ return URL::to("gateways/{$model->public_id}/edit");
+ },
+ function($model) {
+ return !$model->deleted_at;
+ }
+ ], [
+ uctrans('texts.manage_wepay_account'),
+ function ($model) {
+ $accountGateway = AccountGateway::find($model->id);
+ $endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
+ return array(
+ 'url' => $endpoint.'account/'.$accountGateway->getConfig()->accountId,
+ 'attributes' => 'target="_blank"'
+ );
+ },
+ function($model) {
+ return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY;
+ }
+ ]
+ ];
+ }
+
+}
diff --git a/app/Ninja/Datatables/ActivityDatatable.php b/app/Ninja/Datatables/ActivityDatatable.php
new file mode 100644
index 000000000000..5f74bbbe54fb
--- /dev/null
+++ b/app/Ninja/Datatables/ActivityDatatable.php
@@ -0,0 +1,52 @@
+created_at));
+ }
+ ],
+ [
+ 'activity_type_id',
+ function ($model) {
+ $data = [
+ 'client' => link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model))->toHtml(),
+ 'user' => $model->is_system ? '' . trans('texts.system') . '' : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email),
+ 'invoice' => $model->invoice ? link_to('/invoices/' . $model->invoice_public_id, $model->is_recurring ? trans('texts.recurring_invoice') : $model->invoice)->toHtml() : null,
+ 'quote' => $model->invoice ? link_to('/quotes/' . $model->invoice_public_id, $model->invoice)->toHtml() : null,
+ 'contact' => $model->contact_id ? link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model))->toHtml() : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email),
+ 'payment' => $model->payment ?: '',
+ 'credit' => $model->payment_amount ? Utils::formatMoney($model->credit, $model->currency_id, $model->country_id) : '',
+ 'payment_amount' => $model->payment_amount ? Utils::formatMoney($model->payment_amount, $model->currency_id, $model->country_id) : null,
+ 'adjustment' => $model->adjustment ? Utils::formatMoney($model->adjustment, $model->currency_id, $model->country_id) : null
+ ];
+
+ return trans("texts.activity_{$model->activity_type_id}", $data);
+ }
+ ],
+ [
+ 'balance',
+ function ($model) {
+ return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id);
+ }
+ ],
+ [
+ 'adjustment',
+ function ($model) {
+ return $model->adjustment != 0 ? Utils::wrapAdjustment($model->adjustment, $model->currency_id, $model->country_id) : '';
+ }
+ ]
+ ];
+ }
+}
diff --git a/app/Ninja/Datatables/BankAccountDatatable.php b/app/Ninja/Datatables/BankAccountDatatable.php
new file mode 100644
index 000000000000..48bc2672f1c9
--- /dev/null
+++ b/app/Ninja/Datatables/BankAccountDatatable.php
@@ -0,0 +1,42 @@
+public_id}/edit", $model->bank_name)->toHtml();
+ },
+ ],
+ [
+ 'bank_library_id',
+ function ($model) {
+ return 'OFX';
+ }
+ ],
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ uctrans('texts.edit_bank_account'),
+ function ($model) {
+ return URL::to("bank_accounts/{$model->public_id}/edit");
+ },
+ ]
+ ];
+ }
+
+
+}
diff --git a/app/Ninja/Datatables/ClientDatatable.php b/app/Ninja/Datatables/ClientDatatable.php
new file mode 100644
index 000000000000..4b0ca68b0544
--- /dev/null
+++ b/app/Ninja/Datatables/ClientDatatable.php
@@ -0,0 +1,136 @@
+public_id}", $model->name ?: '')->toHtml();
+ }
+ ],
+ [
+ 'first_name',
+ function ($model) {
+ return link_to("clients/{$model->public_id}", $model->first_name.' '.$model->last_name)->toHtml();
+ }
+ ],
+ [
+ 'email',
+ function ($model) {
+ return link_to("clients/{$model->public_id}", $model->email ?: '')->toHtml();
+ }
+ ],
+ [
+ 'clients.created_at',
+ function ($model) {
+ return Utils::timestampToDateString(strtotime($model->created_at));
+ }
+ ],
+ [
+ 'last_login',
+ function ($model) {
+ return Utils::timestampToDateString(strtotime($model->last_login));
+ }
+ ],
+ [
+ 'balance',
+ function ($model) {
+ return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id);
+ }
+ ]
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ trans('texts.edit_client'),
+ function ($model) {
+ return URL::to("clients/{$model->public_id}/edit");
+ },
+ function ($model) {
+ return Auth::user()->can('editByOwner', [ENTITY_CLIENT, $model->user_id]);
+ }
+ ],
+ [
+ '--divider--', function(){return false;},
+ function ($model) {
+ $user = Auth::user();
+ return $user->can('editByOwner', [ENTITY_CLIENT, $model->user_id]) && ($user->can('create', ENTITY_TASK) || $user->can('create', ENTITY_INVOICE));
+ }
+ ],
+ [
+ trans('texts.new_task'),
+ function ($model) {
+ return URL::to("tasks/create/{$model->public_id}");
+ },
+ function ($model) {
+ return Auth::user()->can('create', ENTITY_TASK);
+ }
+ ],
+ [
+ trans('texts.new_invoice'),
+ function ($model) {
+ return URL::to("invoices/create/{$model->public_id}");
+ },
+ function ($model) {
+ return Auth::user()->can('create', ENTITY_INVOICE);
+ }
+ ],
+ [
+ trans('texts.new_quote'),
+ function ($model) {
+ return URL::to("quotes/create/{$model->public_id}");
+ },
+ function ($model) {
+ return Auth::user()->hasFeature(FEATURE_QUOTES) && Auth::user()->can('create', ENTITY_INVOICE);
+ }
+ ],
+ [
+ '--divider--', function(){return false;},
+ function ($model) {
+ $user = Auth::user();
+ return ($user->can('create', ENTITY_TASK) || $user->can('create', ENTITY_INVOICE)) && ($user->can('create', ENTITY_PAYMENT) || $user->can('create', ENTITY_CREDIT) || $user->can('create', ENTITY_EXPENSE));
+ }
+ ],
+ [
+ trans('texts.enter_payment'),
+ function ($model) {
+ return URL::to("payments/create/{$model->public_id}");
+ },
+ function ($model) {
+ return Auth::user()->can('create', ENTITY_PAYMENT);
+ }
+ ],
+ [
+ trans('texts.enter_credit'),
+ function ($model) {
+ return URL::to("credits/create/{$model->public_id}");
+ },
+ function ($model) {
+ return Auth::user()->can('create', ENTITY_CREDIT);
+ }
+ ],
+ [
+ trans('texts.enter_expense'),
+ function ($model) {
+ return URL::to("expenses/create/0/{$model->public_id}");
+ },
+ function ($model) {
+ return Auth::user()->can('create', ENTITY_EXPENSE);
+ }
+ ]
+ ];
+ }
+
+}
diff --git a/app/Ninja/Datatables/CreditDatatable.php b/app/Ninja/Datatables/CreditDatatable.php
new file mode 100644
index 000000000000..7f258e377d1d
--- /dev/null
+++ b/app/Ninja/Datatables/CreditDatatable.php
@@ -0,0 +1,66 @@
+can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){
+ return Utils::getClientDisplayName($model);
+ }
+
+ return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : '';
+ },
+ ! $this->hideClient
+ ],
+ [
+ 'amount',
+ function ($model) {
+ return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id) . '';
+ }
+ ],
+ [
+ 'balance',
+ function ($model) {
+ return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id);
+ }
+ ],
+ [
+ 'credit_date',
+ function ($model) {
+ return Utils::fromSqlDate($model->credit_date);
+ }
+ ],
+ [
+ 'private_notes',
+ function ($model) {
+ return $model->private_notes;
+ }
+ ]
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ trans('texts.apply_credit'),
+ function ($model) {
+ return URL::to("payments/create/{$model->client_public_id}") . '?paymentTypeId=1';
+ },
+ function ($model) {
+ return Auth::user()->can('create', ENTITY_PAYMENT);
+ }
+ ]
+ ];
+ }
+}
diff --git a/app/Ninja/Datatables/EntityDatatable.php b/app/Ninja/Datatables/EntityDatatable.php
new file mode 100644
index 000000000000..085645ff2069
--- /dev/null
+++ b/app/Ninja/Datatables/EntityDatatable.php
@@ -0,0 +1,24 @@
+isBulkEdit = $isBulkEdit;
+ $this->hideClient = $hideClient;
+ }
+
+ public function columns()
+ {
+ return [];
+ }
+
+ public function actions()
+ {
+ return [];
+ }
+}
diff --git a/app/Ninja/Datatables/ExpenseDatatable.php b/app/Ninja/Datatables/ExpenseDatatable.php
new file mode 100644
index 000000000000..29bbbe0c087d
--- /dev/null
+++ b/app/Ninja/Datatables/ExpenseDatatable.php
@@ -0,0 +1,134 @@
+vendor_public_id) {
+ if(!Auth::user()->can('viewByOwner', [ENTITY_VENDOR, $model->vendor_user_id])){
+ return $model->vendor_name;
+ }
+
+ return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml();
+ } else {
+ return '';
+ }
+ },
+ ! $this->hideClient
+ ],
+ [
+ 'client_name',
+ function ($model)
+ {
+ if ($model->client_public_id) {
+ if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){
+ return Utils::getClientDisplayName($model);
+ }
+
+ return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
+ } else {
+ return '';
+ }
+ },
+ ! $this->hideClient
+ ],
+ [
+ 'expense_date',
+ function ($model) {
+ if(!Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id])){
+ return Utils::fromSqlDate($model->expense_date);
+ }
+
+ return link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date))->toHtml();
+ }
+ ],
+ [
+ 'amount',
+ function ($model) {
+ // show both the amount and the converted amount
+ if ($model->exchange_rate != 1) {
+ $converted = round($model->amount * $model->exchange_rate, 2);
+ return Utils::formatMoney($model->amount, $model->expense_currency_id) . ' | ' .
+ Utils::formatMoney($converted, $model->invoice_currency_id);
+ } else {
+ return Utils::formatMoney($model->amount, $model->expense_currency_id);
+ }
+ }
+ ],
+ [
+ 'public_notes',
+ function ($model) {
+ return $model->public_notes != null ? substr($model->public_notes, 0, 100) : '';
+ }
+ ],
+ [
+ 'expense_status_id',
+ function ($model) {
+ return self::getStatusLabel($model->invoice_id, $model->should_be_invoiced);
+ }
+ ],
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ trans('texts.edit_expense'),
+ function ($model) {
+ return URL::to("expenses/{$model->public_id}/edit") ;
+ },
+ function ($model) {
+ return Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id]);
+ }
+ ],
+ [
+ trans('texts.view_invoice'),
+ function ($model) {
+ return URL::to("/invoices/{$model->invoice_public_id}/edit");
+ },
+ function ($model) {
+ return $model->invoice_public_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id]);
+ }
+ ],
+ [
+ trans('texts.invoice_expense'),
+ function ($model) {
+ return "javascript:invoiceEntity({$model->public_id})";
+ },
+ function ($model) {
+ return ! $model->invoice_id && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('create', ENTITY_INVOICE);
+ }
+ ],
+ ];
+ }
+
+
+ private function getStatusLabel($invoiceId, $shouldBeInvoiced)
+ {
+ if ($invoiceId) {
+ $label = trans('texts.invoiced');
+ $class = 'success';
+ } elseif ($shouldBeInvoiced) {
+ $label = trans('texts.pending');
+ $class = 'warning';
+ } else {
+ $label = trans('texts.logged');
+ $class = 'primary';
+ }
+
+ return "
$label
";
+ }
+
+}
diff --git a/app/Ninja/Datatables/InvoiceDatatable.php b/app/Ninja/Datatables/InvoiceDatatable.php
new file mode 100644
index 000000000000..27b3343561fd
--- /dev/null
+++ b/app/Ninja/Datatables/InvoiceDatatable.php
@@ -0,0 +1,193 @@
+entityType;
+
+ return [
+ [
+ 'invoice_number',
+ function ($model) use ($entityType) {
+ if(!Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id])){
+ 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(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){
+ return Utils::getClientDisplayName($model);
+ }
+ return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
+ },
+ ! $this->hideClient
+ ],
+ [
+ 'invoice_date',
+ function ($model) {
+ return Utils::fromSqlDate($model->invoice_date);
+ }
+ ],
+ [
+ 'amount',
+ function ($model) {
+ return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id);
+ }
+ ],
+ [
+ 'balance',
+ function ($model) {
+ return $model->partial > 0 ?
+ trans('texts.partial_remaining', [
+ 'partial' => Utils::formatMoney($model->partial, $model->currency_id, $model->country_id),
+ 'balance' => Utils::formatMoney($model->balance, $model->currency_id, $model->country_id)]
+ ) :
+ Utils::formatMoney($model->balance, $model->currency_id, $model->country_id);
+ },
+ $entityType == ENTITY_INVOICE
+ ],
+ [
+ 'due_date',
+ function ($model) {
+ return Utils::fromSqlDate($model->due_date);
+ },
+ ],
+ [
+ 'invoice_status_name',
+ function ($model) use ($entityType) {
+ return $model->quote_invoice_id ? link_to("invoices/{$model->quote_invoice_id}/edit", trans('texts.converted'))->toHtml() : self::getStatusLabel($model);
+ }
+ ]
+ ];
+ }
+
+ public function actions()
+ {
+ $entityType = $this->entityType;
+
+ return [
+ [
+ trans("texts.edit_{$entityType}"),
+ function ($model) use ($entityType) {
+ return URL::to("{$entityType}s/{$model->public_id}/edit");
+ },
+ function ($model) {
+ return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
+ }
+ ],
+ [
+ trans("texts.clone_{$entityType}"),
+ function ($model) use ($entityType) {
+ return URL::to("{$entityType}s/{$model->public_id}/clone");
+ },
+ function ($model) {
+ return Auth::user()->can('create', ENTITY_INVOICE);
+ }
+ ],
+ [
+ trans("texts.view_history"),
+ function ($model) use ($entityType) {
+ return URL::to("{$entityType}s/{$entityType}_history/{$model->public_id}");
+ }
+ ],
+ [
+ '--divider--', function(){return false;},
+ function ($model) {
+ return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]) || Auth::user()->can('create', ENTITY_PAYMENT);
+ }
+ ],
+ [
+ trans("texts.mark_sent"),
+ function ($model) {
+ return "javascript:markEntity({$model->public_id})";
+ },
+ function ($model) {
+ return $model->invoice_status_id < INVOICE_STATUS_SENT && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
+ }
+ ],
+ [
+ trans('texts.enter_payment'),
+ function ($model) {
+ return URL::to("payments/create/{$model->client_public_id}/{$model->public_id}");
+ },
+ function ($model) use ($entityType) {
+ return $entityType == ENTITY_INVOICE && $model->balance > 0 && Auth::user()->can('create', ENTITY_PAYMENT);
+ }
+ ],
+ [
+ trans("texts.view_quote"),
+ function ($model) {
+ return URL::to("quotes/{$model->quote_id}/edit");
+ },
+ function ($model) use ($entityType) {
+ return $entityType == ENTITY_INVOICE && $model->quote_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
+ }
+ ],
+ [
+ trans("texts.view_invoice"),
+ function ($model) {
+ return URL::to("invoices/{$model->quote_invoice_id}/edit");
+ },
+ function ($model) use ($entityType) {
+ return $entityType == ENTITY_QUOTE && $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
+ }
+ ],
+ [
+ trans("texts.convert_to_invoice"),
+ function ($model) {
+ return "javascript:convertEntity({$model->public_id})";
+ },
+ function ($model) use ($entityType) {
+ return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
+ }
+ ]
+ ];
+ }
+
+ private function getStatusLabel($model)
+ {
+ $entityType = $this->entityType;
+
+ // check if invoice is overdue
+ if (Utils::parseFloat($model->balance) && $model->due_date && $model->due_date != '0000-00-00') {
+ if (\DateTime::createFromFormat('Y-m-d', $model->due_date) < new \DateTime("now")) {
+ $label = $entityType == ENTITY_INVOICE ? trans('texts.overdue') : trans('texts.expired');
+ return "" . $label . "
";
+ }
+ }
+
+ $label = trans("texts.status_" . strtolower($model->invoice_status_name));
+ $class = 'default';
+ switch ($model->invoice_status_id) {
+ case INVOICE_STATUS_SENT:
+ $class = 'info';
+ break;
+ case INVOICE_STATUS_VIEWED:
+ $class = 'warning';
+ break;
+ case INVOICE_STATUS_APPROVED:
+ $class = 'success';
+ break;
+ case INVOICE_STATUS_PARTIAL:
+ $class = 'primary';
+ break;
+ case INVOICE_STATUS_PAID:
+ $class = 'success';
+ break;
+ }
+
+ return "$label
";
+ }
+
+}
diff --git a/app/Ninja/Datatables/PaymentDatatable.php b/app/Ninja/Datatables/PaymentDatatable.php
new file mode 100644
index 000000000000..22006bf742e1
--- /dev/null
+++ b/app/Ninja/Datatables/PaymentDatatable.php
@@ -0,0 +1,158 @@
+can('editByOwner', [ENTITY_INVOICE, $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(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){
+ return Utils::getClientDisplayName($model);
+ }
+
+ return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : '';
+ },
+ ! $this->hideClient
+ ],
+ [
+ 'transaction_reference',
+ function ($model) {
+ return $model->transaction_reference ? $model->transaction_reference : 'Manual entry';
+ }
+ ],
+ [
+ 'payment_type',
+ function ($model) {
+ return ($model->payment_type && !$model->last4) ? $model->payment_type : ($model->account_gateway_id ? $model->gateway_name : '');
+ }
+ ],
+ [
+ 'source',
+ function ($model) {
+ $code = str_replace(' ', '', strtolower($model->payment_type));
+ $card_type = trans("texts.card_" . $code);
+ if ($model->payment_type_id != PAYMENT_TYPE_ACH) {
+ if($model->last4) {
+ $expiration = trans('texts.card_expiration', array('expires' => Utils::fromSqlDate($model->expiration, false)->format('m/y')));
+ return '
•••' . $model->last4 . ' ' . $expiration;
+ } elseif ($model->email) {
+ return $model->email;
+ }
+ } elseif ($model->last4) {
+ $bankData = PaymentMethod::lookupBankData($model->routing_number);
+ if (is_object($bankData)) {
+ return $bankData->name.' •••' . $model->last4;
+ } elseif($model->last4) {
+ return '
•••' . $model->last4;
+ }
+ }
+ }
+ ],
+ [
+ 'amount',
+ function ($model) {
+ return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id);
+ }
+ ],
+ [
+ 'payment_date',
+ function ($model) {
+ return Utils::dateToString($model->payment_date);
+ }
+ ],
+ [
+ 'payment_status_name',
+ function ($model) {
+ return self::getStatusLabel($model);
+ }
+ ]
+ ];
+ }
+
+
+ public function actions()
+ {
+ return [
+ [
+ trans('texts.edit_payment'),
+ function ($model) {
+ return URL::to("payments/{$model->public_id}/edit");
+ },
+ function ($model) {
+ return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]);
+ }
+ ],
+ [
+ trans('texts.refund_payment'),
+ function ($model) {
+ $max_refund = number_format($model->amount - $model->refunded, 2);
+ $formatted = Utils::formatMoney($max_refund, $model->currency_id, $model->country_id);
+ $symbol = Utils::getFromCache($model->currency_id ? $model->currency_id : 1, 'currencies')->symbol ;
+ return "javascript:showRefundModal({$model->public_id}, '{$max_refund}', '{$formatted}', '{$symbol}')";
+ },
+ function ($model) {
+ return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]) && $model->payment_status_id >= PAYMENT_STATUS_COMPLETED &&
+ $model->refunded < $model->amount &&
+ (
+ ($model->transaction_reference && in_array($model->gateway_id , static::$refundableGateways))
+ || $model->payment_type_id == PAYMENT_TYPE_CREDIT
+ );
+ }
+ ]
+ ];
+ }
+
+ private function getStatusLabel($model)
+ {
+ $label = trans("texts.status_" . strtolower($model->payment_status_name));
+ $class = 'default';
+ switch ($model->payment_status_id) {
+ case PAYMENT_STATUS_PENDING:
+ $class = 'info';
+ break;
+ case PAYMENT_STATUS_COMPLETED:
+ $class = 'success';
+ break;
+ case PAYMENT_STATUS_FAILED:
+ $class = 'danger';
+ break;
+ case PAYMENT_STATUS_PARTIALLY_REFUNDED:
+ $label = trans('texts.status_partially_refunded_amount', [
+ 'amount' => Utils::formatMoney($model->refunded, $model->currency_id, $model->country_id),
+ ]);
+ $class = 'primary';
+ break;
+ case PAYMENT_STATUS_VOIDED:
+ case PAYMENT_STATUS_REFUNDED:
+ $class = 'default';
+ break;
+ }
+ return "$label
";
+ }
+}
diff --git a/app/Ninja/Datatables/ProductDatatable.php b/app/Ninja/Datatables/ProductDatatable.php
new file mode 100644
index 000000000000..a5b3cbfc218d
--- /dev/null
+++ b/app/Ninja/Datatables/ProductDatatable.php
@@ -0,0 +1,55 @@
+public_id.'/edit', $model->product_key)->toHtml();
+ }
+ ],
+ [
+ 'notes',
+ function ($model) {
+ return nl2br(Str::limit($model->notes, 100));
+ }
+ ],
+ [
+ 'cost',
+ function ($model) {
+ return Utils::formatMoney($model->cost);
+ }
+ ],
+ [
+ 'tax_rate',
+ function ($model) {
+ return $model->tax_rate ? ($model->tax_name . ' ' . $model->tax_rate . '%') : '';
+ },
+ Auth::user()->account->invoice_item_taxes
+ ]
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ uctrans('texts.edit_product'),
+ function ($model) {
+ return URL::to("products/{$model->public_id}/edit");
+ }
+ ]
+ ];
+ }
+
+}
diff --git a/app/Ninja/Datatables/RecurringInvoiceDatatable.php b/app/Ninja/Datatables/RecurringInvoiceDatatable.php
new file mode 100644
index 000000000000..7b5365814eca
--- /dev/null
+++ b/app/Ninja/Datatables/RecurringInvoiceDatatable.php
@@ -0,0 +1,63 @@
+public_id}", $model->frequency)->toHtml();
+ }
+ ],
+ [
+ 'client_name',
+ function ($model) {
+ return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
+ },
+ ! $this->hideClient
+ ],
+ [
+ 'start_date',
+ function ($model) {
+ return Utils::fromSqlDate($model->start_date);
+ }
+ ],
+ [
+ 'end_date',
+ function ($model) {
+ return Utils::fromSqlDate($model->end_date);
+ }
+ ],
+ [
+ 'amount',
+ function ($model) {
+ return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id);
+ }
+ ]
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ trans('texts.edit_invoice'),
+ function ($model) {
+ return URL::to("invoices/{$model->public_id}/edit");
+ },
+ function ($model) {
+ return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
+ }
+ ]
+ ];
+ }
+
+}
diff --git a/app/Ninja/Datatables/TaskDatatable.php b/app/Ninja/Datatables/TaskDatatable.php
new file mode 100644
index 000000000000..6f460b418e86
--- /dev/null
+++ b/app/Ninja/Datatables/TaskDatatable.php
@@ -0,0 +1,113 @@
+can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){
+ return Utils::getClientDisplayName($model);
+ }
+
+ return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : '';
+ },
+ ! $this->hideClient
+ ],
+ [
+ 'created_at',
+ function ($model) {
+ return link_to("tasks/{$model->public_id}/edit", Task::calcStartTime($model))->toHtml();
+ }
+ ],
+ [
+ 'time_log',
+ function($model) {
+ return Utils::formatTime(Task::calcDuration($model));
+ }
+ ],
+ [
+ 'description',
+ function ($model) {
+ return $model->description;
+ }
+ ],
+ [
+ 'invoice_number',
+ function ($model) {
+ return self::getStatusLabel($model);
+ }
+ ]
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ trans('texts.edit_task'),
+ function ($model) {
+ return URL::to('tasks/'.$model->public_id.'/edit');
+ },
+ function ($model) {
+ return (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]);
+ }
+ ],
+ [
+ trans('texts.view_invoice'),
+ function ($model) {
+ return URL::to("/invoices/{$model->invoice_public_id}/edit");
+ },
+ function ($model) {
+ return $model->invoice_number && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id]);
+ }
+ ],
+ [
+ trans('texts.stop_task'),
+ function ($model) {
+ return "javascript:stopTask({$model->public_id})";
+ },
+ function ($model) {
+ return $model->is_running && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]);
+ }
+ ],
+ [
+ trans('texts.invoice_task'),
+ function ($model) {
+ return "javascript:invoiceEntity({$model->public_id})";
+ },
+ function ($model) {
+ return ! $model->invoice_number && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('create', ENTITY_INVOICE);
+ }
+ ]
+ ];
+ }
+
+ private function getStatusLabel($model)
+ {
+ if ($model->invoice_number) {
+ $class = 'success';
+ $label = trans('texts.invoiced');
+ } elseif ($model->is_running) {
+ $class = 'primary';
+ $label = trans('texts.running');
+ } else {
+ $class = 'default';
+ $label = trans('texts.logged');
+ }
+
+ return "$label
";
+ }
+
+
+}
diff --git a/app/Ninja/Datatables/TaxRateDatatable.php b/app/Ninja/Datatables/TaxRateDatatable.php
new file mode 100644
index 000000000000..d6cb0cb54f03
--- /dev/null
+++ b/app/Ninja/Datatables/TaxRateDatatable.php
@@ -0,0 +1,41 @@
+public_id}/edit", $model->name)->toHtml();
+ }
+ ],
+ [
+ 'rate',
+ function ($model) {
+ return $model->rate . '%';
+ }
+ ]
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ uctrans('texts.edit_tax_rate'),
+ function ($model) {
+ return URL::to("tax_rates/{$model->public_id}/edit");
+ }
+ ]
+ ];
+ }
+
+}
diff --git a/app/Ninja/Datatables/TokenDatatable.php b/app/Ninja/Datatables/TokenDatatable.php
new file mode 100644
index 000000000000..e0e248f15cee
--- /dev/null
+++ b/app/Ninja/Datatables/TokenDatatable.php
@@ -0,0 +1,41 @@
+public_id}/edit", $model->name)->toHtml();
+ }
+ ],
+ [
+ 'token',
+ function ($model) {
+ return $model->token;
+ }
+ ]
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ uctrans('texts.edit_token'),
+ function ($model) {
+ return URL::to("tokens/{$model->public_id}/edit");
+ }
+ ]
+ ];
+ }
+
+}
diff --git a/app/Ninja/Datatables/UserDatatable.php b/app/Ninja/Datatables/UserDatatable.php
new file mode 100644
index 000000000000..a6f267fdbd00
--- /dev/null
+++ b/app/Ninja/Datatables/UserDatatable.php
@@ -0,0 +1,96 @@
+public_id ? link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name)->toHtml() : ($model->first_name.' '.$model->last_name);
+ }
+ ],
+ [
+ 'email',
+ function ($model) {
+ return $model->email;
+ }
+ ],
+ [
+ 'confirmed',
+ function ($model) {
+ if (!$model->public_id) {
+ return self::getStatusLabel(USER_STATE_OWNER);
+ } elseif ($model->deleted_at) {
+ return self::getStatusLabel(USER_STATE_DISABLED);
+ } elseif ($model->confirmed) {
+ if($model->is_admin){
+ return self::getStatusLabel(USER_STATE_ADMIN);
+ } else {
+ return self::getStatusLabel(USER_STATE_ACTIVE);
+ }
+ } else {
+ return self::getStatusLabel(USER_STATE_PENDING);
+ }
+ }
+ ],
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ uctrans('texts.edit_user'),
+ function ($model) {
+ return URL::to("users/{$model->public_id}/edit");
+ },
+ function ($model) {
+ return $model->public_id;
+ }
+ ],
+ [
+ uctrans('texts.send_invite'),
+ function ($model) {
+ return URL::to("send_confirmation/{$model->public_id}");
+ },
+ function ($model) {
+ return $model->public_id && ! $model->confirmed;
+ }
+ ]
+ ];
+ }
+
+ private function getStatusLabel($state)
+ {
+ $label = trans("texts.{$state}");
+ $class = 'default';
+ switch ($state) {
+ case USER_STATE_PENDING:
+ $class = 'default';
+ break;
+ case USER_STATE_ACTIVE:
+ $class = 'info';
+ break;
+ case USER_STATE_DISABLED:
+ $class = 'warning';
+ break;
+ case USER_STATE_OWNER:
+ $class = 'success';
+ break;
+ case USER_STATE_ADMIN:
+ $class = 'primary';
+ break;
+ }
+ return "$label
";
+ }
+
+
+}
diff --git a/app/Ninja/Datatables/VendorDatatable.php b/app/Ninja/Datatables/VendorDatatable.php
new file mode 100644
index 000000000000..93e059b6ae55
--- /dev/null
+++ b/app/Ninja/Datatables/VendorDatatable.php
@@ -0,0 +1,79 @@
+public_id}", $model->name ?: '')->toHtml();
+ }
+ ],
+ [
+ 'city',
+ function ($model) {
+ return $model->city;
+ }
+ ],
+ [
+ 'work_phone',
+ function ($model) {
+ return $model->work_phone;
+ }
+ ],
+ [
+ 'email',
+ function ($model) {
+ return link_to("vendors/{$model->public_id}", $model->email ?: '')->toHtml();
+ }
+ ],
+ [
+ 'vendors.created_at',
+ function ($model) {
+ return Utils::timestampToDateString(strtotime($model->created_at));
+ }
+ ],
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ [
+ trans('texts.edit_vendor'),
+ function ($model) {
+ return URL::to("vendors/{$model->public_id}/edit");
+ },
+ function ($model) {
+ return Auth::user()->can('editByOwner', [ENTITY_VENDOR, $model->user_id]);
+ }
+ ],
+ [
+ '--divider--', function(){return false;},
+ function ($model) {
+ return Auth::user()->can('editByOwner', [ENTITY_VENDOR, $model->user_id]) && Auth::user()->can('create', ENTITY_EXPENSE);
+ }
+
+ ],
+ [
+ trans('texts.enter_expense'),
+ function ($model) {
+ return URL::to("expenses/create/{$model->public_id}");
+ },
+ function ($model) {
+ return Auth::user()->can('create', ENTITY_EXPENSE);
+ }
+ ]
+ ];
+ }
+
+
+}
diff --git a/app/Ninja/Presenters/ClientPresenter.php b/app/Ninja/Presenters/ClientPresenter.php
index bb32a8b62fb0..22ed376be6c6 100644
--- a/app/Ninja/Presenters/ClientPresenter.php
+++ b/app/Ninja/Presenters/ClientPresenter.php
@@ -2,9 +2,8 @@
use URL;
use Utils;
-use Laracasts\Presenter\Presenter;
-class ClientPresenter extends Presenter {
+class ClientPresenter extends EntityPresenter {
public function country()
{
@@ -28,14 +27,4 @@ class ClientPresenter extends Presenter {
return "{$text}";
}
-
- public function url()
- {
- return URL::to('/clients/' . $this->entity->public_id);
- }
-
- public function link()
- {
- return link_to('/clients/' . $this->entity->public_id, $this->entity->getDisplayName());
- }
-}
\ No newline at end of file
+}
diff --git a/app/Ninja/Presenters/CreditPresenter.php b/app/Ninja/Presenters/CreditPresenter.php
index 7e38205b1067..96c0e5b6f4d0 100644
--- a/app/Ninja/Presenters/CreditPresenter.php
+++ b/app/Ninja/Presenters/CreditPresenter.php
@@ -1,9 +1,8 @@
entity->credit_date);
}
-}
\ No newline at end of file
+}
diff --git a/app/Ninja/Presenters/EntityPresenter.php b/app/Ninja/Presenters/EntityPresenter.php
new file mode 100644
index 000000000000..b1e16acbd620
--- /dev/null
+++ b/app/Ninja/Presenters/EntityPresenter.php
@@ -0,0 +1,25 @@
+entity->getEntityType();
+ $id = $this->entity->public_id;
+ $link = sprintf('/%ss/%s', $type, $id);
+
+ return URL::to($link);
+ }
+
+ public function link()
+ {
+ $name = $this->entity->getDisplayName();
+ $link = $this->url();
+
+ return link_to($link, $name)->toHtml();
+ }
+
+}
diff --git a/app/Ninja/Presenters/ExpensePresenter.php b/app/Ninja/Presenters/ExpensePresenter.php
index 1980480a2f53..275d4e657b09 100644
--- a/app/Ninja/Presenters/ExpensePresenter.php
+++ b/app/Ninja/Presenters/ExpensePresenter.php
@@ -1,9 +1,8 @@
entity->invoice_id ? $this->entity->convertedAmount() : 0;
}
-
- public function link()
- {
- return link_to('/expenses/' . $this->entity->public_id, $this->entity->name);
- }
-}
\ No newline at end of file
+
+}
diff --git a/app/Ninja/Presenters/InvoicePresenter.php b/app/Ninja/Presenters/InvoicePresenter.php
index 36a2ce2acbd6..827b171f4208 100644
--- a/app/Ninja/Presenters/InvoicePresenter.php
+++ b/app/Ninja/Presenters/InvoicePresenter.php
@@ -2,9 +2,8 @@
use URL;
use Utils;
-use Laracasts\Presenter\Presenter;
-class InvoicePresenter extends Presenter {
+class InvoicePresenter extends EntityPresenter {
public function client()
{
@@ -45,6 +44,8 @@ class InvoicePresenter extends Presenter {
return trans('texts.deleted');
} elseif ($this->entity->trashed()) {
return trans('texts.archived');
+ } elseif ($this->entity->is_recurring) {
+ return trans('texts.active');
} else {
$status = $this->entity->invoice_status ? $this->entity->invoice_status->name : 'draft';
$status = strtolower($status);
@@ -67,19 +68,9 @@ class InvoicePresenter extends Presenter {
return $this->entity->frequency ? $this->entity->frequency->name : '';
}
- public function url()
- {
- return URL::to('/invoices/' . $this->entity->public_id);
- }
-
- public function link()
- {
- return link_to('/invoices/' . $this->entity->public_id, $this->entity->invoice_number);
- }
-
public function email()
{
$client = $this->entity->client;
return count($client->contacts) ? $client->contacts[0]->email : '';
}
-}
\ No newline at end of file
+}
diff --git a/app/Ninja/Presenters/PaymentPresenter.php b/app/Ninja/Presenters/PaymentPresenter.php
index a1c3692991fe..9b464b4c8a2a 100644
--- a/app/Ninja/Presenters/PaymentPresenter.php
+++ b/app/Ninja/Presenters/PaymentPresenter.php
@@ -2,9 +2,8 @@
use URL;
use Utils;
-use Laracasts\Presenter\Presenter;
-class PaymentPresenter extends Presenter {
+class PaymentPresenter extends EntityPresenter {
public function client()
{
@@ -25,14 +24,4 @@ class PaymentPresenter extends Presenter {
}
}
- public function url()
- {
- return URL::to('/payments/' . $this->entity->public_id . '/edit');
- }
-
- public function link()
- {
- return link_to('/payments/' . $this->entity->public_id . '/edit', $this->entity->getDisplayName());
- }
-
-}
\ No newline at end of file
+}
diff --git a/app/Ninja/Presenters/TaskPresenter.php b/app/Ninja/Presenters/TaskPresenter.php
index 367e849ca797..5e8eee222c95 100644
--- a/app/Ninja/Presenters/TaskPresenter.php
+++ b/app/Ninja/Presenters/TaskPresenter.php
@@ -1,9 +1,6 @@
{$text}";
}
-}
\ No newline at end of file
+}
diff --git a/app/Ninja/Presenters/VendorPresenter.php b/app/Ninja/Presenters/VendorPresenter.php
index d0bef4e0c828..2dd535cac6cd 100644
--- a/app/Ninja/Presenters/VendorPresenter.php
+++ b/app/Ninja/Presenters/VendorPresenter.php
@@ -1,17 +1,10 @@
entity->country ? $this->entity->country->name : '';
}
-
- public function link()
- {
- return link_to('/vendors/' . $this->entity->public_id, $this->entity->name);
- }
-}
\ No newline at end of file
+
+}
diff --git a/app/Ninja/Repositories/ActivityRepository.php b/app/Ninja/Repositories/ActivityRepository.php
index 60474dc9580d..d0ea33981117 100644
--- a/app/Ninja/Repositories/ActivityRepository.php
+++ b/app/Ninja/Repositories/ActivityRepository.php
@@ -91,6 +91,7 @@ class ActivityRepository
'invoices.public_id as invoice_public_id',
'invoices.is_recurring',
'clients.name as client_name',
+ 'accounts.name as account_name',
'clients.public_id as client_public_id',
'contacts.id as contact',
'contacts.first_name as first_name',
@@ -102,4 +103,4 @@ class ActivityRepository
);
}
-}
\ No newline at end of file
+}
diff --git a/app/Ninja/Repositories/ClientRepository.php b/app/Ninja/Repositories/ClientRepository.php
index 83f08cd97a59..bb56d944e6fc 100644
--- a/app/Ninja/Repositories/ClientRepository.php
+++ b/app/Ninja/Repositories/ClientRepository.php
@@ -25,7 +25,7 @@ class ClientRepository extends BaseRepository
->get();
}
- public function find($filter = null)
+ public function find($filter = null, $userId = false)
{
$query = DB::table('clients')
->join('accounts', 'accounts.id', '=', 'clients.account_id')
@@ -63,9 +63,13 @@ class ClientRepository extends BaseRepository
});
}
+ if ($userId) {
+ $query->where('clients.user_id', '=', $userId);
+ }
+
return $query;
}
-
+
public function save($data, $client = null)
{
$publicId = isset($data['public_id']) ? $data['public_id'] : false;
@@ -78,7 +82,7 @@ class ClientRepository extends BaseRepository
$client = Client::scope($publicId)->with('contacts')->firstOrFail();
\Log::warning('Entity not set in client repo save');
}
-
+
// convert currency code to id
if (isset($data['currency_code'])) {
$currencyCode = strtolower($data['currency_code']);
@@ -98,7 +102,7 @@ class ClientRepository extends BaseRepository
return $client;
}
*/
-
+
$first = true;
$contacts = isset($data['contact']) ? [$data['contact']] : $data['contacts'];
$contactIds = [];
@@ -107,7 +111,7 @@ class ClientRepository extends BaseRepository
usort($contacts, function ($left, $right) {
return (isset($right['is_primary']) ? $right['is_primary'] : 1) - (isset($left['is_primary']) ? $left['is_primary'] : 0);
});
-
+
foreach ($contacts as $contact) {
$contact = $client->addContact($contact, $first);
$contactIds[] = $contact->public_id;
diff --git a/app/Ninja/Repositories/ExpenseRepository.php b/app/Ninja/Repositories/ExpenseRepository.php
index 0ce0e155cf50..2d782298a2e7 100644
--- a/app/Ninja/Repositories/ExpenseRepository.php
+++ b/app/Ninja/Repositories/ExpenseRepository.php
@@ -36,22 +36,8 @@ class ExpenseRepository extends BaseRepository
public function findVendor($vendorPublicId)
{
$vendorId = Vendor::getPrivateId($vendorPublicId);
- $accountid = \Auth::user()->account_id;
- $query = DB::table('expenses')
- ->join('accounts', 'accounts.id', '=', 'expenses.account_id')
- ->where('expenses.account_id', '=', $accountid)
- ->where('expenses.vendor_id', '=', $vendorId)
- ->select(
- 'expenses.id',
- 'expenses.expense_date',
- 'expenses.amount',
- 'expenses.public_notes',
- 'expenses.public_id',
- 'expenses.deleted_at',
- 'expenses.should_be_invoiced',
- 'expenses.created_at',
- 'expenses.user_id'
- );
+
+ $query = $this->find()->where('expenses.vendor_id', '=', $vendorId);
return $query;
}
diff --git a/app/Services/AccountGatewayService.php b/app/Services/AccountGatewayService.php
index 88ee177321ec..00e3f672e602 100644
--- a/app/Services/AccountGatewayService.php
+++ b/app/Services/AccountGatewayService.php
@@ -1,10 +1,9 @@
accountGatewayRepo;
}
- /*
- public function save()
- {
- return null;
- }
- */
-
public function getDatatable($accountId)
{
$query = $this->accountGatewayRepo->find($accountId);
- return $this->createDatatable(ENTITY_ACCOUNT_GATEWAY, $query, false);
+ return $this->datatableService->createDatatable(new AccountGatewayDatatable(false), $query);
}
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'name',
- function ($model) {
- if ($model->deleted_at) {
- return $model->name;
- } elseif ($model->gateway_id != GATEWAY_WEPAY) {
- return link_to("gateways/{$model->public_id}/edit", $model->name)->toHtml();
- } else {
- $accountGateway = AccountGateway::find($model->id);
- $config = $accountGateway->getConfig();
- $endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
- $wepayAccountId = $config->accountId;
- $wepayState = isset($config->state)?$config->state:null;
- $linkText = $model->name;
- $url = $endpoint.'account/'.$wepayAccountId;
- $wepay = \Utils::setupWepay($accountGateway);
- $html = link_to($url, $linkText, array('target'=>'_blank'))->toHtml();
-
- try {
- if ($wepayState == 'action_required') {
- $updateUri = $wepay->request('/account/get_update_uri', array(
- 'account_id' => $wepayAccountId,
- 'redirect_uri' => URL::to('gateways'),
- ));
-
- $linkText .= ' ('.trans('texts.action_required').')';
- $url = $updateUri->uri;
- $html = "{$linkText}";
- $model->setupUrl = $url;
- } elseif ($wepayState == 'pending') {
- $linkText .= ' ('.trans('texts.resend_confirmation_email').')';
- $model->resendConfirmationUrl = $url = URL::to("gateways/{$accountGateway->public_id}/resend_confirmation");
- $html = link_to($url, $linkText)->toHtml();
- }
- } catch(\WePayException $ex){}
-
- return $html;
- }
- }
- ],
- [
- 'payment_type',
- function ($model) {
- return Gateway::getPrettyPaymentType($model->gateway_id);
- }
- ],
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- uctrans('texts.resend_confirmation_email'),
- function ($model) {
- return $model->resendConfirmationUrl;
- },
- function($model) {
- return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY && !empty($model->resendConfirmationUrl);
- }
- ], [
- uctrans('texts.finish_setup'),
- function ($model) {
- return $model->setupUrl;
- },
- function($model) {
- return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY && !empty($model->setupUrl);
- }
- ] , [
- uctrans('texts.edit_gateway'),
- function ($model) {
- return URL::to("gateways/{$model->public_id}/edit");
- },
- function($model) {
- return !$model->deleted_at;
- }
- ], [
- uctrans('texts.manage_wepay_account'),
- function ($model) {
- $accountGateway = AccountGateway::find($model->id);
- $endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
- return array(
- 'url' => $endpoint.'account/'.$accountGateway->getConfig()->accountId,
- 'attributes' => 'target="_blank"'
- );
- },
- function($model) {
- return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY;
- }
- ]
- ];
- }
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/ActivityService.php b/app/Services/ActivityService.php
index 6f6ef4b35956..6b06fce73a8b 100644
--- a/app/Services/ActivityService.php
+++ b/app/Services/ActivityService.php
@@ -4,6 +4,7 @@ use Utils;
use App\Models\Client;
use App\Services\BaseService;
use App\Ninja\Repositories\ActivityRepository;
+use App\Ninja\Datatables\ActivityDatatable;
class ActivityService extends BaseService
{
@@ -22,48 +23,7 @@ class ActivityService extends BaseService
$query = $this->activityRepo->findByClientId($clientId);
- return $this->createDatatable(ENTITY_ACTIVITY, $query);
+ return $this->datatableService->createDatatable(new ActivityDatatable(false), $query);
}
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'activities.id',
- function ($model) {
- return Utils::timestampToDateTimeString(strtotime($model->created_at));
- }
- ],
- [
- 'activity_type_id',
- function ($model) {
- $data = [
- 'client' => link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model))->toHtml(),
- 'user' => $model->is_system ? '' . trans('texts.system') . '' : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email),
- 'invoice' => $model->invoice ? link_to('/invoices/' . $model->invoice_public_id, $model->is_recurring ? trans('texts.recurring_invoice') : $model->invoice)->toHtml() : null,
- 'quote' => $model->invoice ? link_to('/quotes/' . $model->invoice_public_id, $model->invoice)->toHtml() : null,
- 'contact' => $model->contact_id ? link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model))->toHtml() : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email),
- 'payment' => $model->payment ?: '',
- 'credit' => $model->payment_amount ? Utils::formatMoney($model->credit, $model->currency_id, $model->country_id) : '',
- 'payment_amount' => $model->payment_amount ? Utils::formatMoney($model->payment_amount, $model->currency_id, $model->country_id) : null,
- 'adjustment' => $model->adjustment ? Utils::formatMoney($model->adjustment, $model->currency_id, $model->country_id) : null
- ];
-
- return trans("texts.activity_{$model->activity_type_id}", $data);
- }
- ],
- [
- 'balance',
- function ($model) {
- return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id);
- }
- ],
- [
- 'adjustment',
- function ($model) {
- return $model->adjustment != 0 ? Utils::wrapAdjustment($model->adjustment, $model->currency_id, $model->country_id) : '';
- }
- ]
- ];
- }
-}
\ No newline at end of file
+}
diff --git a/app/Services/BankAccountService.php b/app/Services/BankAccountService.php
index 688bd866d3ad..9291a36342c3 100644
--- a/app/Services/BankAccountService.php
+++ b/app/Services/BankAccountService.php
@@ -11,6 +11,7 @@ use App\Services\BaseService;
use App\Ninja\Repositories\BankAccountRepository;
use App\Ninja\Repositories\ExpenseRepository;
use App\Ninja\Repositories\VendorRepository;
+use App\Ninja\Datatables\BankAccountDatatable;
use App\Libraries\Finance;
use App\Libraries\Login;
@@ -206,7 +207,7 @@ class BankAccountService extends BaseService
$vendorMap[$transaction['vendor_orig']] = $vendor;
$countVendors++;
}
-
+
// create the expense record
$this->expenseRepo->save([
'vendor_id' => $vendor->id,
@@ -241,36 +242,6 @@ class BankAccountService extends BaseService
{
$query = $this->bankAccountRepo->find($accountId);
- return $this->createDatatable(ENTITY_BANK_ACCOUNT, $query, false);
- }
-
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'bank_name',
- function ($model) {
- return link_to("bank_accounts/{$model->public_id}/edit", $model->bank_name)->toHtml();
- },
- ],
- [
- 'bank_library_id',
- function ($model) {
- return 'OFX';
- }
- ],
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- uctrans('texts.edit_bank_account'),
- function ($model) {
- return URL::to("bank_accounts/{$model->public_id}/edit");
- },
- ]
- ];
+ return $this->datatableService->createDatatable(new BankAccountDatatable(false), $query);
}
}
diff --git a/app/Services/BaseService.php b/app/Services/BaseService.php
index afd6ed1ea1eb..e6dad06334bd 100644
--- a/app/Services/BaseService.php
+++ b/app/Services/BaseService.php
@@ -30,21 +30,4 @@ class BaseService
return count($entities);
}
- public function createDatatable($entityType, $query, $showCheckbox = true, $hideClient = false, $orderColumns = [])
- {
- $columns = $this->getDatatableColumns($entityType, !$showCheckbox);
- $actions = $this->getDatatableActions($entityType);
-
- return $this->datatableService->createDatatable($entityType, $query, $columns, $actions, $showCheckbox, $orderColumns);
- }
-
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [];
- }
}
diff --git a/app/Services/ClientService.php b/app/Services/ClientService.php
index 96357991c519..065258d05abb 100644
--- a/app/Services/ClientService.php
+++ b/app/Services/ClientService.php
@@ -12,6 +12,7 @@ use App\Models\Payment;
use App\Models\Task;
use App\Ninja\Repositories\ClientRepository;
use App\Ninja\Repositories\NinjaRepository;
+use App\Ninja\Datatables\ClientDatatable;
class ClientService extends BaseService
{
@@ -39,139 +40,13 @@ class ClientService extends BaseService
return $this->clientRepo->save($data, $client);
}
- public function getDatatable($search)
+ public function getDatatable($search, $userId)
{
- $query = $this->clientRepo->find($search);
+ $datatable = new ClientDatatable();
- if(!Utils::hasPermission('view_all')){
- $query->where('clients.user_id', '=', Auth::user()->id);
- }
+ $query = $this->clientRepo->find($search, $userId);
- return $this->createDatatable(ENTITY_CLIENT, $query);
+ return $this->datatableService->createDatatable($datatable, $query);
}
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'name',
- function ($model) {
- return link_to("clients/{$model->public_id}", $model->name ?: '')->toHtml();
- }
- ],
- [
- 'first_name',
- function ($model) {
- return link_to("clients/{$model->public_id}", $model->first_name.' '.$model->last_name)->toHtml();
- }
- ],
- [
- 'email',
- function ($model) {
- return link_to("clients/{$model->public_id}", $model->email ?: '')->toHtml();
- }
- ],
- [
- 'clients.created_at',
- function ($model) {
- return Utils::timestampToDateString(strtotime($model->created_at));
- }
- ],
- [
- 'last_login',
- function ($model) {
- return Utils::timestampToDateString(strtotime($model->last_login));
- }
- ],
- [
- 'balance',
- function ($model) {
- return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id);
- }
- ]
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- trans('texts.edit_client'),
- function ($model) {
- return URL::to("clients/{$model->public_id}/edit");
- },
- function ($model) {
- return Auth::user()->can('editByOwner', [ENTITY_CLIENT, $model->user_id]);
- }
- ],
- [
- '--divider--', function(){return false;},
- function ($model) {
- $user = Auth::user();
- return $user->can('editByOwner', [ENTITY_CLIENT, $model->user_id]) && ($user->can('create', ENTITY_TASK) || $user->can('create', ENTITY_INVOICE));
- }
- ],
- [
- trans('texts.new_task'),
- function ($model) {
- return URL::to("tasks/create/{$model->public_id}");
- },
- function ($model) {
- return Auth::user()->can('create', ENTITY_TASK);
- }
- ],
- [
- trans('texts.new_invoice'),
- function ($model) {
- return URL::to("invoices/create/{$model->public_id}");
- },
- function ($model) {
- return Auth::user()->can('create', ENTITY_INVOICE);
- }
- ],
- [
- trans('texts.new_quote'),
- function ($model) {
- return URL::to("quotes/create/{$model->public_id}");
- },
- function ($model) {
- return Auth::user()->hasFeature(FEATURE_QUOTES) && Auth::user()->can('create', ENTITY_INVOICE);
- }
- ],
- [
- '--divider--', function(){return false;},
- function ($model) {
- $user = Auth::user();
- return ($user->can('create', ENTITY_TASK) || $user->can('create', ENTITY_INVOICE)) && ($user->can('create', ENTITY_PAYMENT) || $user->can('create', ENTITY_CREDIT) || $user->can('create', ENTITY_EXPENSE));
- }
- ],
- [
- trans('texts.enter_payment'),
- function ($model) {
- return URL::to("payments/create/{$model->public_id}");
- },
- function ($model) {
- return Auth::user()->can('create', ENTITY_PAYMENT);
- }
- ],
- [
- trans('texts.enter_credit'),
- function ($model) {
- return URL::to("credits/create/{$model->public_id}");
- },
- function ($model) {
- return Auth::user()->can('create', ENTITY_CREDIT);
- }
- ],
- [
- trans('texts.enter_expense'),
- function ($model) {
- return URL::to("expenses/create/0/{$model->public_id}");
- },
- function ($model) {
- return Auth::user()->can('create', ENTITY_EXPENSE);
- }
- ]
- ];
- }
}
diff --git a/app/Services/CreditService.php b/app/Services/CreditService.php
index 54ef659f05f9..a1e1a5db40ab 100644
--- a/app/Services/CreditService.php
+++ b/app/Services/CreditService.php
@@ -7,7 +7,7 @@ use App\Services\BaseService;
use App\Models\Client;
use App\Models\Payment;
use App\Ninja\Repositories\CreditRepository;
-
+use App\Ninja\Datatables\CreditDatatable;
class CreditService extends BaseService
{
@@ -32,68 +32,14 @@ class CreditService extends BaseService
public function getDatatable($clientPublicId, $search)
{
+ // we don't support bulk edit and hide the client on the individual client page
+ $datatable = new CreditDatatable( ! $clientPublicId, $clientPublicId);
$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);
+ return $this->datatableService->createDatatable($datatable, $query);
}
-
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'client_name',
- function ($model) {
- if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $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
- ],
- [
- 'amount',
- function ($model) {
- return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id) . '';
- }
- ],
- [
- 'balance',
- function ($model) {
- return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id);
- }
- ],
- [
- 'credit_date',
- function ($model) {
- return Utils::fromSqlDate($model->credit_date);
- }
- ],
- [
- 'private_notes',
- function ($model) {
- return $model->private_notes;
- }
- ]
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- trans('texts.apply_credit'),
- function ($model) {
- return URL::to("payments/create/{$model->client_public_id}") . '?paymentTypeId=1';
- },
- function ($model) {
- return Auth::user()->can('create', ENTITY_PAYMENT);
- }
- ]
- ];
- }
-}
\ No newline at end of file
+}
diff --git a/app/Services/DatatableService.php b/app/Services/DatatableService.php
index df4c9d93d55d..8fa49df5f7df 100644
--- a/app/Services/DatatableService.php
+++ b/app/Services/DatatableService.php
@@ -4,24 +4,25 @@ use HtmlString;
use Utils;
use Datatable;
use Auth;
+use App\Ninja\Datatables\EntityDatatable;
class DatatableService
{
- public function createDatatable($entityType, $query, $columns, $actions = null, $showCheckbox = true, $orderColumns = [])
+ public function createDatatable(EntityDatatable $datatable, $query)
{
$table = Datatable::query($query);
- $calculateOrderColumns = empty($orderColumns);
-
- if ($actions && $showCheckbox) {
+ //$calculateOrderColumns = empty($orderColumns);
+
+ if ($datatable->isBulkEdit) {
$table->addColumn('checkbox', function ($model) {
$can_edit = Auth::user()->hasPermission('edit_all') || (isset($model->user_id) && Auth::user()->id == $model->user_id);
-
+
return !$can_edit?'':'';
});
}
- foreach ($columns as $column) {
+ foreach ($datatable->columns() as $column) {
// set visible to true by default
if (count($column) == 2) {
$column[] = true;
@@ -31,27 +32,31 @@ class DatatableService
if ($visible) {
$table->addColumn($field, $value);
+ $orderColumns[] = $field;
+ /*
if ($calculateOrderColumns) {
$orderColumns[] = $field;
}
+ */
}
}
- if ($actions) {
- $this->createDropdown($entityType, $table, $actions);
+ if (count($datatable->actions())) {
+ $this->createDropdown($datatable, $table);
}
return $table->orderColumns($orderColumns)->make();
}
- private function createDropdown($entityType, $table, $actions)
+ //private function createDropdown($entityType, $table, $actions)
+ private function createDropdown(EntityDatatable $datatable, $table)
{
- $table->addColumn('dropdown', function ($model) use ($entityType, $actions) {
+ $table->addColumn('dropdown', function ($model) use ($datatable) {
$hasAction = false;
$str = '';
$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 .= '';
} elseif ($model->deleted_at && $model->deleted_at !== '0000-00-00') {
@@ -64,7 +69,7 @@ class DatatableService
$lastIsDivider = false;
if (!$model->deleted_at || $model->deleted_at == '0000-00-00') {
- foreach ($actions as $action) {
+ foreach ($datatable->actions() as $action) {
if (count($action)) {
if (count($action) == 2) {
$action[] = function() {
@@ -104,20 +109,20 @@ class DatatableService
$dropdown_contents .= "";
}
- if (($entityType != ENTITY_USER || $model->public_id) && $can_edit) {
+ if (($datatable->entityType != ENTITY_USER || $model->public_id) && $can_edit) {
$dropdown_contents .= "public_id})\">"
- . trans("texts.archive_{$entityType}") . "";
+ . trans("texts.archive_{$datatable->entityType}") . "";
}
} else if($can_edit) {
- if ($entityType != ENTITY_ACCOUNT_GATEWAY || Auth::user()->account->canAddGateway(\App\Models\Gateway::getPaymentType($model->gateway_id))) {
+ if ($datatable->entityType != ENTITY_ACCOUNT_GATEWAY || Auth::user()->account->canAddGateway(\App\Models\Gateway::getPaymentType($model->gateway_id))) {
$dropdown_contents .= "public_id})\">"
- . trans("texts.restore_{$entityType}") . "";
+ . trans("texts.restore_{$datatable->entityType}") . "";
}
}
if (property_exists($model, 'is_deleted') && !$model->is_deleted && $can_edit) {
$dropdown_contents .= "public_id})\">"
- . trans("texts.delete_{$entityType}") . "";
+ . trans("texts.delete_{$datatable->entityType}") . "";
}
if (!empty($dropdown_contents)) {
@@ -132,5 +137,4 @@ class DatatableService
return $str.'';
});
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/ExpenseService.php b/app/Services/ExpenseService.php
index 671648ea32a5..a16bff7dd3f1 100644
--- a/app/Services/ExpenseService.php
+++ b/app/Services/ExpenseService.php
@@ -10,6 +10,7 @@ use App\Models\Expense;
use App\Models\Invoice;
use App\Models\Client;
use App\Models\Vendor;
+use App\Ninja\Datatables\ExpenseDatatable;
class ExpenseService extends BaseService
{
@@ -49,89 +50,22 @@ class ExpenseService extends BaseService
$query->where('expenses.user_id', '=', Auth::user()->id);
}
- return $this->createDatatable(ENTITY_EXPENSE, $query);
+ return $this->datatableService->createDatatable(new ExpenseDatatable(), $query);
}
public function getDatatableVendor($vendorPublicId)
{
+ $datatable = new ExpenseDatatable(false, true);
+
$query = $this->expenseRepo->findVendor($vendorPublicId);
- return $this->datatableService->createDatatable(ENTITY_EXPENSE,
- $query,
- $this->getDatatableColumnsVendor(ENTITY_EXPENSE,false),
- $this->getDatatableActionsVendor(ENTITY_EXPENSE),
- false);
+
+ if(!Utils::hasPermission('view_all')){
+ $query->where('expenses.user_id', '=', Auth::user()->id);
+ }
+
+ return $this->datatableService->createDatatable($datatable, $query);
}
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'vendor_name',
- function ($model)
- {
- if ($model->vendor_public_id) {
- if(!Auth::user()->can('viewByOwner', [ENTITY_VENDOR, $model->vendor_user_id])){
- return $model->vendor_name;
- }
-
- return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml();
- } else {
- return '';
- }
- }
- ],
- [
- 'client_name',
- function ($model)
- {
- if ($model->client_public_id) {
- if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){
- return Utils::getClientDisplayName($model);
- }
-
- return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
- } else {
- return '';
- }
- }
- ],
- [
- 'expense_date',
- function ($model) {
- if(!Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id])){
- return Utils::fromSqlDate($model->expense_date);
- }
-
- return link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date))->toHtml();
- }
- ],
- [
- 'amount',
- function ($model) {
- // show both the amount and the converted amount
- if ($model->exchange_rate != 1) {
- $converted = round($model->amount * $model->exchange_rate, 2);
- return Utils::formatMoney($model->amount, $model->expense_currency_id) . ' | ' .
- Utils::formatMoney($converted, $model->invoice_currency_id);
- } else {
- return Utils::formatMoney($model->amount, $model->expense_currency_id);
- }
- }
- ],
- [
- 'public_notes',
- function ($model) {
- return $model->public_notes != null ? substr($model->public_notes, 0, 100) : '';
- }
- ],
- [
- 'expense_status_id',
- function ($model) {
- return self::getStatusLabel($model->invoice_id, $model->should_be_invoiced);
- }
- ],
- ];
- }
protected function getDatatableColumnsVendor($entityType, $hideClient)
{
@@ -163,58 +97,9 @@ class ExpenseService extends BaseService
];
}
- protected function getDatatableActions($entityType)
- {
- return [
- [
- trans('texts.edit_expense'),
- function ($model) {
- return URL::to("expenses/{$model->public_id}/edit") ;
- },
- function ($model) {
- return Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id]);
- }
- ],
- [
- trans('texts.view_invoice'),
- function ($model) {
- return URL::to("/invoices/{$model->invoice_public_id}/edit");
- },
- function ($model) {
- return $model->invoice_public_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id]);
- }
- ],
- [
- trans('texts.invoice_expense'),
- function ($model) {
- return "javascript:invoiceEntity({$model->public_id})";
- },
- function ($model) {
- return ! $model->invoice_id && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('create', ENTITY_INVOICE);
- }
- ],
- ];
- }
-
protected function getDatatableActionsVendor($entityType)
{
return [];
}
- private function getStatusLabel($invoiceId, $shouldBeInvoiced)
- {
- if ($invoiceId) {
- $label = trans('texts.invoiced');
- $class = 'success';
- } elseif ($shouldBeInvoiced) {
- $label = trans('texts.pending');
- $class = 'warning';
- } else {
- $label = trans('texts.logged');
- $class = 'primary';
- }
-
- return "$label
";
- }
-
}
diff --git a/app/Services/InvoiceService.php b/app/Services/InvoiceService.php
index edbee8caf84c..950c8bb95fcb 100644
--- a/app/Services/InvoiceService.php
+++ b/app/Services/InvoiceService.php
@@ -11,6 +11,7 @@ use App\Models\Invitation;
use App\Models\Invoice;
use App\Models\Client;
use App\Models\Payment;
+use App\Ninja\Datatables\InvoiceDatatable;
class InvoiceService extends BaseService
{
@@ -34,12 +35,12 @@ class InvoiceService extends BaseService
{
if (isset($data['client'])) {
$canSaveClient = false;
- $clientPublicId = array_get($data, 'client.public_id') ?: array_get($data, 'client.id');
+ $clientPublicId = array_get($data, 'client.public_id') ?: array_get($data, 'client.id');
if (empty($clientPublicId) || $clientPublicId == '-1') {
$canSaveClient = Auth::user()->can('create', ENTITY_CLIENT);
} else {
$canSaveClient = Auth::user()->can('edit', Client::scope($clientPublicId)->first());
- }
+ }
if ($canSaveClient) {
$client = $this->clientRepo->save($data['client']);
$data['client_id'] = $client->id;
@@ -92,7 +93,7 @@ class InvoiceService extends BaseService
public function approveQuote($quote, $invitation = null)
{
$account = $quote->account;
-
+
if (!$quote->is_quote || $quote->quote_invoice_id) {
return null;
}
@@ -118,189 +119,15 @@ class InvoiceService extends BaseService
public function getDatatable($accountId, $clientPublicId = null, $entityType, $search)
{
+ $datatable = new InvoiceDatatable( ! $clientPublicId, $clientPublicId);
$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);
- }
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'invoice_number',
- function ($model) use ($entityType) {
- if(!Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id])){
- 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(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){
- return Utils::getClientDisplayName($model);
- }
- return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
- },
- ! $hideClient
- ],
- [
- 'invoice_date',
- function ($model) {
- return Utils::fromSqlDate($model->invoice_date);
- }
- ],
- [
- 'amount',
- function ($model) {
- return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id);
- }
- ],
- [
- 'balance',
- function ($model) {
- return $model->partial > 0 ?
- trans('texts.partial_remaining', [
- 'partial' => Utils::formatMoney($model->partial, $model->currency_id, $model->country_id),
- 'balance' => Utils::formatMoney($model->balance, $model->currency_id, $model->country_id)]
- ) :
- Utils::formatMoney($model->balance, $model->currency_id, $model->country_id);
- },
- $entityType == ENTITY_INVOICE
- ],
- [
- 'due_date',
- function ($model) {
- return Utils::fromSqlDate($model->due_date);
- },
- ],
- [
- 'invoice_status_name',
- function ($model) use ($entityType) {
- return $model->quote_invoice_id ? link_to("invoices/{$model->quote_invoice_id}/edit", trans('texts.converted'))->toHtml() : self::getStatusLabel($entityType, $model);
- }
- ]
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- trans("texts.edit_{$entityType}"),
- function ($model) use ($entityType) {
- return URL::to("{$entityType}s/{$model->public_id}/edit");
- },
- function ($model) {
- return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
- }
- ],
- [
- trans("texts.clone_{$entityType}"),
- function ($model) use ($entityType) {
- return URL::to("{$entityType}s/{$model->public_id}/clone");
- },
- function ($model) {
- return Auth::user()->can('create', ENTITY_INVOICE);
- }
- ],
- [
- trans("texts.view_history"),
- function ($model) use ($entityType) {
- return URL::to("{$entityType}s/{$entityType}_history/{$model->public_id}");
- }
- ],
- [
- '--divider--', function(){return false;},
- function ($model) {
- return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]) || Auth::user()->can('create', ENTITY_PAYMENT);
- }
- ],
- [
- trans("texts.mark_sent"),
- function ($model) {
- return "javascript:markEntity({$model->public_id})";
- },
- function ($model) {
- return $model->invoice_status_id < INVOICE_STATUS_SENT && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
- }
- ],
- [
- trans('texts.enter_payment'),
- function ($model) {
- return URL::to("payments/create/{$model->client_public_id}/{$model->public_id}");
- },
- function ($model) use ($entityType) {
- return $entityType == ENTITY_INVOICE && $model->balance > 0 && Auth::user()->can('create', ENTITY_PAYMENT);
- }
- ],
- [
- trans("texts.view_quote"),
- function ($model) {
- return URL::to("quotes/{$model->quote_id}/edit");
- },
- function ($model) use ($entityType) {
- return $entityType == ENTITY_INVOICE && $model->quote_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
- }
- ],
- [
- trans("texts.view_invoice"),
- function ($model) {
- return URL::to("invoices/{$model->quote_invoice_id}/edit");
- },
- function ($model) use ($entityType) {
- return $entityType == ENTITY_QUOTE && $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
- }
- ],
- [
- trans("texts.convert_to_invoice"),
- function ($model) {
- return "javascript:convertEntity({$model->public_id})";
- },
- function ($model) use ($entityType) {
- return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
- }
- ]
- ];
- }
-
- private function getStatusLabel($entityType, $model)
- {
- // check if invoice is overdue
- if (Utils::parseFloat($model->balance) && $model->due_date && $model->due_date != '0000-00-00') {
- if (\DateTime::createFromFormat('Y-m-d', $model->due_date) < new \DateTime("now")) {
- $label = $entityType == ENTITY_INVOICE ? trans('texts.overdue') : trans('texts.expired');
- return "" . $label . "
";
- }
- }
-
- $label = trans("texts.status_" . strtolower($model->invoice_status_name));
- $class = 'default';
- switch ($model->invoice_status_id) {
- case INVOICE_STATUS_SENT:
- $class = 'info';
- break;
- case INVOICE_STATUS_VIEWED:
- $class = 'warning';
- break;
- case INVOICE_STATUS_APPROVED:
- $class = 'success';
- break;
- case INVOICE_STATUS_PARTIAL:
- $class = 'primary';
- break;
- case INVOICE_STATUS_PAID:
- $class = 'success';
- break;
- }
- return "$label
";
+ return $this->datatableService->createDatatable($datatable, $query);
}
}
diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php
index 51cbccc57177..b227b466413c 100644
--- a/app/Services/PaymentService.php
+++ b/app/Services/PaymentService.php
@@ -23,18 +23,13 @@ use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\AccountRepository;
use App\Services\BaseService;
use App\Events\PaymentWasCreated;
+use App\Ninja\Datatables\PaymentDatatable;
class PaymentService extends BaseService
{
public $lastError;
protected $datatableService;
- protected static $refundableGateways = array(
- GATEWAY_STRIPE,
- GATEWAY_BRAINTREE,
- GATEWAY_WEPAY,
- );
-
public function __construct(PaymentRepository $paymentRepo, AccountRepository $accountRepo, DatatableService $datatableService)
{
$this->datatableService = $datatableService;
@@ -524,7 +519,7 @@ class PaymentService extends BaseService
return $paymentMethod;
}
-
+
public function convertPaymentMethodFromGatewayResponse($gatewayResponse, $accountGateway, $accountGatewayToken = null, $contactId = null, $existingPaymentMethod = null) {
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
$data = $gatewayResponse->getData();
@@ -642,7 +637,7 @@ class PaymentService extends BaseService
$payment->contact_id = $invitation->contact_id;
$payment->transaction_reference = $ref;
$payment->payment_date = date_create()->format('Y-m-d');
-
+
if (!empty($paymentDetails['card'])) {
$card = $paymentDetails['card'];
$payment->last4 = $card->getNumberLastFour();
@@ -707,10 +702,10 @@ class PaymentService extends BaseService
$pending_monthly = true;
}
}
-
- if (!empty($plan)) {
+
+ if (!empty($plan)) {
$account = Account::with('users')->find($invoice->client->public_id);
-
+
if(
$account->company->plan != $plan
|| DateTime::createFromFormat('Y-m-d', $account->company->plan_expires) >= date_create('-7 days')
@@ -719,10 +714,10 @@ class PaymentService extends BaseService
// Reset any grandfathering
$account->company->plan_started = date_create()->format('Y-m-d');
}
-
+
if (
$account->company->plan == $plan
- && $account->company->plan_term == $term
+ && $account->company->plan_term == $term
&& DateTime::createFromFormat('Y-m-d', $account->company->plan_expires) >= date_create()
) {
// This is a renewal; mark it paid as of when this term expires
@@ -730,13 +725,13 @@ class PaymentService extends BaseService
} else {
$account->company->plan_paid = date_create()->format('Y-m-d');
}
-
+
$account->company->payment_id = $payment->id;
$account->company->plan = $plan;
$account->company->plan_term = $term;
$account->company->plan_expires = DateTime::createFromFormat('Y-m-d', $account->company->plan_paid)
->modify($term == PLAN_TERM_MONTHLY ? '+1 month' : '+1 year')->format('Y-m-d');
-
+
if (!empty($pending_monthly)) {
$account->company->pending_plan = $plan;
$account->company->pending_term = PLAN_TERM_MONTHLY;
@@ -744,7 +739,7 @@ class PaymentService extends BaseService
$account->company->pending_plan = null;
$account->company->pending_term = null;
}
-
+
$account->company->save();
}
}
@@ -783,7 +778,7 @@ class PaymentService extends BaseService
return PAYMENT_TYPE_CREDIT_CARD_OTHER;
}
}
-
+
private function detectCardType($number)
{
if (preg_match('/^3[47][0-9]{13}$/',$number)) {
@@ -856,127 +851,17 @@ class PaymentService extends BaseService
public function getDatatable($clientPublicId, $search)
{
+ $datatable = new PaymentDatatable( ! $clientPublicId, $clientPublicId);
$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, false,
- ['invoice_number', 'transaction_reference', 'payment_type', 'amount', 'payment_date']);
+ return $this->datatableService->createDatatable($datatable, $query);
}
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'invoice_number',
- function ($model) {
- if(!Auth::user()->can('editByOwner', [ENTITY_INVOICE, $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(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $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
- ],
- [
- 'transaction_reference',
- function ($model) {
- return $model->transaction_reference ? $model->transaction_reference : 'Manual entry';
- }
- ],
- [
- 'payment_type',
- function ($model) {
- return ($model->payment_type && !$model->last4) ? $model->payment_type : ($model->account_gateway_id ? $model->gateway_name : '');
- }
- ],
- [
- 'source',
- function ($model) {
- $code = str_replace(' ', '', strtolower($model->payment_type));
- $card_type = trans("texts.card_" . $code);
- if ($model->payment_type_id != PAYMENT_TYPE_ACH) {
- if($model->last4) {
- $expiration = trans('texts.card_expiration', array('expires' => Utils::fromSqlDate($model->expiration, false)->format('m/y')));
- return '
•••' . $model->last4 . ' ' . $expiration;
- } elseif ($model->email) {
- return $model->email;
- }
- } elseif ($model->last4) {
- $bankData = PaymentMethod::lookupBankData($model->routing_number);
- if (is_object($bankData)) {
- return $bankData->name.' •••' . $model->last4;
- } elseif($model->last4) {
- return '
•••' . $model->last4;
- }
- }
- }
- ],
- [
- 'amount',
- function ($model) {
- return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id);
- }
- ],
- [
- 'payment_date',
- function ($model) {
- return Utils::dateToString($model->payment_date);
- }
- ],
- [
- 'payment_status_name',
- function ($model) use ($entityType) {
- return self::getStatusLabel($entityType, $model);
- }
- ]
- ];
- }
- protected function getDatatableActions($entityType)
- {
- return [
- [
- trans('texts.edit_payment'),
- function ($model) {
- return URL::to("payments/{$model->public_id}/edit");
- },
- function ($model) {
- return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]);
- }
- ],
- [
- trans('texts.refund_payment'),
- function ($model) {
- $max_refund = number_format($model->amount - $model->refunded, 2);
- $formatted = Utils::formatMoney($max_refund, $model->currency_id, $model->country_id);
- $symbol = Utils::getFromCache($model->currency_id ? $model->currency_id : 1, 'currencies')->symbol ;
- return "javascript:showRefundModal({$model->public_id}, '{$max_refund}', '{$formatted}', '{$symbol}')";
- },
- function ($model) {
- return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]) && $model->payment_status_id >= PAYMENT_STATUS_COMPLETED &&
- $model->refunded < $model->amount &&
- (
- ($model->transaction_reference && in_array($model->gateway_id , static::$refundableGateways))
- || $model->payment_type_id == PAYMENT_TYPE_CREDIT
- );
- }
- ]
- ];
- }
-
public function bulk($ids, $action, $params = array())
{
if ($action == 'refund') {
@@ -1001,50 +886,22 @@ class PaymentService extends BaseService
return parent::bulk($ids, $action);
}
}
-
- private function getStatusLabel($entityType, $model)
- {
- $label = trans("texts.status_" . strtolower($model->payment_status_name));
- $class = 'default';
- switch ($model->payment_status_id) {
- case PAYMENT_STATUS_PENDING:
- $class = 'info';
- break;
- case PAYMENT_STATUS_COMPLETED:
- $class = 'success';
- break;
- case PAYMENT_STATUS_FAILED:
- $class = 'danger';
- break;
- case PAYMENT_STATUS_PARTIALLY_REFUNDED:
- $label = trans('texts.status_partially_refunded_amount', [
- 'amount' => Utils::formatMoney($model->refunded, $model->currency_id, $model->country_id),
- ]);
- $class = 'primary';
- break;
- case PAYMENT_STATUS_VOIDED:
- case PAYMENT_STATUS_REFUNDED:
- $class = 'default';
- break;
- }
- return "$label
";
- }
-
+
public function refund($payment, $amount = null) {
if ($amount) {
$amount = min($amount, $payment->amount - $payment->refunded);
}
$accountGateway = $payment->account_gateway;
-
+
if (!$accountGateway) {
$accountGateway = AccountGateway::withTrashed()->find($payment->account_gateway_id);
}
-
+
if (!$amount || !$accountGateway) {
return;
}
-
+
if ($payment->payment_type_id != PAYMENT_TYPE_CREDIT) {
$gateway = $this->createGateway($accountGateway);
diff --git a/app/Services/PaymentTermService.php b/app/Services/PaymentTermService.php
index 1371d20c2c43..08e2a84caf4b 100644
--- a/app/Services/PaymentTermService.php
+++ b/app/Services/PaymentTermService.php
@@ -25,10 +25,10 @@ class PaymentTermService extends BaseService
{
$query = $this->paymentTermRepo->find();
- return $this->createDatatable(ENTITY_PAYMENT_TERM, $query, false);
+ return $this->datatableService->createDatatable(ENTITY_PAYMENT_TERM, $query, false);
}
- protected function getDatatableColumns($entityType, $hideClient)
+ public function columns($entityType, $hideClient)
{
return [
[
@@ -46,7 +46,7 @@ class PaymentTermService extends BaseService
];
}
- protected function getDatatableActions($entityType)
+ public function actions($entityType)
{
return [
[
@@ -57,4 +57,4 @@ class PaymentTermService extends BaseService
]
];
}
-}
\ No newline at end of file
+}
diff --git a/app/Services/ProductService.php b/app/Services/ProductService.php
index f8ec6e1131d5..fc7fc6cceed4 100644
--- a/app/Services/ProductService.php
+++ b/app/Services/ProductService.php
@@ -1,12 +1,12 @@
productRepo->find($accountId);
- return $this->createDatatable(ENTITY_PRODUCT, $query, false);
+ return $this->datatableService->createDatatable($datatable, $query);
}
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'product_key',
- function ($model) {
- return link_to('products/'.$model->public_id.'/edit', $model->product_key)->toHtml();
- }
- ],
- [
- 'notes',
- function ($model) {
- return nl2br(Str::limit($model->notes, 100));
- }
- ],
- [
- 'cost',
- function ($model) {
- return Utils::formatMoney($model->cost);
- }
- ],
- [
- 'tax_rate',
- function ($model) {
- return $model->tax_rate ? ($model->tax_name . ' ' . $model->tax_rate . '%') : '';
- },
- Auth::user()->account->invoice_item_taxes
- ]
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- uctrans('texts.edit_product'),
- function ($model) {
- return URL::to("products/{$model->public_id}/edit");
- }
- ]
- ];
- }
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/RecurringInvoiceService.php b/app/Services/RecurringInvoiceService.php
index b003455abd6a..bc6daa1f0178 100644
--- a/app/Services/RecurringInvoiceService.php
+++ b/app/Services/RecurringInvoiceService.php
@@ -5,6 +5,7 @@ use Auth;
use Utils;
use App\Models\Invoice;
use App\Ninja\Repositories\InvoiceRepository;
+use App\Ninja\Datatables\RecurringInvoiceDatatable;
class RecurringInvoiceService extends BaseService
{
@@ -19,64 +20,14 @@ class RecurringInvoiceService extends BaseService
public function getDatatable($accountId, $clientPublicId = null, $entityType, $search)
{
+ $datatable = new RecurringInvoiceDatatable( ! $clientPublicId, $clientPublicId);
$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);
+
+ return $this->datatableService->createDatatable($datatable, $query);
}
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'frequency',
- function ($model) {
- return link_to("invoices/{$model->public_id}", $model->frequency)->toHtml();
- }
- ],
- [
- 'client_name',
- function ($model) {
- return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
- },
- ! $hideClient
- ],
- [
- 'start_date',
- function ($model) {
- return Utils::fromSqlDate($model->start_date);
- }
- ],
- [
- 'end_date',
- function ($model) {
- return Utils::fromSqlDate($model->end_date);
- }
- ],
- [
- 'amount',
- function ($model) {
- return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id);
- }
- ]
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- trans('texts.edit_invoice'),
- function ($model) {
- return URL::to("invoices/{$model->public_id}/edit");
- },
- function ($model) {
- return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
- }
- ]
- ];
- }
-}
\ No newline at end of file
+}
diff --git a/app/Services/TaskService.php b/app/Services/TaskService.php
index e07793b2f85c..bfb25708d0d5 100644
--- a/app/Services/TaskService.php
+++ b/app/Services/TaskService.php
@@ -8,6 +8,7 @@ use App\Models\Invoice;
use App\Models\Client;
use App\Ninja\Repositories\TaskRepository;
use App\Services\BaseService;
+use App\Ninja\Datatables\TaskDatatable;
class TaskService extends BaseService
{
@@ -34,112 +35,14 @@ class TaskService extends BaseService
public function getDatatable($clientPublicId, $search)
{
+ $datatable = new TaskDatatable( ! $clientPublicId, $clientPublicId);
$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);
+ return $this->datatableService->createDatatable($datatable, $query);
}
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'client_name',
- function ($model) {
- if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $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
- ],
- [
- 'created_at',
- function ($model) {
- return link_to("tasks/{$model->public_id}/edit", Task::calcStartTime($model))->toHtml();
- }
- ],
- [
- 'time_log',
- function($model) {
- return Utils::formatTime(Task::calcDuration($model));
- }
- ],
- [
- 'description',
- function ($model) {
- return $model->description;
- }
- ],
- [
- 'invoice_number',
- function ($model) {
- return self::getStatusLabel($model);
- }
- ]
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- trans('texts.edit_task'),
- function ($model) {
- return URL::to('tasks/'.$model->public_id.'/edit');
- },
- function ($model) {
- return (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]);
- }
- ],
- [
- trans('texts.view_invoice'),
- function ($model) {
- return URL::to("/invoices/{$model->invoice_public_id}/edit");
- },
- function ($model) {
- return $model->invoice_number && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id]);
- }
- ],
- [
- trans('texts.stop_task'),
- function ($model) {
- return "javascript:stopTask({$model->public_id})";
- },
- function ($model) {
- return $model->is_running && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]);
- }
- ],
- [
- trans('texts.invoice_task'),
- function ($model) {
- return "javascript:invoiceEntity({$model->public_id})";
- },
- function ($model) {
- return ! $model->invoice_number && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('create', ENTITY_INVOICE);
- }
- ]
- ];
- }
-
- private function getStatusLabel($model)
- {
- if ($model->invoice_number) {
- $class = 'success';
- $label = trans('texts.invoiced');
- } elseif ($model->is_running) {
- $class = 'primary';
- $label = trans('texts.running');
- } else {
- $class = 'default';
- $label = trans('texts.logged');
- }
-
- return "$label
";
- }
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/TaxRateService.php b/app/Services/TaxRateService.php
index db5b041395f0..330477149462 100644
--- a/app/Services/TaxRateService.php
+++ b/app/Services/TaxRateService.php
@@ -4,6 +4,7 @@ use URL;
use Auth;
use App\Services\BaseService;
use App\Ninja\Repositories\TaxRateRepository;
+use App\Ninja\Datatables\TaxRateDatatable;
class TaxRateService extends BaseService
{
@@ -21,48 +22,12 @@ class TaxRateService extends BaseService
return $this->taxRateRepo;
}
- /*
- public function save()
- {
- return null;
- }
- */
-
public function getDatatable($accountId)
{
+ $datatable = new TaxRateDatatable(false);
$query = $this->taxRateRepo->find($accountId);
- return $this->createDatatable(ENTITY_TAX_RATE, $query, false);
+ return $this->datatableService->createDatatable($datatable, $query);
}
-
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'name',
- function ($model) {
- return link_to("tax_rates/{$model->public_id}/edit", $model->name)->toHtml();
- }
- ],
- [
- 'rate',
- function ($model) {
- return $model->rate . '%';
- }
- ]
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- uctrans('texts.edit_tax_rate'),
- function ($model) {
- return URL::to("tax_rates/{$model->public_id}/edit");
- }
- ]
- ];
- }
-
-}
\ No newline at end of file
+
+}
diff --git a/app/Services/TokenService.php b/app/Services/TokenService.php
index 092f3995d3d7..5d5b29e3de6c 100644
--- a/app/Services/TokenService.php
+++ b/app/Services/TokenService.php
@@ -3,6 +3,7 @@
use URL;
use App\Services\BaseService;
use App\Ninja\Repositories\TokenRepository;
+use App\Ninja\Datatables\TokenDatatable;
class TokenService extends BaseService
{
@@ -20,48 +21,12 @@ class TokenService extends BaseService
return $this->tokenRepo;
}
- /*
- public function save()
- {
- return null;
- }
- */
-
public function getDatatable($userId)
{
+ $datatable = new TokenDatatable(false);
$query = $this->tokenRepo->find($userId);
- return $this->createDatatable(ENTITY_TOKEN, $query, false);
+ return $this->datatableService->createDatatable($datatable, $query);
}
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'name',
- function ($model) {
- return link_to("tokens/{$model->public_id}/edit", $model->name)->toHtml();
- }
- ],
- [
- 'token',
- function ($model) {
- return $model->token;
- }
- ]
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- uctrans('texts.edit_token'),
- function ($model) {
- return URL::to("tokens/{$model->public_id}/edit");
- }
- ]
- ];
- }
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/UserService.php b/app/Services/UserService.php
index 8e31b4c30d2d..3aa7a60c8851 100644
--- a/app/Services/UserService.php
+++ b/app/Services/UserService.php
@@ -3,6 +3,7 @@
use URL;
use App\Services\BaseService;
use App\Ninja\Repositories\UserRepository;
+use App\Ninja\Datatables\UserDatatable;
class UserService extends BaseService
{
@@ -20,102 +21,12 @@ class UserService extends BaseService
return $this->userRepo;
}
- /*
- public function save()
- {
- return null;
- }
- */
-
public function getDatatable($accountId)
{
+ $datatable = new UserDatatable(false);
$query = $this->userRepo->find($accountId);
- return $this->createDatatable(ENTITY_USER, $query, false);
+ return $this->datatableService->createDatatable($datatable, $query);
}
- protected function getDatatableColumns($entityType, $hideClient)
- {
- return [
- [
- 'first_name',
- function ($model) {
- return $model->public_id ? link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name)->toHtml() : ($model->first_name.' '.$model->last_name);
- }
- ],
- [
- 'email',
- function ($model) {
- return $model->email;
- }
- ],
- [
- 'confirmed',
- function ($model) {
- if (!$model->public_id) {
- return self::getStatusLabel(USER_STATE_OWNER);
- } elseif ($model->deleted_at) {
- return self::getStatusLabel(USER_STATE_DISABLED);
- } elseif ($model->confirmed) {
- if($model->is_admin){
- return self::getStatusLabel(USER_STATE_ADMIN);
- } else {
- return self::getStatusLabel(USER_STATE_ACTIVE);
- }
- } else {
- return self::getStatusLabel(USER_STATE_PENDING);
- }
- }
- ],
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- uctrans('texts.edit_user'),
- function ($model) {
- return URL::to("users/{$model->public_id}/edit");
- },
- function ($model) {
- return $model->public_id;
- }
- ],
- [
- uctrans('texts.send_invite'),
- function ($model) {
- return URL::to("send_confirmation/{$model->public_id}");
- },
- function ($model) {
- return $model->public_id && ! $model->confirmed;
- }
- ]
- ];
- }
-
- private function getStatusLabel($state)
- {
- $label = trans("texts.{$state}");
- $class = 'default';
- switch ($state) {
- case USER_STATE_PENDING:
- $class = 'default';
- break;
- case USER_STATE_ACTIVE:
- $class = 'info';
- break;
- case USER_STATE_DISABLED:
- $class = 'warning';
- break;
- case USER_STATE_OWNER:
- $class = 'success';
- break;
- case USER_STATE_ADMIN:
- $class = 'primary';
- break;
- }
- return "$label
";
- }
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/VendorService.php b/app/Services/VendorService.php
index 41f5fd4664bb..0940be420cb4 100644
--- a/app/Services/VendorService.php
+++ b/app/Services/VendorService.php
@@ -8,6 +8,7 @@ use App\Models\Expense;
use App\Services\BaseService;
use App\Ninja\Repositories\VendorRepository;
use App\Ninja\Repositories\NinjaRepository;
+use App\Ninja\Datatables\VendorDatatable;
class VendorService extends BaseService
{
@@ -37,79 +38,14 @@ class VendorService extends BaseService
public function getDatatable($search)
{
+ $datatable = new VendorDatatable();
$query = $this->vendorRepo->find($search);
-
+
if(!Utils::hasPermission('view_all')){
$query->where('vendors.user_id', '=', Auth::user()->id);
}
- return $this->createDatatable(ENTITY_VENDOR, $query);
+ return $this->datatableService->createDatatable($datatable, $query);
}
- protected function getDatatableColumns($entityType, $hideVendor)
- {
- return [
- [
- 'name',
- function ($model) {
- return link_to("vendors/{$model->public_id}", $model->name ?: '')->toHtml();
- }
- ],
- [
- 'city',
- function ($model) {
- return $model->city;
- }
- ],
- [
- 'work_phone',
- function ($model) {
- return $model->work_phone;
- }
- ],
- [
- 'email',
- function ($model) {
- return link_to("vendors/{$model->public_id}", $model->email ?: '')->toHtml();
- }
- ],
- [
- 'vendors.created_at',
- function ($model) {
- return Utils::timestampToDateString(strtotime($model->created_at));
- }
- ],
- ];
- }
-
- protected function getDatatableActions($entityType)
- {
- return [
- [
- trans('texts.edit_vendor'),
- function ($model) {
- return URL::to("vendors/{$model->public_id}/edit");
- },
- function ($model) {
- return Auth::user()->can('editByOwner', [ENTITY_VENDOR, $model->user_id]);
- }
- ],
- [
- '--divider--', function(){return false;},
- function ($model) {
- return Auth::user()->can('editByOwner', [ENTITY_VENDOR, $model->user_id]) && Auth::user()->can('create', ENTITY_EXPENSE);
- }
-
- ],
- [
- trans('texts.enter_expense'),
- function ($model) {
- return URL::to("expenses/create/{$model->public_id}");
- },
- function ($model) {
- return Auth::user()->can('create', ENTITY_EXPENSE);
- }
- ]
- ];
- }
}
diff --git a/database/seeds/DateFormatsSeeder.php b/database/seeds/DateFormatsSeeder.php
index 40568ca3000a..c55028b6840c 100644
--- a/database/seeds/DateFormatsSeeder.php
+++ b/database/seeds/DateFormatsSeeder.php
@@ -11,22 +11,24 @@ class DateFormatsSeeder extends Seeder
// Date formats
$formats = [
- ['format' => 'd/M/Y', 'picker_format' => 'dd/M/yyyy', 'label' => '10/Mar/2013'],
- ['format' => 'd-M-Y', 'picker_format' => 'dd-M-yyyy', 'label' => '10-Mar-2013'],
- ['format' => 'd/F/Y', 'picker_format' => 'dd/MM/yyyy', 'label' => '10/March/2013'],
- ['format' => 'd-F-Y', 'picker_format' => 'dd-MM-yyyy', 'label' => '10-March-2013'],
- ['format' => 'M j, Y', 'picker_format' => 'M d, yyyy', 'label' => 'Mar 10, 2013'],
- ['format' => 'F j, Y', 'picker_format' => 'MM d, yyyy', 'label' => 'March 10, 2013'],
- ['format' => 'D M j, Y', 'picker_format' => 'D MM d, yyyy', 'label' => 'Mon March 10, 2013'],
- ['format' => 'Y-m-d', 'picker_format' => 'yyyy-mm-dd', 'label' => '2013-03-10'],
- ['format' => 'd-m-Y', 'picker_format' => 'dd-mm-yyyy', 'label' => '20-03-2013'],
- ['format' => 'm/d/Y', 'picker_format' => 'mm/dd/yyyy', 'label' => '03/20/2013']
+ ['format' => 'd/M/Y', 'picker_format' => 'dd/M/yyyy'],
+ ['format' => 'd-M-Y', 'picker_format' => 'dd-M-yyyy'],
+ ['format' => 'd/F/Y', 'picker_format' => 'dd/MM/yyyy'],
+ ['format' => 'd-F-Y', 'picker_format' => 'dd-MM-yyyy'],
+ ['format' => 'M j, Y', 'picker_format' => 'M d, yyyy'],
+ ['format' => 'F j, Y', 'picker_format' => 'MM d, yyyy'],
+ ['format' => 'D M j, Y', 'picker_format' => 'D MM d, yyyy'],
+ ['format' => 'Y-m-d', 'picker_format' => 'yyyy-mm-dd'],
+ ['format' => 'd-m-Y', 'picker_format' => 'dd-mm-yyyy'],
+ ['format' => 'm/d/Y', 'picker_format' => 'mm/dd/yyyy'],
+ ['format' => 'd.m.Y', 'picker_format' => 'dd.mm.yyyy'],
+ ['format' => 'j. M. Y', 'picker_format' => 'd. M. yyyy'],
+ ['format' => 'j. F Y', 'picker_format' => 'd. MM yyyy']
];
-
+
foreach ($formats as $format) {
- $record = DateFormat::whereLabel($format['label'])->first();
+ $record = DateFormat::whereFormat($format['format'])->first();
if ($record) {
- $record->format = $format['format'];
$record->picker_format = $format['picker_format'];
$record->save();
} else {
@@ -36,62 +38,24 @@ class DateFormatsSeeder extends Seeder
// Date/time formats
$formats = [
- [
- 'format' => 'd/M/Y g:i a',
- 'format_moment' => 'DD/MMM/YYYY h:mm:ss a',
- 'label' => '10/Mar/2013'
- ],
- [
- 'format' => 'd-M-Y g:i a',
- 'format_moment' => 'DD-MMM-YYYY h:mm:ss a',
- 'label' => '10-Mar-2013'
- ],
- [
- 'format' => 'd/F/Y g:i a',
- 'format_moment' => 'DD/MMMM/YYYY h:mm:ss a',
- 'label' => '10/March/2013'
- ],
- [
- 'format' => 'd-F-Y g:i a',
- 'format_moment' => 'DD-MMMM-YYYY h:mm:ss a',
- 'label' => '10-March-2013'
- ],
- [
- 'format' => 'M j, Y g:i a',
- 'format_moment' => 'MMM D, YYYY h:mm:ss a',
- 'label' => 'Mar 10, 2013 6:15 pm'
- ],
- [
- 'format' => 'F j, Y g:i a',
- 'format_moment' => 'MMMM D, YYYY h:mm:ss a',
- 'label' => 'March 10, 2013 6:15 pm'
- ],
- [
- 'format' => 'D M jS, Y g:i a',
- 'format_moment' => 'ddd MMM Do, YYYY h:mm:ss a',
- 'label' => 'Mon March 10th, 2013 6:15 pm'
- ],
- [
- 'format' => 'Y-m-d g:i a',
- 'format_moment' => 'YYYY-MMM-DD h:mm:ss a',
- 'label' => '2013-03-10 6:15 pm'
- ],
- [
- 'format' => 'd-m-Y g:i a',
- 'format_moment' => 'DD-MM-YYYY h:mm:ss a',
- 'label' => '20-03-2013 6:15 pm'
- ],
- [
- 'format' => 'm/d/Y g:i a',
- 'format_moment' => 'MM/DD/YYYY h:mm:ss a',
- 'label' => '03/20/2013 6:15 pm'
- ]
+ ['format' => 'd/M/Y g:i a', 'format_moment' => 'DD/MMM/YYYY h:mm:ss a'],
+ ['format' => 'd-M-Y g:i a', 'format_moment' => 'DD-MMM-YYYY h:mm:ss a'],
+ ['format' => 'd/F/Y g:i a', 'format_moment' => 'DD/MMMM/YYYY h:mm:ss a'],
+ ['format' => 'd-F-Y g:i a', 'format_moment' => 'DD-MMMM-YYYY h:mm:ss a'],
+ ['format' => 'M j, Y g:i a', 'format_moment' => 'MMM D, YYYY h:mm:ss a'],
+ ['format' => 'F j, Y g:i a', 'format_moment' => 'MMMM D, YYYY h:mm:ss a'],
+ ['format' => 'D M jS, Y g:i a', 'format_moment' => 'ddd MMM Do, YYYY h:mm:ss a'],
+ ['format' => 'Y-m-d g:i a', 'format_moment' => 'YYYY-MMM-DD h:mm:ss a'],
+ ['format' => 'd-m-Y g:i a', 'format_moment' => 'DD-MM-YYYY h:mm:ss a'],
+ ['format' => 'm/d/Y g:i a', 'format_moment' => 'MM/DD/YYYY h:mm:ss a'],
+ ['format' => 'd.m.Y g:i a', 'format_moment' => 'D.MM.YYYY h:mm:ss a'],
+ ['format' => 'j. M. Y g:i a', 'format_moment' => 'DD. MMM. YYYY h:mm:ss a'],
+ ['format' => 'j. F Y g:i a', 'format_moment' => 'DD. MMMM YYYY h:mm:ss a']
];
-
+
foreach ($formats as $format) {
- $record = DatetimeFormat::whereLabel($format['label'])->first();
+ $record = DatetimeFormat::whereFormat($format['format'])->first();
if ($record) {
- $record->format = $format['format'];
$record->format_moment = $format['format_moment'];
$record->save();
} else {
diff --git a/database/seeds/UserTableSeeder.php b/database/seeds/UserTableSeeder.php
index dbaba660b75c..00a081cb5412 100644
--- a/database/seeds/UserTableSeeder.php
+++ b/database/seeds/UserTableSeeder.php
@@ -20,7 +20,7 @@ class UserTableSeeder extends Seeder
$faker = Faker\Factory::create();
$company = Company::create();
-
+
$account = Account::create([
'name' => $faker->name,
'address1' => $faker->streetAddress,
@@ -28,12 +28,12 @@ class UserTableSeeder extends Seeder
'city' => $faker->city,
'state' => $faker->state,
'postal_code' => $faker->postcode,
- 'country_id' => Country::all()->random()->id,
+ 'country_id' => Country::all()->random()->id,
'account_key' => str_random(RANDOM_KEY_LENGTH),
'invoice_terms' => $faker->text($faker->numberBetween(50, 300)),
'work_phone' => $faker->phoneNumber,
'work_email' => $faker->safeEmail,
- 'invoice_design_id' => min(InvoiceDesign::all()->random()->id, 10),
+ 'invoice_design_id' => InvoiceDesign::where('id', '<', CUSTOM_DESIGN)->get()->random()->id,
'header_font_id' => min(Font::all()->random()->id, 17),
'body_font_id' => min(Font::all()->random()->id, 17),
'primary_color' => $faker->hexcolor,
@@ -55,7 +55,7 @@ class UserTableSeeder extends Seeder
Affiliate::create([
'affiliate_key' => SELF_HOST_AFFILIATE_KEY
]);
-
+
}
-}
\ No newline at end of file
+}
diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php
index f73e936f5fb5..2b9f2e5f4aec 100644
--- a/resources/lang/en/texts.php
+++ b/resources/lang/en/texts.php
@@ -1305,6 +1305,12 @@ $LANG = array(
'canada' => 'Canada',
'accept_debit_cards' => 'Accept Debit Cards',
'debit_cards' => 'Debit Cards',
+
+ 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.',
+ 'original_start_date' => 'Original start date',
+ 'new_start_date' => 'New start date',
+ 'security' => 'Security',
+ 'see_whats_new' => 'See what\'s new in v:version',
);
return $LANG;
diff --git a/resources/views/accounts/client_portal.blade.php b/resources/views/accounts/client_portal.blade.php
index 1df146123fa3..14883901831c 100644
--- a/resources/views/accounts/client_portal.blade.php
+++ b/resources/views/accounts/client_portal.blade.php
@@ -30,9 +30,10 @@
+
-
{!! trans('texts.client_portal') !!}
+ {!! trans('texts.navigation') !!}
@@ -45,20 +46,29 @@
->text(trans('texts.enable'))
->help(trans('texts.enable_client_portal_dashboard_help')) !!}
+
+
+
+
+
+
{!! trans('texts.security') !!}
+
+
{!! Former::checkbox('enable_portal_password')
- ->text(trans('texts.enable_portal_password'))
+ ->text(trans('texts.enable'))
->help(trans('texts.enable_portal_password_help'))
- ->label(' ') !!}
+ ->label(trans('texts.enable_portal_password')) !!}
{!! Former::checkbox('send_portal_password')
- ->text(trans('texts.send_portal_password'))
+ ->text(trans('texts.enable'))
->help(trans('texts.send_portal_password_help'))
- ->label(' ') !!}
+ ->label(trans('texts.send_portal_password')) !!}
+
@if (Utils::hasFeature(FEATURE_CLIENT_PORTAL_CSS))
diff --git a/resources/views/accounts/localization.blade.php b/resources/views/accounts/localization.blade.php
index b921c8710567..ccca9f3c4e20 100644
--- a/resources/views/accounts/localization.blade.php
+++ b/resources/views/accounts/localization.blade.php
@@ -1,6 +1,6 @@
@extends('header')
-@section('content')
+@section('content')
@parent
{!! Former::open_for_files()->addClass('warn-on-exit') !!}
@@ -11,7 +11,7 @@
@include('accounts.nav', ['selected' => ACCOUNT_LOCALIZATION])
-
+
@@ -21,15 +21,15 @@
{!! Former::select('currency_id')->addOption('','')
- ->fromQuery($currencies, 'name', 'id') !!}
+ ->fromQuery($currencies, 'name', 'id') !!}
{!! Former::select('language_id')->addOption('','')
- ->fromQuery($languages, 'name', 'id') !!}
+ ->fromQuery($languages, 'name', 'id') !!}
{!! Former::select('timezone_id')->addOption('','')
->fromQuery($timezones, 'location', 'id') !!}
{!! Former::select('date_format_id')->addOption('','')
- ->fromQuery($dateFormats, 'label', 'id') !!}
+ ->fromQuery($dateFormats) !!}
{!! Former::select('datetime_format_id')->addOption('','')
- ->fromQuery($datetimeFormats, 'label', 'id') !!}
+ ->fromQuery($datetimeFormats) !!}
{!! Former::checkbox('military_time')->text(trans('texts.enable')) !!}
{{-- Former::checkbox('show_currency_code')->text(trans('texts.enable')) --}}
@@ -48,4 +48,4 @@
@section('onReady')
$('#currency_id').focus();
-@stop
\ No newline at end of file
+@stop
diff --git a/resources/views/expenses/edit.blade.php b/resources/views/expenses/edit.blade.php
index b6eb65f763c1..41af3f1e801e 100644
--- a/resources/views/expenses/edit.blade.php
+++ b/resources/views/expenses/edit.blade.php
@@ -364,6 +364,12 @@
@if (Auth::user()->account->hasFeature(FEATURE_DOCUMENTS))
function handleDocumentAdded(file){
+ // open document when clicked
+ if (file.url) {
+ file.previewElement.addEventListener("click", function() {
+ window.open(file.url, '_blank');
+ });
+ }
if(file.mock)return;
file.index = model.documents().length;
model.addDocument({name:file.name, size:file.size, type:file.type});
diff --git a/resources/views/invoices/edit.blade.php b/resources/views/invoices/edit.blade.php
index 9deb5322452a..3ca6acafba59 100644
--- a/resources/views/invoices/edit.blade.php
+++ b/resources/views/invoices/edit.blade.php
@@ -527,7 +527,9 @@
{!! Former::select('invoice_design_id')->style('display:inline;width:150px;background-color:white !important')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id") !!}
@endif
- {!! Button::primary(trans('texts.download_pdf'))->withAttributes(array('onclick' => 'onDownloadClick()'))->appendIcon(Icon::create('download-alt')) !!}
+ @if ( ! $invoice->is_recurring)
+ {!! Button::primary(trans('texts.download_pdf'))->withAttributes(array('onclick' => 'onDownloadClick()'))->appendIcon(Icon::create('download-alt')) !!}
+ @endif
@if ($invoice->isClientTrashed())
@@ -807,6 +809,7 @@
var invoice = {!! $invoice !!};
ko.mapping.fromJS(invoice, model.invoice().mapping, model.invoice);
model.invoice().is_recurring({{ $invoice->is_recurring ? '1' : '0' }});
+ model.invoice().start_date_orig(model.invoice().start_date());
@if ($invoice->id)
var invitationContactIds = {!! json_encode($invitationContactIds) !!};
@@ -1182,22 +1185,41 @@
if (!isEmailValid()) {
alert("{!! trans('texts.provide_email') !!}");
return;
- }
+8 }
if (confirm('{!! trans("texts.confirm_email_$entityType") !!}' + '\n\n' + getSendToEmails())) {
- preparePdfData('email');
+ var accountLanguageId = parseInt({{ $account->language_id ?: '0' }});
+ var clientLanguageId = parseInt(model.invoice().client().language_id()) || 0;
+ // if the client's language is different then we can't use the browser version of the PDF
+ if (clientLanguageId && clientLanguageId != accountLanguageId) {
+ submitAction('email');
+ } else {
+ preparePdfData('email');
+ }
}
}
function onSaveClick() {
- if (model.invoice().is_recurring() && {{ $invoice ? 'false' : 'true' }}) {
- if (confirm("{!! trans("texts.confirm_recurring_email_$entityType") !!}" + '\n\n' + getSendToEmails() + '\n' + "{!! trans("texts.confirm_recurring_timing") !!}")) {
- submitAction('');
- }
- } else {
- preparePdfData('');
- }
- }
+ if (model.invoice().is_recurring()) {
+ // warn invoice will be emailed when saving new recurring invoice
+ if ({{ $invoice->exists() ? 'false' : 'true' }}) {
+ if (confirm("{!! trans("texts.confirm_recurring_email_$entityType") !!}" + '\n\n' + getSendToEmails() + '\n' + "{!! trans("texts.confirm_recurring_timing") !!}")) {
+ submitAction('');
+ }
+ return;
+ // warn invoice will be emailed again if start date is changed
+ } else if (model.invoice().start_date() != model.invoice().start_date_orig()) {
+ if (confirm("{!! trans("texts.warn_start_date_changed") !!}" + '\n\n'
+ + "{!! trans("texts.original_start_date") !!}: " + model.invoice().start_date_orig() + '\n'
+ + "{!! trans("texts.new_start_date") !!}: " + model.invoice().start_date())) {
+ submitAction('');
+ }
+ return;
+ }
+ }
+
+ preparePdfData('');
+ }
function getSendToEmails() {
var client = model.invoice().client();
@@ -1403,6 +1425,12 @@
@if ($account->hasFeature(FEATURE_DOCUMENTS))
function handleDocumentAdded(file){
+ // open document when clicked
+ if (file.url) {
+ file.previewElement.addEventListener("click", function() {
+ window.open(file.url, '_blank');
+ });
+ }
if(file.mock)return;
file.index = model.invoice().documents().length;
model.invoice().addDocument({name:file.name, size:file.size, type:file.type});
diff --git a/resources/views/invoices/knockout.blade.php b/resources/views/invoices/knockout.blade.php
index f92055b5df34..ab2e892c25f2 100644
--- a/resources/views/invoices/knockout.blade.php
+++ b/resources/views/invoices/knockout.blade.php
@@ -55,7 +55,7 @@ function ViewModel(data) {
if (self.invoice().tax_name1() || self.invoice().tax_name2()) {
return true;
}
-
+
return self.invoice_taxes() && {{ count($taxRateOptions) ? 'true' : 'false' }};
});
@@ -100,11 +100,11 @@ function ViewModel(data) {
$('input.client-email').each(function(item, value) {
var $email = $(value);
var email = $(value).val();
-
+
// Trim whitespace
email = (email || '').trim();
$email.val(email);
-
+
if (!firstName && (!email || !isValidEmailAddress(email))) {
isValid = false;
}
@@ -180,6 +180,7 @@ function InvoiceModel(data) {
self.due_date = ko.observable('');
self.recurring_due_date = ko.observable('');
self.start_date = ko.observable('');
+ self.start_date_orig = ko.observable('');
self.end_date = ko.observable('');
self.last_sent_date = ko.observable('');
self.tax_name1 = ko.observable();
@@ -240,13 +241,13 @@ function InvoiceModel(data) {
applyComboboxListeners();
return itemModel;
}
-
+
self.addDocument = function() {
var documentModel = new DocumentModel();
self.documents.push(documentModel);
return documentModel;
}
-
+
self.removeDocument = function(doc) {
var public_id = doc.public_id?doc.public_id():doc;
self.documents.remove(function(document) {
@@ -291,7 +292,7 @@ function InvoiceModel(data) {
self.tax_rate2(rate);
}
})
-
+
self.wrapped_terms = ko.computed({
read: function() {
return this.terms();
@@ -386,7 +387,7 @@ function InvoiceModel(data) {
var taxRate2 = parseFloat(self.tax_rate2());
var tax2 = roundToTwo(total * (taxRate2/100));
-
+
return self.formatMoney(tax1 + tax2);
});
@@ -403,7 +404,7 @@ function InvoiceModel(data) {
lineTotal -= roundToTwo(lineTotal * (self.discount()/100));
}
}
-
+
var taxAmount = roundToTwo(lineTotal * item.tax_rate1() / 100);
if (taxAmount) {
var key = item.tax_name1() + item.tax_rate1();
@@ -664,12 +665,12 @@ function ContactModel(data) {
return str;
});
-
+
self.info_color = ko.computed(function() {
if (self.invitation_viewed()) {
return '#57D172';
} else if (self.invitation_openend()) {
- return '#FFCC00';
+ return '#FFCC00';
} else {
return '#B1B5BA';
}
@@ -780,7 +781,7 @@ function ItemModel(data) {
this.onSelect = function() {}
}
-
+
function DocumentModel(data) {
var self = this;
self.public_id = ko.observable(0);
@@ -788,16 +789,16 @@ function DocumentModel(data) {
self.name = ko.observable('');
self.type = ko.observable('');
self.url = ko.observable('');
-
+
self.update = function(data){
ko.mapping.fromJS(data, {}, this);
}
-
+
if (data) {
self.update(data);
- }
+ }
}
-
+
var ExpenseModel = function(data) {
var self = this;
@@ -808,7 +809,7 @@ var ExpenseModel = function(data) {
}
}
}
-
+
self.description = ko.observable('');
self.qty = ko.observable(0);
self.public_id = ko.observable(0);
@@ -825,7 +826,7 @@ ko.bindingHandlers.typeahead = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var $element = $(element);
var allBindings = allBindingsAccessor();
-
+
$element.typeahead({
highlight: true,
minLength: 0,
@@ -875,4 +876,4 @@ ko.bindingHandlers.typeahead = {
}
};
-
\ No newline at end of file
+
diff --git a/resources/views/vendors/show.blade.php b/resources/views/vendors/show.blade.php
index 37572ee4c5bc..eca43f233662 100644
--- a/resources/views/vendors/show.blade.php
+++ b/resources/views/vendors/show.blade.php
@@ -152,7 +152,7 @@
trans('texts.expense_date'),
trans('texts.amount'),
trans('texts.public_notes'))
- ->setUrl(url('api/expenseVendor/' . $vendor->public_id))
+ ->setUrl(url('api/vendor_expense/' . $vendor->public_id))
->setCustomValues('entityType', 'expenses')
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)