mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-11 05:32:39 +01:00
Merge branch 'release-2.8.0'
This commit is contained in:
commit
b620356db1
1
.gitignore
vendored
1
.gitignore
vendored
@ -32,6 +32,7 @@ Thumbs.db
|
|||||||
/.project
|
/.project
|
||||||
tests/_output/
|
tests/_output/
|
||||||
tests/_bootstrap.php
|
tests/_bootstrap.php
|
||||||
|
tests/_support/_generated/
|
||||||
|
|
||||||
# composer stuff
|
# composer stuff
|
||||||
/c3.php
|
/c3.php
|
||||||
|
@ -65,6 +65,7 @@ before_script:
|
|||||||
- sleep 5
|
- sleep 5
|
||||||
# Make sure the app is up-to-date
|
# Make sure the app is up-to-date
|
||||||
- curl -L http://ninja.dev:8000/update
|
- curl -L http://ninja.dev:8000/update
|
||||||
|
#- php artisan ninja:create-test-data 25
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- php ./vendor/codeception/codeception/codecept run --debug acceptance AllPagesCept.php
|
- php ./vendor/codeception/codeception/codecept run --debug acceptance AllPagesCept.php
|
||||||
|
36
CHANGELOG.md
36
CHANGELOG.md
@ -1,36 +0,0 @@
|
|||||||
# Changelog
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
||||||
|
|
||||||
|
|
||||||
## [Unreleased]
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Auto billing uses credits if they exist
|
|
||||||
|
|
||||||
|
|
||||||
## [2.6.4] - 2016-07-19
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Added 'Buy Now' buttons
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Setting default tax rate breaks invoice creation #974
|
|
||||||
|
|
||||||
|
|
||||||
## [2.6] - 2016-07-12
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Configuration for first day of the week #950
|
|
||||||
- StyleCI configuration #929
|
|
||||||
- Added expense category
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Removed `invoiceninja.komodoproject` from Git #932
|
|
||||||
- `APP_CIPHER` changed from `rinjdael-128` to `AES-256-CBC` #898
|
|
||||||
- Improved options when exporting data
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- "Manual entry" untranslatable #562
|
|
||||||
- Using a database table prefix breaks the dashboard #203
|
|
||||||
- Request statically called in StartupCheck.php #977
|
|
@ -1,6 +1,7 @@
|
|||||||
<?php namespace App\Console\Commands;
|
<?php namespace App\Console\Commands;
|
||||||
|
|
||||||
use DB;
|
use DB;
|
||||||
|
use Mail;
|
||||||
use Carbon;
|
use Carbon;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
@ -51,9 +52,12 @@ class CheckData extends Command {
|
|||||||
*/
|
*/
|
||||||
protected $description = 'Check/fix data';
|
protected $description = 'Check/fix data';
|
||||||
|
|
||||||
|
protected $log = '';
|
||||||
|
protected $isValid = true;
|
||||||
|
|
||||||
public function fire()
|
public function fire()
|
||||||
{
|
{
|
||||||
$this->info(date('Y-m-d') . ' Running CheckData...');
|
$this->logMessage(date('Y-m-d') . ' Running CheckData...');
|
||||||
|
|
||||||
if (!$this->option('client_id')) {
|
if (!$this->option('client_id')) {
|
||||||
$this->checkPaidToDate();
|
$this->checkPaidToDate();
|
||||||
@ -66,7 +70,21 @@ class CheckData extends Command {
|
|||||||
$this->checkAccountData();
|
$this->checkAccountData();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->info('Done');
|
$this->logMessage('Done');
|
||||||
|
$errorEmail = env('ERROR_EMAIL');
|
||||||
|
|
||||||
|
if ( ! $this->isValid && $errorEmail) {
|
||||||
|
Mail::raw($this->log, function ($message) use ($errorEmail) {
|
||||||
|
$message->to($errorEmail)
|
||||||
|
->from(CONTACT_EMAIL)
|
||||||
|
->subject('Check-Data');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function logMessage($str)
|
||||||
|
{
|
||||||
|
$this->log .= $str . "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkBlankInvoiceHistory()
|
private function checkBlankInvoiceHistory()
|
||||||
@ -75,9 +93,14 @@ class CheckData extends Command {
|
|||||||
->where('activity_type_id', '=', 5)
|
->where('activity_type_id', '=', 5)
|
||||||
->where('json_backup', '=', '')
|
->where('json_backup', '=', '')
|
||||||
->whereNotIn('id', [634386, 756352, 756353, 756356])
|
->whereNotIn('id', [634386, 756352, 756353, 756356])
|
||||||
|
->whereNotIn('id', [634386, 756352, 756353, 756356, 820872])
|
||||||
->count();
|
->count();
|
||||||
|
|
||||||
$this->info($count . ' activities with blank invoice backup');
|
if ($count > 0) {
|
||||||
|
$this->isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logMessage($count . ' activities with blank invoice backup');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkAccountData()
|
private function checkAccountData()
|
||||||
@ -132,7 +155,8 @@ class CheckData extends Command {
|
|||||||
->get(["{$table}.id", 'clients.account_id', 'clients.user_id']);
|
->get(["{$table}.id", 'clients.account_id', 'clients.user_id']);
|
||||||
|
|
||||||
if (count($records)) {
|
if (count($records)) {
|
||||||
$this->info(count($records) . " {$table} records with incorrect {$entityType} account id");
|
$this->isValid = false;
|
||||||
|
$this->logMessage(count($records) . " {$table} records with incorrect {$entityType} account id");
|
||||||
|
|
||||||
if ($this->option('fix') == 'true') {
|
if ($this->option('fix') == 'true') {
|
||||||
foreach ($records as $record) {
|
foreach ($records as $record) {
|
||||||
@ -162,7 +186,11 @@ class CheckData extends Command {
|
|||||||
->groupBy('clients.id')
|
->groupBy('clients.id')
|
||||||
->havingRaw('clients.paid_to_date != sum(payments.amount - payments.refunded) and clients.paid_to_date != 999999999.9999')
|
->havingRaw('clients.paid_to_date != sum(payments.amount - payments.refunded) and clients.paid_to_date != 999999999.9999')
|
||||||
->get(['clients.id', 'clients.paid_to_date', DB::raw('sum(payments.amount) as amount')]);
|
->get(['clients.id', 'clients.paid_to_date', DB::raw('sum(payments.amount) as amount')]);
|
||||||
$this->info(count($clients) . ' clients with incorrect paid to date');
|
$this->logMessage(count($clients) . ' clients with incorrect paid to date');
|
||||||
|
|
||||||
|
if (count($clients) > 0) {
|
||||||
|
$this->isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->option('fix') == 'true') {
|
if ($this->option('fix') == 'true') {
|
||||||
foreach ($clients as $client) {
|
foreach ($clients as $client) {
|
||||||
@ -179,6 +207,7 @@ class CheckData extends Command {
|
|||||||
$clients = DB::table('clients')
|
$clients = DB::table('clients')
|
||||||
->join('invoices', 'invoices.client_id', '=', 'clients.id')
|
->join('invoices', 'invoices.client_id', '=', 'clients.id')
|
||||||
->join('accounts', 'accounts.id', '=', 'clients.account_id')
|
->join('accounts', 'accounts.id', '=', 'clients.account_id')
|
||||||
|
->where('accounts.id', '!=', 20432)
|
||||||
->where('clients.is_deleted', '=', 0)
|
->where('clients.is_deleted', '=', 0)
|
||||||
->where('invoices.is_deleted', '=', 0)
|
->where('invoices.is_deleted', '=', 0)
|
||||||
->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD)
|
->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD)
|
||||||
@ -192,10 +221,14 @@ class CheckData extends Command {
|
|||||||
$clients = $clients->groupBy('clients.id', 'clients.balance', 'clients.created_at')
|
$clients = $clients->groupBy('clients.id', 'clients.balance', 'clients.created_at')
|
||||||
->orderBy('accounts.company_id', 'DESC')
|
->orderBy('accounts.company_id', 'DESC')
|
||||||
->get(['accounts.company_id', 'clients.account_id', 'clients.id', 'clients.balance', 'clients.paid_to_date', DB::raw('sum(invoices.balance) actual_balance')]);
|
->get(['accounts.company_id', 'clients.account_id', 'clients.id', 'clients.balance', 'clients.paid_to_date', DB::raw('sum(invoices.balance) actual_balance')]);
|
||||||
$this->info(count($clients) . ' clients with incorrect balance/activities');
|
$this->logMessage(count($clients) . ' clients with incorrect balance/activities');
|
||||||
|
|
||||||
|
if (count($clients) > 0) {
|
||||||
|
$this->isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($clients as $client) {
|
foreach ($clients as $client) {
|
||||||
$this->info("=== Company: {$client->company_id} Account:{$client->account_id} Client:{$client->id} Balance:{$client->balance} Actual Balance:{$client->actual_balance} ===");
|
$this->logMessage("=== Company: {$client->company_id} Account:{$client->account_id} Client:{$client->id} Balance:{$client->balance} Actual Balance:{$client->actual_balance} ===");
|
||||||
$foundProblem = false;
|
$foundProblem = false;
|
||||||
$lastBalance = 0;
|
$lastBalance = 0;
|
||||||
$lastAdjustment = 0;
|
$lastAdjustment = 0;
|
||||||
@ -205,7 +238,7 @@ class CheckData extends Command {
|
|||||||
->where('client_id', '=', $client->id)
|
->where('client_id', '=', $client->id)
|
||||||
->orderBy('activities.id')
|
->orderBy('activities.id')
|
||||||
->get(['activities.id', 'activities.created_at', 'activities.activity_type_id', 'activities.adjustment', 'activities.balance', 'activities.invoice_id']);
|
->get(['activities.id', 'activities.created_at', 'activities.activity_type_id', 'activities.adjustment', 'activities.balance', 'activities.invoice_id']);
|
||||||
//$this->info(var_dump($activities));
|
//$this->logMessage(var_dump($activities));
|
||||||
|
|
||||||
foreach ($activities as $activity) {
|
foreach ($activities as $activity) {
|
||||||
|
|
||||||
@ -252,19 +285,19 @@ class CheckData extends Command {
|
|||||||
|
|
||||||
// **Fix for ninja invoices which didn't have the invoice_type_id value set
|
// **Fix for ninja invoices which didn't have the invoice_type_id value set
|
||||||
if ($noAdjustment && $client->account_id == 20432) {
|
if ($noAdjustment && $client->account_id == 20432) {
|
||||||
$this->info("No adjustment for ninja invoice");
|
$this->logMessage("No adjustment for ninja invoice");
|
||||||
$foundProblem = true;
|
$foundProblem = true;
|
||||||
$clientFix += $invoice->amount;
|
$clientFix += $invoice->amount;
|
||||||
$activityFix = $invoice->amount;
|
$activityFix = $invoice->amount;
|
||||||
// **Fix for allowing converting a recurring invoice to a normal one without updating the balance**
|
// **Fix for allowing converting a recurring invoice to a normal one without updating the balance**
|
||||||
} elseif ($noAdjustment && $invoice->invoice_type_id == INVOICE_TYPE_STANDARD && !$invoice->is_recurring) {
|
} elseif ($noAdjustment && $invoice->invoice_type_id == INVOICE_TYPE_STANDARD && !$invoice->is_recurring) {
|
||||||
$this->info("No adjustment for new invoice:{$activity->invoice_id} amount:{$invoice->amount} invoiceTypeId:{$invoice->invoice_type_id} isRecurring:{$invoice->is_recurring}");
|
$this->logMessage("No adjustment for new invoice:{$activity->invoice_id} amount:{$invoice->amount} invoiceTypeId:{$invoice->invoice_type_id} isRecurring:{$invoice->is_recurring}");
|
||||||
$foundProblem = true;
|
$foundProblem = true;
|
||||||
$clientFix += $invoice->amount;
|
$clientFix += $invoice->amount;
|
||||||
$activityFix = $invoice->amount;
|
$activityFix = $invoice->amount;
|
||||||
// **Fix for updating balance when creating a quote or recurring invoice**
|
// **Fix for updating balance when creating a quote or recurring invoice**
|
||||||
} elseif ($activity->adjustment != 0 && ($invoice->invoice_type_id == INVOICE_TYPE_QUOTE || $invoice->is_recurring)) {
|
} elseif ($activity->adjustment != 0 && ($invoice->invoice_type_id == INVOICE_TYPE_QUOTE || $invoice->is_recurring)) {
|
||||||
$this->info("Incorrect adjustment for new invoice:{$activity->invoice_id} adjustment:{$activity->adjustment} invoiceTypeId:{$invoice->invoice_type_id} isRecurring:{$invoice->is_recurring}");
|
$this->logMessage("Incorrect adjustment for new invoice:{$activity->invoice_id} adjustment:{$activity->adjustment} invoiceTypeId:{$invoice->invoice_type_id} isRecurring:{$invoice->is_recurring}");
|
||||||
$foundProblem = true;
|
$foundProblem = true;
|
||||||
$clientFix -= $activity->adjustment;
|
$clientFix -= $activity->adjustment;
|
||||||
$activityFix = 0;
|
$activityFix = 0;
|
||||||
@ -272,7 +305,7 @@ class CheckData extends Command {
|
|||||||
} elseif ($activity->activity_type_id == ACTIVITY_TYPE_DELETE_INVOICE) {
|
} elseif ($activity->activity_type_id == ACTIVITY_TYPE_DELETE_INVOICE) {
|
||||||
// **Fix for updating balance when deleting a recurring invoice**
|
// **Fix for updating balance when deleting a recurring invoice**
|
||||||
if ($activity->adjustment != 0 && $invoice->is_recurring) {
|
if ($activity->adjustment != 0 && $invoice->is_recurring) {
|
||||||
$this->info("Incorrect adjustment for deleted invoice adjustment:{$activity->adjustment}");
|
$this->logMessage("Incorrect adjustment for deleted invoice adjustment:{$activity->adjustment}");
|
||||||
$foundProblem = true;
|
$foundProblem = true;
|
||||||
if ($activity->balance != $lastBalance) {
|
if ($activity->balance != $lastBalance) {
|
||||||
$clientFix -= $activity->adjustment;
|
$clientFix -= $activity->adjustment;
|
||||||
@ -282,7 +315,7 @@ class CheckData extends Command {
|
|||||||
} elseif ($activity->activity_type_id == ACTIVITY_TYPE_ARCHIVE_INVOICE) {
|
} elseif ($activity->activity_type_id == ACTIVITY_TYPE_ARCHIVE_INVOICE) {
|
||||||
// **Fix for updating balance when archiving an invoice**
|
// **Fix for updating balance when archiving an invoice**
|
||||||
if ($activity->adjustment != 0 && !$invoice->is_recurring) {
|
if ($activity->adjustment != 0 && !$invoice->is_recurring) {
|
||||||
$this->info("Incorrect adjustment for archiving invoice adjustment:{$activity->adjustment}");
|
$this->logMessage("Incorrect adjustment for archiving invoice adjustment:{$activity->adjustment}");
|
||||||
$foundProblem = true;
|
$foundProblem = true;
|
||||||
$activityFix = 0;
|
$activityFix = 0;
|
||||||
$clientFix += $activity->adjustment;
|
$clientFix += $activity->adjustment;
|
||||||
@ -290,12 +323,12 @@ class CheckData extends Command {
|
|||||||
} elseif ($activity->activity_type_id == ACTIVITY_TYPE_UPDATE_INVOICE) {
|
} elseif ($activity->activity_type_id == ACTIVITY_TYPE_UPDATE_INVOICE) {
|
||||||
// **Fix for updating balance when updating recurring invoice**
|
// **Fix for updating balance when updating recurring invoice**
|
||||||
if ($activity->adjustment != 0 && $invoice->is_recurring) {
|
if ($activity->adjustment != 0 && $invoice->is_recurring) {
|
||||||
$this->info("Incorrect adjustment for updated recurring invoice adjustment:{$activity->adjustment}");
|
$this->logMessage("Incorrect adjustment for updated recurring invoice adjustment:{$activity->adjustment}");
|
||||||
$foundProblem = true;
|
$foundProblem = true;
|
||||||
$clientFix -= $activity->adjustment;
|
$clientFix -= $activity->adjustment;
|
||||||
$activityFix = 0;
|
$activityFix = 0;
|
||||||
} else if ((strtotime($activity->created_at) - strtotime($lastCreatedAt) <= 1) && $activity->adjustment > 0 && $activity->adjustment == $lastAdjustment) {
|
} else if ((strtotime($activity->created_at) - strtotime($lastCreatedAt) <= 1) && $activity->adjustment > 0 && $activity->adjustment == $lastAdjustment) {
|
||||||
$this->info("Duplicate adjustment for updated invoice adjustment:{$activity->adjustment}");
|
$this->logMessage("Duplicate adjustment for updated invoice adjustment:{$activity->adjustment}");
|
||||||
$foundProblem = true;
|
$foundProblem = true;
|
||||||
$clientFix -= $activity->adjustment;
|
$clientFix -= $activity->adjustment;
|
||||||
$activityFix = 0;
|
$activityFix = 0;
|
||||||
@ -303,7 +336,7 @@ class CheckData extends Command {
|
|||||||
} elseif ($activity->activity_type_id == ACTIVITY_TYPE_UPDATE_QUOTE) {
|
} elseif ($activity->activity_type_id == ACTIVITY_TYPE_UPDATE_QUOTE) {
|
||||||
// **Fix for updating balance when updating a quote**
|
// **Fix for updating balance when updating a quote**
|
||||||
if ($activity->balance != $lastBalance) {
|
if ($activity->balance != $lastBalance) {
|
||||||
$this->info("Incorrect adjustment for updated quote adjustment:{$activity->adjustment}");
|
$this->logMessage("Incorrect adjustment for updated quote adjustment:{$activity->adjustment}");
|
||||||
$foundProblem = true;
|
$foundProblem = true;
|
||||||
$clientFix += $lastBalance - $activity->balance;
|
$clientFix += $lastBalance - $activity->balance;
|
||||||
$activityFix = 0;
|
$activityFix = 0;
|
||||||
@ -311,7 +344,7 @@ class CheckData extends Command {
|
|||||||
} else if ($activity->activity_type_id == ACTIVITY_TYPE_DELETE_PAYMENT) {
|
} else if ($activity->activity_type_id == ACTIVITY_TYPE_DELETE_PAYMENT) {
|
||||||
// **Fix for deleting payment after deleting invoice**
|
// **Fix for deleting payment after deleting invoice**
|
||||||
if ($activity->adjustment != 0 && $invoice->is_deleted && $activity->created_at > $invoice->deleted_at) {
|
if ($activity->adjustment != 0 && $invoice->is_deleted && $activity->created_at > $invoice->deleted_at) {
|
||||||
$this->info("Incorrect adjustment for deleted payment adjustment:{$activity->adjustment}");
|
$this->logMessage("Incorrect adjustment for deleted payment adjustment:{$activity->adjustment}");
|
||||||
$foundProblem = true;
|
$foundProblem = true;
|
||||||
$activityFix = 0;
|
$activityFix = 0;
|
||||||
$clientFix -= $activity->adjustment;
|
$clientFix -= $activity->adjustment;
|
||||||
@ -340,7 +373,7 @@ class CheckData extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($activity->balance + $clientFix != $client->actual_balance) {
|
if ($activity->balance + $clientFix != $client->actual_balance) {
|
||||||
$this->info("** Creating 'recovered update' activity **");
|
$this->logMessage("** Creating 'recovered update' activity **");
|
||||||
if ($this->option('fix') == 'true') {
|
if ($this->option('fix') == 'true') {
|
||||||
DB::table('activities')->insert([
|
DB::table('activities')->insert([
|
||||||
'created_at' => new Carbon,
|
'created_at' => new Carbon,
|
||||||
@ -354,7 +387,7 @@ class CheckData extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$data = ['balance' => $client->actual_balance];
|
$data = ['balance' => $client->actual_balance];
|
||||||
$this->info("Corrected balance:{$client->actual_balance}");
|
$this->logMessage("Corrected balance:{$client->actual_balance}");
|
||||||
if ($this->option('fix') == 'true') {
|
if ($this->option('fix') == 'true') {
|
||||||
DB::table('clients')
|
DB::table('clients')
|
||||||
->where('id', $client->id)
|
->where('id', $client->id)
|
||||||
|
28
app/Events/TaskWasArchived.php
Normal file
28
app/Events/TaskWasArchived.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php namespace App\Events;
|
||||||
|
|
||||||
|
use App\Models\Task;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class TaskWasArchived
|
||||||
|
*/
|
||||||
|
class TaskWasArchived extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Task
|
||||||
|
*/
|
||||||
|
public $task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @param Task $task
|
||||||
|
*/
|
||||||
|
public function __construct(Task $task)
|
||||||
|
{
|
||||||
|
$this->task = $task;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
28
app/Events/TaskWasDeleted.php
Normal file
28
app/Events/TaskWasDeleted.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php namespace App\Events;
|
||||||
|
|
||||||
|
use App\Models\Task;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class TaskWasDeleted
|
||||||
|
*/
|
||||||
|
class TaskWasDeleted extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Task
|
||||||
|
*/
|
||||||
|
public $task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @param Task $task
|
||||||
|
*/
|
||||||
|
public function __construct(Task $task)
|
||||||
|
{
|
||||||
|
$this->task = $task;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
app/Events/TaskWasRestored.php
Normal file
29
app/Events/TaskWasRestored.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php namespace App\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use App\Models\Task;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class TaskWasRestored
|
||||||
|
*/
|
||||||
|
class TaskWasRestored extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Task
|
||||||
|
*/
|
||||||
|
public $task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @param Task $task
|
||||||
|
*/
|
||||||
|
public function __construct(Task $task)
|
||||||
|
{
|
||||||
|
$this->task = $task;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
<?php namespace App\Exceptions;
|
<?php namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Braintree\Util;
|
||||||
|
use Illuminate\Support\Facades\Response;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
use Utils;
|
use Utils;
|
||||||
use Exception;
|
use Exception;
|
||||||
@ -69,7 +71,7 @@ class Handler extends ExceptionHandler
|
|||||||
{
|
{
|
||||||
if ($e instanceof ModelNotFoundException) {
|
if ($e instanceof ModelNotFoundException) {
|
||||||
return Redirect::to('/');
|
return Redirect::to('/');
|
||||||
} elseif ($e instanceof \Illuminate\Session\TokenMismatchException) {
|
} if ($e instanceof \Illuminate\Session\TokenMismatchException) {
|
||||||
// prevent loop since the page auto-submits
|
// prevent loop since the page auto-submits
|
||||||
if ($request->path() != 'get_started') {
|
if ($request->path() != 'get_started') {
|
||||||
// https://gist.github.com/jrmadsen67/bd0f9ad0ef1ed6bb594e
|
// https://gist.github.com/jrmadsen67/bd0f9ad0ef1ed6bb594e
|
||||||
@ -82,6 +84,40 @@ class Handler extends ExceptionHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($this->isHttpException($e))
|
||||||
|
{
|
||||||
|
switch ($e->getStatusCode())
|
||||||
|
{
|
||||||
|
// not found
|
||||||
|
case 404:
|
||||||
|
if($request->header('X-Ninja-Token') != '') {
|
||||||
|
//API request which has hit a route which does not exist
|
||||||
|
|
||||||
|
$error['error'] = ['message'=>'Route does not exist'];
|
||||||
|
$error = json_encode($error, JSON_PRETTY_PRINT);
|
||||||
|
$headers = Utils::getApiHeaders();
|
||||||
|
|
||||||
|
return response()->make($error, 404, $headers);
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// internal error
|
||||||
|
case '500':
|
||||||
|
if($request->header('X-Ninja-Token') != '') {
|
||||||
|
//API request which produces 500 error
|
||||||
|
|
||||||
|
$error['error'] = ['message'=>'Internal Server Error'];
|
||||||
|
$error = json_encode($error, JSON_PRETTY_PRINT);
|
||||||
|
$headers = Utils::getApiHeaders();
|
||||||
|
|
||||||
|
return response()->make($error, 500, $headers);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// In production, except for maintenance mode, we'll show a custom error screen
|
// In production, except for maintenance mode, we'll show a custom error screen
|
||||||
if (Utils::isNinjaProd()
|
if (Utils::isNinjaProd()
|
||||||
&& !Utils::isDownForMaintenance()
|
&& !Utils::isDownForMaintenance()
|
||||||
|
@ -4,6 +4,9 @@ use Auth;
|
|||||||
use Utils;
|
use Utils;
|
||||||
use Response;
|
use Response;
|
||||||
use Cache;
|
use Cache;
|
||||||
|
use Socialite;
|
||||||
|
use Exception;
|
||||||
|
use App\Services\AuthService;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Ninja\Repositories\AccountRepository;
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -181,4 +184,30 @@ class AccountApiController extends BaseAPIController
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function oauthLogin(Request $request)
|
||||||
|
{
|
||||||
|
$user = false;
|
||||||
|
$token = $request->input('token');
|
||||||
|
$provider = $request->input('provider');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$user = Socialite::driver($provider)->userFromToken($token);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return $this->errorResponse(['message' => $exception->getMessage()], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
$providerId = AuthService::getProviderId($provider);
|
||||||
|
$user = $this->accountRepo->findUserByOauth($providerId, $user->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
Auth::login($user);
|
||||||
|
return $this->processLogin($request);
|
||||||
|
} else {
|
||||||
|
sleep(ERROR_DELAY);
|
||||||
|
return $this->errorResponse(['message' => 'Invalid credentials'], 401);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<?php namespace App\Http\Controllers;
|
<?php namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\AccountGateway;
|
use App\Models\AccountGateway;
|
||||||
|
use App\Models\AccountGatewaySettings;
|
||||||
|
use App\Models\GatewayType;
|
||||||
use App\Services\TemplateService;
|
use App\Services\TemplateService;
|
||||||
use Auth;
|
use Auth;
|
||||||
use File;
|
use File;
|
||||||
@ -165,6 +167,10 @@ class AccountController extends BaseController
|
|||||||
$term = Input::get('plan_term');
|
$term = Input::get('plan_term');
|
||||||
$numUsers = Input::get('num_users');
|
$numUsers = Input::get('num_users');
|
||||||
|
|
||||||
|
if ($plan != PLAN_ENTERPRISE) {
|
||||||
|
$numUsers = 1;
|
||||||
|
}
|
||||||
|
|
||||||
$planDetails = $account->getPlanDetails(false, false);
|
$planDetails = $account->getPlanDetails(false, false);
|
||||||
|
|
||||||
$newPlan = [
|
$newPlan = [
|
||||||
@ -193,7 +199,9 @@ class AccountController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hasPaid = false;
|
||||||
if (!empty($planDetails['paid']) && $plan != PLAN_FREE) {
|
if (!empty($planDetails['paid']) && $plan != PLAN_FREE) {
|
||||||
|
$hasPaid = true;
|
||||||
$time_used = $planDetails['paid']->diff(date_create());
|
$time_used = $planDetails['paid']->diff(date_create());
|
||||||
$days_used = $time_used->days;
|
$days_used = $time_used->days;
|
||||||
|
|
||||||
@ -209,7 +217,11 @@ class AccountController extends BaseController
|
|||||||
|
|
||||||
if ($newPlan['price'] > $credit) {
|
if ($newPlan['price'] > $credit) {
|
||||||
$invitation = $this->accountRepo->enablePlan($newPlan, $credit);
|
$invitation = $this->accountRepo->enablePlan($newPlan, $credit);
|
||||||
return Redirect::to('view/' . $invitation->invitation_key);
|
if ($hasPaid) {
|
||||||
|
return Redirect::to('view/' . $invitation->invitation_key);
|
||||||
|
} else {
|
||||||
|
return Redirect::to('payment/' . $invitation->invitation_key);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if ($plan != PLAN_FREE) {
|
if ($plan != PLAN_FREE) {
|
||||||
@ -417,6 +429,7 @@ class AccountController extends BaseController
|
|||||||
'currencies' => Cache::get('currencies'),
|
'currencies' => Cache::get('currencies'),
|
||||||
'title' => trans('texts.localization'),
|
'title' => trans('texts.localization'),
|
||||||
'weekdays' => Utils::getTranslatedWeekdayNames(),
|
'weekdays' => Utils::getTranslatedWeekdayNames(),
|
||||||
|
'months' => Utils::getMonthOptions(),
|
||||||
];
|
];
|
||||||
|
|
||||||
return View::make('accounts.localization', $data);
|
return View::make('accounts.localization', $data);
|
||||||
@ -458,10 +471,12 @@ class AccountController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
return View::make('accounts.payments', [
|
return View::make('accounts.payments', [
|
||||||
'showAdd' => $count < count(Gateway::$alternate) + 1,
|
'showAdd' => $count < count(Gateway::$alternate) + 1,
|
||||||
'title' => trans('texts.online_payments'),
|
'title' => trans('texts.online_payments'),
|
||||||
'tokenBillingOptions' => $tokenBillingOptions,
|
'tokenBillingOptions' => $tokenBillingOptions,
|
||||||
'account' => $account,
|
'currency' => Utils::getFromCache(Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY),
|
||||||
|
'currencies'),
|
||||||
|
'account' => $account,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -471,16 +486,9 @@ class AccountController extends BaseController
|
|||||||
*/
|
*/
|
||||||
private function showProducts()
|
private function showProducts()
|
||||||
{
|
{
|
||||||
$columns = ['product', 'description', 'unit_cost'];
|
|
||||||
if (Auth::user()->account->invoice_item_taxes) {
|
|
||||||
$columns[] = 'tax_rate';
|
|
||||||
}
|
|
||||||
$columns[] = 'action';
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'account' => Auth::user()->account,
|
'account' => Auth::user()->account,
|
||||||
'title' => trans('texts.product_library'),
|
'title' => trans('texts.product_library'),
|
||||||
'columns' => Utils::trans($columns),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return View::make('accounts.products', $data);
|
return View::make('accounts.products', $data);
|
||||||
@ -667,11 +675,9 @@ class AccountController extends BaseController
|
|||||||
* @param $section
|
* @param $section
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function doSection($section = ACCOUNT_COMPANY_DETAILS)
|
public function doSection($section)
|
||||||
{
|
{
|
||||||
if ($section === ACCOUNT_COMPANY_DETAILS) {
|
if ($section === ACCOUNT_LOCALIZATION) {
|
||||||
return AccountController::saveDetails();
|
|
||||||
} elseif ($section === ACCOUNT_LOCALIZATION) {
|
|
||||||
return AccountController::saveLocalization();
|
return AccountController::saveLocalization();
|
||||||
} elseif ($section == ACCOUNT_PAYMENTS) {
|
} elseif ($section == ACCOUNT_PAYMENTS) {
|
||||||
return self::saveOnlinePayments();
|
return self::saveOnlinePayments();
|
||||||
@ -697,9 +703,27 @@ class AccountController extends BaseController
|
|||||||
return AccountController::saveTaxRates();
|
return AccountController::saveTaxRates();
|
||||||
} elseif ($section === ACCOUNT_PAYMENT_TERMS) {
|
} elseif ($section === ACCOUNT_PAYMENT_TERMS) {
|
||||||
return AccountController::savePaymetTerms();
|
return AccountController::savePaymetTerms();
|
||||||
|
} elseif ($section === ACCOUNT_MANAGEMENT) {
|
||||||
|
return AccountController::saveAccountManagement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
private function saveAccountManagement()
|
||||||
|
{
|
||||||
|
$account = Auth::user()->account;
|
||||||
|
$modules = Input::get('modules');
|
||||||
|
|
||||||
|
$account->enabled_modules = $modules ? array_sum($modules) : 0;
|
||||||
|
$account->save();
|
||||||
|
|
||||||
|
Session::flash('message', trans('texts.updated_settings'));
|
||||||
|
|
||||||
|
return Redirect::to('settings/'.ACCOUNT_MANAGEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
@ -723,12 +747,7 @@ class AccountController extends BaseController
|
|||||||
private function saveClientPortal()
|
private function saveClientPortal()
|
||||||
{
|
{
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
|
$account->fill(Input::all());
|
||||||
$account->enable_client_portal = !!Input::get('enable_client_portal');
|
|
||||||
$account->enable_client_portal_dashboard = !!Input::get('enable_client_portal_dashboard');
|
|
||||||
$account->enable_portal_password = !!Input::get('enable_portal_password');
|
|
||||||
$account->send_portal_password = !!Input::get('send_portal_password');
|
|
||||||
$account->enable_buy_now_buttons = !!Input::get('enable_buy_now_buttons');
|
|
||||||
|
|
||||||
// Only allowed for pro Invoice Ninja users or white labeled self-hosted users
|
// Only allowed for pro Invoice Ninja users or white labeled self-hosted users
|
||||||
if (Auth::user()->account->hasFeature(FEATURE_CLIENT_PORTAL_CSS)) {
|
if (Auth::user()->account->hasFeature(FEATURE_CLIENT_PORTAL_CSS)) {
|
||||||
@ -1200,6 +1219,7 @@ class AccountController extends BaseController
|
|||||||
$account->military_time = Input::get('military_time') ? true : false;
|
$account->military_time = Input::get('military_time') ? true : false;
|
||||||
$account->show_currency_code = Input::get('show_currency_code') ? true : false;
|
$account->show_currency_code = Input::get('show_currency_code') ? true : false;
|
||||||
$account->start_of_week = Input::get('start_of_week') ? Input::get('start_of_week') : 0;
|
$account->start_of_week = Input::get('start_of_week') ? Input::get('start_of_week') : 0;
|
||||||
|
$account->financial_year_start = Input::get('financial_year_start') ? Input::get('financial_year_start') : null;
|
||||||
$account->save();
|
$account->save();
|
||||||
|
|
||||||
event(new UserSettingsChanged());
|
event(new UserSettingsChanged());
|
||||||
@ -1226,6 +1246,35 @@ class AccountController extends BaseController
|
|||||||
return Redirect::to('settings/'.ACCOUNT_PAYMENTS);
|
return Redirect::to('settings/'.ACCOUNT_PAYMENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function savePaymentGatewayLimits()
|
||||||
|
{
|
||||||
|
$gateway_type_id = intval(Input::get('gateway_type_id'));
|
||||||
|
$gateway_settings = AccountGatewaySettings::scope()->where('gateway_type_id', '=', $gateway_type_id)->first();
|
||||||
|
|
||||||
|
if ( ! $gateway_settings) {
|
||||||
|
$gateway_settings = AccountGatewaySettings::createNew();
|
||||||
|
$gateway_settings->gateway_type_id = $gateway_type_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gateway_settings->min_limit = Input::get('limit_min_enable') ? intval(Input::get('limit_min')) : null;
|
||||||
|
$gateway_settings->max_limit = Input::get('limit_max_enable') ? intval(Input::get('limit_max')) : null;
|
||||||
|
|
||||||
|
if ($gateway_settings->max_limit !== null && $gateway_settings->min_limit > $gateway_settings->max_limit) {
|
||||||
|
$gateway_settings->max_limit = $gateway_settings->min_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gateway_settings->save();
|
||||||
|
|
||||||
|
event(new UserSettingsChanged());
|
||||||
|
|
||||||
|
Session::flash('message', trans('texts.updated_settings'));
|
||||||
|
|
||||||
|
return Redirect::to('settings/' . ACCOUNT_PAYMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
|
@ -48,8 +48,10 @@ class AccountGatewayController extends BaseController
|
|||||||
$accountGateway = AccountGateway::scope($publicId)->firstOrFail();
|
$accountGateway = AccountGateway::scope($publicId)->firstOrFail();
|
||||||
$config = $accountGateway->getConfig();
|
$config = $accountGateway->getConfig();
|
||||||
|
|
||||||
foreach ($config as $field => $value) {
|
if ($accountGateway->gateway_id != GATEWAY_CUSTOM) {
|
||||||
$config->$field = str_repeat('*', strlen($value));
|
foreach ($config as $field => $value) {
|
||||||
|
$config->$field = str_repeat('*', strlen($value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = self::getViewModel($accountGateway);
|
$data = self::getViewModel($accountGateway);
|
||||||
@ -60,8 +62,6 @@ class AccountGatewayController extends BaseController
|
|||||||
$data['hiddenFields'] = Gateway::$hiddenFields;
|
$data['hiddenFields'] = Gateway::$hiddenFields;
|
||||||
$data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get();
|
$data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get();
|
||||||
|
|
||||||
$this->testGateway($accountGateway);
|
|
||||||
|
|
||||||
return View::make('accounts.account_gateway', $data);
|
return View::make('accounts.account_gateway', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ class AccountGatewayController extends BaseController
|
|||||||
|
|
||||||
if ($otherProviders) {
|
if ($otherProviders) {
|
||||||
$availableGatewaysIds = $account->availableGatewaysIds();
|
$availableGatewaysIds = $account->availableGatewaysIds();
|
||||||
$data['primaryGateways'] = Gateway::primary($availableGatewaysIds)->orderBy('name', 'desc')->get();
|
$data['primaryGateways'] = Gateway::primary($availableGatewaysIds)->orderBy('sort_order')->get();
|
||||||
$data['secondaryGateways'] = Gateway::secondary($availableGatewaysIds)->orderBy('name')->get();
|
$data['secondaryGateways'] = Gateway::secondary($availableGatewaysIds)->orderBy('name')->get();
|
||||||
$data['hiddenFields'] = Gateway::$hiddenFields;
|
$data['hiddenFields'] = Gateway::$hiddenFields;
|
||||||
|
|
||||||
@ -132,7 +132,9 @@ class AccountGatewayController extends BaseController
|
|||||||
|
|
||||||
foreach ($gateways as $gateway) {
|
foreach ($gateways as $gateway) {
|
||||||
$fields = $gateway->getFields();
|
$fields = $gateway->getFields();
|
||||||
asort($fields);
|
if ( ! $gateway->isCustom()) {
|
||||||
|
asort($fields);
|
||||||
|
}
|
||||||
$gateway->fields = $gateway->id == GATEWAY_WEPAY ? [] : $fields;
|
$gateway->fields = $gateway->id == GATEWAY_WEPAY ? [] : $fields;
|
||||||
if ($accountGateway && $accountGateway->gateway_id == $gateway->id) {
|
if ($accountGateway && $accountGateway->gateway_id == $gateway->id) {
|
||||||
$accountGateway->fields = $gateway->fields;
|
$accountGateway->fields = $gateway->fields;
|
||||||
@ -247,6 +249,8 @@ class AccountGatewayController extends BaseController
|
|||||||
}
|
}
|
||||||
if (!$value && ($field == 'testMode' || $field == 'developerMode')) {
|
if (!$value && ($field == 'testMode' || $field == 'developerMode')) {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
} elseif ($gatewayId == GATEWAY_CUSTOM) {
|
||||||
|
$config->$field = strip_tags($value);
|
||||||
} else {
|
} else {
|
||||||
$config->$field = $value;
|
$config->$field = $value;
|
||||||
}
|
}
|
||||||
@ -312,14 +316,17 @@ class AccountGatewayController extends BaseController
|
|||||||
if (isset($wepayResponse)) {
|
if (isset($wepayResponse)) {
|
||||||
return $wepayResponse;
|
return $wepayResponse;
|
||||||
} else {
|
} else {
|
||||||
|
$this->testGateway($accountGateway);
|
||||||
|
|
||||||
if ($accountGatewayPublicId) {
|
if ($accountGatewayPublicId) {
|
||||||
$message = trans('texts.updated_gateway');
|
$message = trans('texts.updated_gateway');
|
||||||
|
Session::flash('message', $message);
|
||||||
|
return Redirect::to("gateways/{$accountGateway->public_id}/edit");
|
||||||
} else {
|
} else {
|
||||||
$message = trans('texts.created_gateway');
|
$message = trans('texts.created_gateway');
|
||||||
|
Session::flash('message', $message);
|
||||||
|
return Redirect::to("/settings/online_payments");
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::flash('message', $message);
|
|
||||||
return Redirect::to("gateways/{$accountGateway->public_id}/edit");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php namespace App\Http\Controllers;
|
<?php namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Utils;
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
|
|
||||||
@ -20,4 +21,24 @@ class BaseController extends Controller
|
|||||||
$this->layout = View::make($this->layout);
|
$this->layout = View::make($this->layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function returnBulk($entityType, $action, $ids)
|
||||||
|
{
|
||||||
|
if ( ! is_array($ids)) {
|
||||||
|
$ids = [$ids];
|
||||||
|
}
|
||||||
|
|
||||||
|
$isDatatable = filter_var(request()->datatable, FILTER_VALIDATE_BOOLEAN);
|
||||||
|
$entityTypes = Utils::pluralizeEntityType($entityType);
|
||||||
|
|
||||||
|
if ($action == 'restore' && count($ids) == 1) {
|
||||||
|
return redirect("{$entityTypes}/" . $ids[0]);
|
||||||
|
} elseif ($isDatatable || ($action == 'archive' || $action == 'delete')) {
|
||||||
|
return redirect("{$entityTypes}");
|
||||||
|
} elseif (count($ids)) {
|
||||||
|
return redirect("{$entityTypes}/" . $ids[0]);
|
||||||
|
} else {
|
||||||
|
return redirect("{$entityTypes}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php namespace App\Http\Controllers;
|
<?php namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\ClientRequest;
|
||||||
use Response;
|
use Response;
|
||||||
use Input;
|
use Input;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
@ -52,6 +53,31 @@ class ClientApiController extends BaseAPIController
|
|||||||
return $this->listResponse($clients);
|
return $this->listResponse($clients);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/clients/{client_id}",
|
||||||
|
* summary="Individual Client",
|
||||||
|
* tags={"client"},
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A single client",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Client"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function show(ClientRequest $request)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($request->entity());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/clients",
|
* path="/clients",
|
||||||
|
@ -95,7 +95,7 @@ class ClientController extends BaseController
|
|||||||
if($user->can('create', ENTITY_TASK)){
|
if($user->can('create', ENTITY_TASK)){
|
||||||
$actionLinks[] = ['label' => trans('texts.new_task'), 'url' => URL::to('/tasks/create/'.$client->public_id)];
|
$actionLinks[] = ['label' => trans('texts.new_task'), 'url' => URL::to('/tasks/create/'.$client->public_id)];
|
||||||
}
|
}
|
||||||
if (Utils::hasFeature(FEATURE_QUOTES) && $user->can('create', ENTITY_INVOICE)) {
|
if (Utils::hasFeature(FEATURE_QUOTES) && $user->can('create', ENTITY_QUOTE)) {
|
||||||
$actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => URL::to('/quotes/create/'.$client->public_id)];
|
$actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => URL::to('/quotes/create/'.$client->public_id)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,10 +221,6 @@ class ClientController extends BaseController
|
|||||||
$message = Utils::pluralize($action.'d_client', $count);
|
$message = Utils::pluralize($action.'d_client', $count);
|
||||||
Session::flash('message', $message);
|
Session::flash('message', $message);
|
||||||
|
|
||||||
if ($action == 'restore' && $count == 1) {
|
return $this->returnBulk(ENTITY_CLIENT, $action, $ids);
|
||||||
return Redirect::to('clients/'.Utils::getFirst($ids));
|
|
||||||
} else {
|
|
||||||
return Redirect::to('clients');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ use App\Ninja\Repositories\InvoiceRepository;
|
|||||||
use App\Ninja\Repositories\PaymentRepository;
|
use App\Ninja\Repositories\PaymentRepository;
|
||||||
use App\Ninja\Repositories\ActivityRepository;
|
use App\Ninja\Repositories\ActivityRepository;
|
||||||
use App\Ninja\Repositories\DocumentRepository;
|
use App\Ninja\Repositories\DocumentRepository;
|
||||||
|
use App\Ninja\Repositories\CreditRepository;
|
||||||
use App\Events\InvoiceInvitationWasViewed;
|
use App\Events\InvoiceInvitationWasViewed;
|
||||||
use App\Events\QuoteInvitationWasViewed;
|
use App\Events\QuoteInvitationWasViewed;
|
||||||
use App\Services\PaymentService;
|
use App\Services\PaymentService;
|
||||||
@ -33,13 +34,14 @@ class ClientPortalController extends BaseController
|
|||||||
private $paymentRepo;
|
private $paymentRepo;
|
||||||
private $documentRepo;
|
private $documentRepo;
|
||||||
|
|
||||||
public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo, ActivityRepository $activityRepo, DocumentRepository $documentRepo, PaymentService $paymentService)
|
public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo, ActivityRepository $activityRepo, DocumentRepository $documentRepo, PaymentService $paymentService, CreditRepository $creditRepo)
|
||||||
{
|
{
|
||||||
$this->invoiceRepo = $invoiceRepo;
|
$this->invoiceRepo = $invoiceRepo;
|
||||||
$this->paymentRepo = $paymentRepo;
|
$this->paymentRepo = $paymentRepo;
|
||||||
$this->activityRepo = $activityRepo;
|
$this->activityRepo = $activityRepo;
|
||||||
$this->documentRepo = $documentRepo;
|
$this->documentRepo = $documentRepo;
|
||||||
$this->paymentService = $paymentService;
|
$this->paymentService = $paymentService;
|
||||||
|
$this->creditRepo = $creditRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function view($invitationKey)
|
public function view($invitationKey)
|
||||||
@ -102,7 +104,9 @@ class ClientPortalController extends BaseController
|
|||||||
$paymentURL = '';
|
$paymentURL = '';
|
||||||
if (count($paymentTypes) == 1) {
|
if (count($paymentTypes) == 1) {
|
||||||
$paymentURL = $paymentTypes[0]['url'];
|
$paymentURL = $paymentTypes[0]['url'];
|
||||||
if (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) {
|
if ($paymentTypes[0]['gatewayTypeId'] == GATEWAY_TYPE_CUSTOM) {
|
||||||
|
// do nothing
|
||||||
|
} elseif (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) {
|
||||||
$paymentURL = URL::to($paymentURL);
|
$paymentURL = URL::to($paymentURL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,7 +145,12 @@ class ClientPortalController extends BaseController
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($accountGateway = $account->getGatewayByType(GATEWAY_TYPE_CUSTOM)) {
|
||||||
|
$data += [
|
||||||
|
'customGatewayName' => $accountGateway->getConfigField('name'),
|
||||||
|
'customGatewayText' => $accountGateway->getConfigField('text'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
if($account->hasFeature(FEATURE_DOCUMENTS) && $this->canCreateZip()){
|
if($account->hasFeature(FEATURE_DOCUMENTS) && $this->canCreateZip()){
|
||||||
$zipDocs = $this->getInvoiceZipDocuments($invoice, $size);
|
$zipDocs = $this->getInvoiceZipDocuments($invoice, $size);
|
||||||
@ -155,18 +164,6 @@ class ClientPortalController extends BaseController
|
|||||||
return View::make('invoices.view', $data);
|
return View::make('invoices.view', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function contactIndex($contactKey) {
|
|
||||||
if (!$contact = Contact::where('contact_key', '=', $contactKey)->first()) {
|
|
||||||
return $this->returnError();
|
|
||||||
}
|
|
||||||
|
|
||||||
$client = $contact->client;
|
|
||||||
|
|
||||||
Session::put('contact_key', $contactKey);// track current contact
|
|
||||||
|
|
||||||
return redirect()->to($client->account->enable_client_portal_dashboard?'/client/dashboard':'/client/invoices/');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getPaymentTypes($account, $client, $invitation)
|
private function getPaymentTypes($account, $client, $invitation)
|
||||||
{
|
{
|
||||||
$links = [];
|
$links = [];
|
||||||
@ -201,19 +198,41 @@ class ClientPortalController extends BaseController
|
|||||||
return $pdfString;
|
return $pdfString;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dashboard()
|
public function sign($invitationKey)
|
||||||
{
|
{
|
||||||
if (!$contact = $this->getContact()) {
|
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
||||||
|
return RESULT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$invitation->signature_base64 = Input::get('signature');
|
||||||
|
$invitation->signature_date = date_create();
|
||||||
|
$invitation->save();
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dashboard($contactKey = false)
|
||||||
|
{
|
||||||
|
if ($contactKey) {
|
||||||
|
if (!$contact = Contact::where('contact_key', '=', $contactKey)->first()) {
|
||||||
|
return $this->returnError();
|
||||||
|
}
|
||||||
|
Session::put('contact_key', $contactKey);// track current contact
|
||||||
|
} else if (!$contact = $this->getContact()) {
|
||||||
return $this->returnError();
|
return $this->returnError();
|
||||||
}
|
}
|
||||||
|
|
||||||
$client = $contact->client;
|
$client = $contact->client;
|
||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
|
$account->loadLocalizationSettings($client);
|
||||||
|
|
||||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
$customer = false;
|
$customer = false;
|
||||||
|
|
||||||
if (!$account->enable_client_portal || !$account->enable_client_portal_dashboard) {
|
if (!$account->enable_client_portal) {
|
||||||
return $this->returnError();
|
return $this->returnError();
|
||||||
|
} elseif (!$account->enable_client_portal_dashboard) {
|
||||||
|
return redirect()->to('/client/invoices/');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN)) {
|
if ($paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN)) {
|
||||||
@ -273,6 +292,7 @@ class ClientPortalController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$account = $contact->account;
|
$account = $contact->account;
|
||||||
|
$account->loadLocalizationSettings($contact->client);
|
||||||
|
|
||||||
if (!$account->enable_client_portal) {
|
if (!$account->enable_client_portal) {
|
||||||
return $this->returnError();
|
return $this->returnError();
|
||||||
@ -300,6 +320,7 @@ class ClientPortalController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$account = $contact->account;
|
$account = $contact->account;
|
||||||
|
$account->loadLocalizationSettings($contact->client);
|
||||||
|
|
||||||
if (!$account->enable_client_portal) {
|
if (!$account->enable_client_portal) {
|
||||||
return $this->returnError();
|
return $this->returnError();
|
||||||
@ -346,12 +367,14 @@ class ClientPortalController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$account = $contact->account;
|
$account = $contact->account;
|
||||||
|
$account->loadLocalizationSettings($contact->client);
|
||||||
|
|
||||||
if (!$account->enable_client_portal) {
|
if (!$account->enable_client_portal) {
|
||||||
return $this->returnError();
|
return $this->returnError();
|
||||||
}
|
}
|
||||||
|
|
||||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'account' => $account,
|
'account' => $account,
|
||||||
@ -416,12 +439,14 @@ class ClientPortalController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$account = $contact->account;
|
$account = $contact->account;
|
||||||
|
$account->loadLocalizationSettings($contact->client);
|
||||||
|
|
||||||
if (!$account->enable_client_portal) {
|
if (!$account->enable_client_portal) {
|
||||||
return $this->returnError();
|
return $this->returnError();
|
||||||
}
|
}
|
||||||
|
|
||||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'account' => $account,
|
'account' => $account,
|
||||||
@ -444,6 +469,42 @@ class ClientPortalController extends BaseController
|
|||||||
return $this->invoiceRepo->getClientDatatable($contact->id, ENTITY_QUOTE, Input::get('sSearch'));
|
return $this->invoiceRepo->getClientDatatable($contact->id, ENTITY_QUOTE, Input::get('sSearch'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function creditIndex()
|
||||||
|
{
|
||||||
|
if (!$contact = $this->getContact()) {
|
||||||
|
return $this->returnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
$account = $contact->account;
|
||||||
|
$account->loadLocalizationSettings($contact->client);
|
||||||
|
|
||||||
|
if (!$account->enable_client_portal) {
|
||||||
|
return $this->returnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'color' => $color,
|
||||||
|
'account' => $account,
|
||||||
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
|
'title' => trans('texts.credits'),
|
||||||
|
'entityType' => ENTITY_CREDIT,
|
||||||
|
'columns' => Utils::trans(['credit_date', 'credit_amount', 'credit_balance']),
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->view('public_list', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function creditDatatable()
|
||||||
|
{
|
||||||
|
if (!$contact = $this->getContact()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->creditRepo->getClientDatatable($contact->client_id);
|
||||||
|
}
|
||||||
|
|
||||||
public function documentIndex()
|
public function documentIndex()
|
||||||
{
|
{
|
||||||
if (!$contact = $this->getContact()) {
|
if (!$contact = $this->getContact()) {
|
||||||
@ -451,12 +512,14 @@ class ClientPortalController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$account = $contact->account;
|
$account = $contact->account;
|
||||||
|
$account->loadLocalizationSettings($contact->client);
|
||||||
|
|
||||||
if (!$account->enable_client_portal) {
|
if (!$account->enable_client_portal) {
|
||||||
return $this->returnError();
|
return $this->returnError();
|
||||||
}
|
}
|
||||||
|
|
||||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'account' => $account,
|
'account' => $account,
|
||||||
|
@ -23,8 +23,8 @@ class DashboardApiController extends BaseAPIController
|
|||||||
|
|
||||||
$dashboardRepo = $this->dashboardRepo;
|
$dashboardRepo = $this->dashboardRepo;
|
||||||
$metrics = $dashboardRepo->totals($accountId, $userId, $viewAll);
|
$metrics = $dashboardRepo->totals($accountId, $userId, $viewAll);
|
||||||
$paidToDate = $dashboardRepo->paidToDate($accountId, $userId, $viewAll);
|
$paidToDate = $dashboardRepo->paidToDate($user->account, $userId, $viewAll);
|
||||||
$averageInvoice = $dashboardRepo->averages($accountId, $userId, $viewAll);
|
$averageInvoice = $dashboardRepo->averages($user->account, $userId, $viewAll);
|
||||||
$balances = $dashboardRepo->balances($accountId, $userId, $viewAll);
|
$balances = $dashboardRepo->balances($accountId, $userId, $viewAll);
|
||||||
$activities = $dashboardRepo->activities($accountId, $userId, $viewAll);
|
$activities = $dashboardRepo->activities($accountId, $userId, $viewAll);
|
||||||
$pastDue = $dashboardRepo->pastDue($accountId, $userId, $viewAll);
|
$pastDue = $dashboardRepo->pastDue($accountId, $userId, $viewAll);
|
||||||
|
@ -33,8 +33,8 @@ class DashboardController extends BaseController
|
|||||||
|
|
||||||
$dashboardRepo = $this->dashboardRepo;
|
$dashboardRepo = $this->dashboardRepo;
|
||||||
$metrics = $dashboardRepo->totals($accountId, $userId, $viewAll);
|
$metrics = $dashboardRepo->totals($accountId, $userId, $viewAll);
|
||||||
$paidToDate = $dashboardRepo->paidToDate($accountId, $userId, $viewAll);
|
$paidToDate = $dashboardRepo->paidToDate($account, $userId, $viewAll);
|
||||||
$averageInvoice = $dashboardRepo->averages($accountId, $userId, $viewAll);
|
$averageInvoice = $dashboardRepo->averages($account, $userId, $viewAll);
|
||||||
$balances = $dashboardRepo->balances($accountId, $userId, $viewAll);
|
$balances = $dashboardRepo->balances($accountId, $userId, $viewAll);
|
||||||
$activities = $dashboardRepo->activities($accountId, $userId, $viewAll);
|
$activities = $dashboardRepo->activities($accountId, $userId, $viewAll);
|
||||||
$pastDue = $dashboardRepo->pastDue($accountId, $userId, $viewAll);
|
$pastDue = $dashboardRepo->pastDue($accountId, $userId, $viewAll);
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
<?php namespace App\Http\Controllers;
|
<?php namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
|
||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
use App\Ninja\Repositories\ExpenseRepository;
|
use App\Ninja\Repositories\ExpenseRepository;
|
||||||
use App\Services\ExpenseService;
|
use App\Services\ExpenseService;
|
||||||
|
use App\Http\Requests\ExpenseRequest;
|
||||||
|
use App\Http\Requests\CreateExpenseRequest;
|
||||||
|
use App\Http\Requests\UpdateExpenseRequest;
|
||||||
|
|
||||||
class ExpenseApiController extends BaseAPIController
|
class ExpenseApiController extends BaseAPIController
|
||||||
{
|
{
|
||||||
@ -20,6 +24,22 @@ class ExpenseApiController extends BaseAPIController
|
|||||||
$this->expenseService = $expenseService;
|
$this->expenseService = $expenseService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/expenses",
|
||||||
|
* summary="List of expenses",
|
||||||
|
* tags={"expense"},
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A list with expenses",
|
||||||
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Expense"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$expenses = Expense::scope()
|
$expenses = Expense::scope()
|
||||||
@ -30,23 +50,103 @@ class ExpenseApiController extends BaseAPIController
|
|||||||
return $this->listResponse($expenses);
|
return $this->listResponse($expenses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update()
|
/**
|
||||||
|
* @SWG\Post(
|
||||||
|
* path="/expenses",
|
||||||
|
* tags={"expense"},
|
||||||
|
* summary="Create a expense",
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="body",
|
||||||
|
* name="body",
|
||||||
|
* @SWG\Schema(ref="#/definitions/Expense")
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="New expense",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Expense"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function store(CreateExpenseRequest $request)
|
||||||
{
|
{
|
||||||
//stub
|
$expense = $this->expenseRepo->save($request->input());
|
||||||
|
|
||||||
|
$expense = Expense::scope($expense->public_id)
|
||||||
|
->with('client', 'invoice', 'vendor')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return $this->itemResponse($expense);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store()
|
/**
|
||||||
|
* @SWG\Put(
|
||||||
|
* path="/expenses/{expense_id}",
|
||||||
|
* tags={"expense"},
|
||||||
|
* summary="Update a expense",
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="body",
|
||||||
|
* name="body",
|
||||||
|
* @SWG\Schema(ref="#/definitions/Expense")
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Update expense",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Expense"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function update(UpdateExpenseRequest $request, $publicId)
|
||||||
{
|
{
|
||||||
//stub
|
if ($request->action) {
|
||||||
|
return $this->handleAction($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $request->input();
|
||||||
|
$data['public_id'] = $publicId;
|
||||||
|
$expense = $this->expenseRepo->save($data, $request->entity());
|
||||||
|
|
||||||
|
return $this->itemResponse($expense);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy()
|
/**
|
||||||
|
* @SWG\Delete(
|
||||||
|
* path="/expenses/{expense_id}",
|
||||||
|
* tags={"expense"},
|
||||||
|
* summary="Delete a expense",
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="body",
|
||||||
|
* name="body",
|
||||||
|
* @SWG\Schema(ref="#/definitions/Expense")
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Delete expense",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Expense"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function destroy(ExpenseRequest $request)
|
||||||
{
|
{
|
||||||
//stub
|
$expense = $request->entity();
|
||||||
|
|
||||||
|
$this->expenseRepo->delete($expense);
|
||||||
|
|
||||||
|
return $this->itemResponse($expense);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
41
app/Http/Controllers/ExpenseCategoryApiController.php
Normal file
41
app/Http/Controllers/ExpenseCategoryApiController.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use View;
|
||||||
|
use Utils;
|
||||||
|
use Input;
|
||||||
|
use Session;
|
||||||
|
use App\Services\ExpenseCategoryService;
|
||||||
|
use App\Http\Requests\CreateExpenseCategoryRequest;
|
||||||
|
use App\Http\Requests\UpdateExpenseCategoryRequest;
|
||||||
|
use App\Ninja\Repositories\ExpenseCategoryRepository;
|
||||||
|
|
||||||
|
|
||||||
|
class ExpenseCategoryApiController extends BaseAPIController
|
||||||
|
{
|
||||||
|
protected $categoryRepo;
|
||||||
|
protected $categoryService;
|
||||||
|
protected $entityType = ENTITY_EXPENSE_CATEGORY;
|
||||||
|
|
||||||
|
public function __construct(ExpenseCategoryRepository $categoryRepo, ExpenseCategoryService $categoryService)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->categoryRepo = $categoryRepo;
|
||||||
|
$this->categoryService = $categoryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(UpdateExpenseCategoryRequest $request)
|
||||||
|
{
|
||||||
|
$category = $this->categoryRepo->save($request->input(), $request->entity());
|
||||||
|
|
||||||
|
return $this->itemResponse($category);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CreateExpenseCategoryRequest $request)
|
||||||
|
{
|
||||||
|
$category = $this->categoryRepo->save($request->input());
|
||||||
|
|
||||||
|
return $this->itemResponse($category);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -134,6 +134,7 @@ class ExpenseController extends BaseController
|
|||||||
$data = [
|
$data = [
|
||||||
'vendor' => null,
|
'vendor' => null,
|
||||||
'expense' => $expense,
|
'expense' => $expense,
|
||||||
|
'entity' => $expense,
|
||||||
'method' => 'PUT',
|
'method' => 'PUT',
|
||||||
'url' => 'expenses/'.$expense->public_id,
|
'url' => 'expenses/'.$expense->public_id,
|
||||||
'title' => 'Edit Expense',
|
'title' => 'Edit Expense',
|
||||||
@ -245,7 +246,7 @@ class ExpenseController extends BaseController
|
|||||||
Session::flash('message', $message);
|
Session::flash('message', $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Redirect::to('expenses');
|
return $this->returnBulk($this->entityType, $action, $ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function getViewModel()
|
private static function getViewModel()
|
||||||
|
@ -76,10 +76,8 @@ class HomeController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Track the referral/campaign code
|
// Track the referral/campaign code
|
||||||
foreach (['rc', 'utm_campaign'] as $code) {
|
if (Input::has('rc')) {
|
||||||
if (Input::has($code)) {
|
Session::set(SESSION_REFERRAL_CODE, Input::get('rc'));
|
||||||
Session::set(SESSION_REFERRAL_CODE, Input::get($code));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Auth::check()) {
|
if (Auth::check()) {
|
||||||
|
@ -31,6 +31,11 @@ class ImportController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! count($files)) {
|
||||||
|
Session::flash('error', trans('texts.select_file'));
|
||||||
|
return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($source === IMPORT_CSV) {
|
if ($source === IMPORT_CSV) {
|
||||||
$data = $this->importService->mapCSV($files);
|
$data = $this->importService->mapCSV($files);
|
||||||
|
@ -176,7 +176,7 @@ class InvoiceApiController extends BaseAPIController
|
|||||||
if (isset($data['email_invoice']) && $data['email_invoice']) {
|
if (isset($data['email_invoice']) && $data['email_invoice']) {
|
||||||
if ($payment) {
|
if ($payment) {
|
||||||
$this->mailer->sendPaymentConfirmation($payment);
|
$this->mailer->sendPaymentConfirmation($payment);
|
||||||
} else {
|
} elseif ( ! $invoice->is_recurring) {
|
||||||
$this->mailer->sendInvoice($invoice);
|
$this->mailer->sendInvoice($invoice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +218,7 @@ class InvoiceController extends BaseController
|
|||||||
$contact->invitation_viewed = $invitation->viewed_date && $invitation->viewed_date != '0000-00-00 00:00:00' ? $invitation->viewed_date : false;
|
$contact->invitation_viewed = $invitation->viewed_date && $invitation->viewed_date != '0000-00-00 00:00:00' ? $invitation->viewed_date : false;
|
||||||
$contact->invitation_openend = $invitation->opened_date && $invitation->opened_date != '0000-00-00 00:00:00' ? $invitation->opened_date : false;
|
$contact->invitation_openend = $invitation->opened_date && $invitation->opened_date != '0000-00-00 00:00:00' ? $invitation->opened_date : false;
|
||||||
$contact->invitation_status = $contact->email_error ? false : $invitation->getStatus();
|
$contact->invitation_status = $contact->email_error ? false : $invitation->getStatus();
|
||||||
|
$contact->invitation_signature_svg = $invitation->signatureDiv();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,6 +270,9 @@ class InvoiceController extends BaseController
|
|||||||
private static function getViewModel($invoice)
|
private static function getViewModel($invoice)
|
||||||
{
|
{
|
||||||
$recurringHelp = '';
|
$recurringHelp = '';
|
||||||
|
$recurringDueDateHelp = '';
|
||||||
|
$recurringDueDates = [];
|
||||||
|
|
||||||
foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_help')) as $line) {
|
foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_help')) as $line) {
|
||||||
$parts = explode('=>', $line);
|
$parts = explode('=>', $line);
|
||||||
if (count($parts) > 1) {
|
if (count($parts) > 1) {
|
||||||
@ -279,7 +283,6 @@ class InvoiceController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$recurringDueDateHelp = '';
|
|
||||||
foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_due_date_help')) as $line) {
|
foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_due_date_help')) as $line) {
|
||||||
$parts = explode('=>', $line);
|
$parts = explode('=>', $line);
|
||||||
if (count($parts) > 1) {
|
if (count($parts) > 1) {
|
||||||
@ -409,10 +412,10 @@ class InvoiceController extends BaseController
|
|||||||
Session::flash('message', $message);
|
Session::flash('message', $message);
|
||||||
|
|
||||||
if ($action == 'email') {
|
if ($action == 'email') {
|
||||||
return $this->emailInvoice($invoice, Input::get('pdfupload'));
|
$this->emailInvoice($invoice, Input::get('pdfupload'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->to($invoice->getRoute());
|
return url($invoice->getRoute());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -435,14 +438,14 @@ class InvoiceController extends BaseController
|
|||||||
Session::flash('message', $message);
|
Session::flash('message', $message);
|
||||||
|
|
||||||
if ($action == 'clone') {
|
if ($action == 'clone') {
|
||||||
return $this->cloneInvoice($request, $invoice->public_id);
|
return url(sprintf('%ss/%s/clone', $entityType, $invoice->public_id));
|
||||||
} elseif ($action == 'convert') {
|
} elseif ($action == 'convert') {
|
||||||
return $this->convertQuote($request, $invoice->public_id);
|
return $this->convertQuote($request, $invoice->public_id);
|
||||||
} elseif ($action == 'email') {
|
} elseif ($action == 'email') {
|
||||||
return $this->emailInvoice($invoice, Input::get('pdfupload'));
|
$this->emailInvoice($invoice, Input::get('pdfupload'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->to($invoice->getRoute());
|
return url($invoice->getRoute());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -469,8 +472,6 @@ class InvoiceController extends BaseController
|
|||||||
} else {
|
} else {
|
||||||
Session::flash('error', $response);
|
Session::flash('error', $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Redirect::to("{$entityType}s/{$invoice->public_id}/edit");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function emailRecurringInvoice(&$invoice)
|
private function emailRecurringInvoice(&$invoice)
|
||||||
@ -527,11 +528,7 @@ class InvoiceController extends BaseController
|
|||||||
Session::flash('message', $message);
|
Session::flash('message', $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($action == 'restore' && $count == 1) {
|
return $this->returnBulk($entityType, $action, $ids);
|
||||||
return Redirect::to("{$entityType}s/".Utils::getFirst($ids));
|
|
||||||
} else {
|
|
||||||
return Redirect::to("{$entityType}s");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function convertQuote(InvoiceRequest $request)
|
public function convertQuote(InvoiceRequest $request)
|
||||||
@ -540,7 +537,7 @@ class InvoiceController extends BaseController
|
|||||||
|
|
||||||
Session::flash('message', trans('texts.converted_to_invoice'));
|
Session::flash('message', trans('texts.converted_to_invoice'));
|
||||||
|
|
||||||
return Redirect::to('invoices/' . $clone->public_id);
|
return url('invoices/' . $clone->public_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function cloneInvoice(InvoiceRequest $request, $publicId)
|
public function cloneInvoice(InvoiceRequest $request, $publicId)
|
||||||
@ -608,12 +605,19 @@ class InvoiceController extends BaseController
|
|||||||
return View::make('invoices.history', $data);
|
return View::make('invoices.history', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkInvoiceNumber($invoiceNumber)
|
public function checkInvoiceNumber($invoicePublicId = false)
|
||||||
{
|
{
|
||||||
$count = Invoice::scope()
|
$invoiceNumber = request()->invoice_number;
|
||||||
|
|
||||||
|
$query = Invoice::scope()
|
||||||
->whereInvoiceNumber($invoiceNumber)
|
->whereInvoiceNumber($invoiceNumber)
|
||||||
->withTrashed()
|
->withTrashed();
|
||||||
->count();
|
|
||||||
|
if ($invoicePublicId) {
|
||||||
|
$query->where('public_id', '!=', $invoicePublicId);
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = $query->count();
|
||||||
|
|
||||||
return $count ? RESULT_FAILURE : RESULT_SUCCESS;
|
return $count ? RESULT_FAILURE : RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ use App\Http\Requests\CreateOnlinePaymentRequest;
|
|||||||
use App\Ninja\Repositories\ClientRepository;
|
use App\Ninja\Repositories\ClientRepository;
|
||||||
use App\Ninja\Repositories\InvoiceRepository;
|
use App\Ninja\Repositories\InvoiceRepository;
|
||||||
use App\Services\InvoiceService;
|
use App\Services\InvoiceService;
|
||||||
|
use App\Models\GatewayType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class OnlinePaymentController
|
* Class OnlinePaymentController
|
||||||
@ -60,7 +61,7 @@ class OnlinePaymentController extends BaseController
|
|||||||
* @param bool $sourceId
|
* @param bool $sourceId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function showPayment($invitationKey, $gatewayType = false, $sourceId = false)
|
public function showPayment($invitationKey, $gatewayTypeAlias = false, $sourceId = false)
|
||||||
{
|
{
|
||||||
if ( ! $invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
if ( ! $invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
||||||
return response()->view('error', [
|
return response()->view('error', [
|
||||||
@ -69,17 +70,23 @@ class OnlinePaymentController extends BaseController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! floatval($invitation->invoice->balance)) {
|
if ( ! $invitation->invoice->canBePaid()) {
|
||||||
return redirect()->to('view/' . $invitation->invitation_key);
|
return redirect()->to('view/' . $invitation->invitation_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
$invitation = $invitation->load('invoice.client.account.account_gateways.gateway');
|
$invitation = $invitation->load('invoice.client.account.account_gateways.gateway');
|
||||||
|
$account = $invitation->account;
|
||||||
|
$account->loadLocalizationSettings($invitation->invoice->client);
|
||||||
|
|
||||||
if ( ! $gatewayType) {
|
if ( ! $gatewayTypeAlias) {
|
||||||
$gatewayType = Session::get($invitation->id . 'gateway_type');
|
$gatewayTypeId = Session::get($invitation->id . 'gateway_type');
|
||||||
|
} elseif ($gatewayTypeAlias != GATEWAY_TYPE_TOKEN) {
|
||||||
|
$gatewayTypeId = GatewayType::getIdFromAlias($gatewayTypeAlias);
|
||||||
|
} else {
|
||||||
|
$gatewayTypeId = $gatewayTypeAlias;
|
||||||
}
|
}
|
||||||
|
|
||||||
$paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayType);
|
$paymentDriver = $account->paymentDriver($invitation, $gatewayTypeId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return $paymentDriver->startPurchase(Input::all(), $sourceId);
|
return $paymentDriver->startPurchase(Input::all(), $sourceId);
|
||||||
@ -95,8 +102,12 @@ class OnlinePaymentController extends BaseController
|
|||||||
public function doPayment(CreateOnlinePaymentRequest $request)
|
public function doPayment(CreateOnlinePaymentRequest $request)
|
||||||
{
|
{
|
||||||
$invitation = $request->invitation;
|
$invitation = $request->invitation;
|
||||||
$gatewayType = Session::get($invitation->id . 'gateway_type');
|
$gatewayTypeId = Session::get($invitation->id . 'gateway_type');
|
||||||
$paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayType);
|
$paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayTypeId);
|
||||||
|
|
||||||
|
if ( ! $invitation->invoice->canBePaid()) {
|
||||||
|
return redirect()->to('view/' . $invitation->invitation_key);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$paymentDriver->completeOnsitePurchase($request->all());
|
$paymentDriver->completeOnsitePurchase($request->all());
|
||||||
@ -114,17 +125,24 @@ class OnlinePaymentController extends BaseController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $invitationKey
|
* @param bool $invitationKey
|
||||||
* @param bool $gatewayType
|
* @param mixed $gatewayTypeAlias
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function offsitePayment($invitationKey = false, $gatewayType = false)
|
public function offsitePayment($invitationKey = false, $gatewayTypeAlias = false)
|
||||||
{
|
{
|
||||||
$invitationKey = $invitationKey ?: Session::get('invitation_key');
|
$invitationKey = $invitationKey ?: Session::get('invitation_key');
|
||||||
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway')
|
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway')
|
||||||
->where('invitation_key', '=', $invitationKey)->firstOrFail();
|
->where('invitation_key', '=', $invitationKey)->firstOrFail();
|
||||||
|
|
||||||
$gatewayType = $gatewayType ?: Session::get($invitation->id . 'gateway_type');
|
if ( ! $gatewayTypeAlias) {
|
||||||
$paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayType);
|
$gatewayTypeId = Session::get($invitation->id . 'gateway_type');
|
||||||
|
} elseif ($gatewayTypeAlias != GATEWAY_TYPE_TOKEN) {
|
||||||
|
$gatewayTypeId = GatewayType::getIdFromAlias($gatewayTypeAlias);
|
||||||
|
} else {
|
||||||
|
$gatewayTypeId = $gatewayTypeAlias;
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayTypeId);
|
||||||
|
|
||||||
if ($error = Input::get('error_description') ?: Input::get('error')) {
|
if ($error = Input::get('error_description') ?: Input::get('error')) {
|
||||||
return $this->error($paymentDriver, $error);
|
return $this->error($paymentDriver, $error);
|
||||||
@ -228,7 +246,7 @@ class OnlinePaymentController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleBuyNow(ClientRepository $clientRepo, InvoiceService $invoiceService, $gatewayType = false)
|
public function handleBuyNow(ClientRepository $clientRepo, InvoiceService $invoiceService, $gatewayTypeAlias = false)
|
||||||
{
|
{
|
||||||
if (Crawler::isCrawler()) {
|
if (Crawler::isCrawler()) {
|
||||||
return redirect()->to(NINJA_WEB_URL, 301);
|
return redirect()->to(NINJA_WEB_URL, 301);
|
||||||
@ -267,6 +285,8 @@ class OnlinePaymentController extends BaseController
|
|||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'client_id' => $client->id,
|
'client_id' => $client->id,
|
||||||
|
'tax_rate1' => $account->default_tax_rate ? $account->default_tax_rate->rate : 0,
|
||||||
|
'tax_name1' => $account->default_tax_rate ? $account->default_tax_rate->name : '',
|
||||||
'invoice_items' => [[
|
'invoice_items' => [[
|
||||||
'product_key' => $product->product_key,
|
'product_key' => $product->product_key,
|
||||||
'notes' => $product->notes,
|
'notes' => $product->notes,
|
||||||
@ -280,8 +300,8 @@ class OnlinePaymentController extends BaseController
|
|||||||
$invitation = $invoice->invitations[0];
|
$invitation = $invoice->invitations[0];
|
||||||
$link = $invitation->getLink();
|
$link = $invitation->getLink();
|
||||||
|
|
||||||
if ($gatewayType) {
|
if ($gatewayTypeAlias) {
|
||||||
return redirect()->to($invitation->getLink('payment') . "/{$gatewayType}");
|
return redirect()->to($invitation->getLink('payment') . "/{$gatewayTypeAlias}");
|
||||||
} else {
|
} else {
|
||||||
return redirect()->to($invitation->getLink());
|
return redirect()->to($invitation->getLink());
|
||||||
}
|
}
|
||||||
|
@ -142,11 +142,13 @@ class PaymentController extends BaseController
|
|||||||
'invoices' => Invoice::scope()->invoiceType(INVOICE_TYPE_STANDARD)->where('is_recurring', '=', false)
|
'invoices' => Invoice::scope()->invoiceType(INVOICE_TYPE_STANDARD)->where('is_recurring', '=', false)
|
||||||
->with('client', 'invoice_status')->orderBy('invoice_number')->get(),
|
->with('client', 'invoice_status')->orderBy('invoice_number')->get(),
|
||||||
'payment' => $payment,
|
'payment' => $payment,
|
||||||
|
'entity' => $payment,
|
||||||
'method' => 'PUT',
|
'method' => 'PUT',
|
||||||
'url' => 'payments/'.$payment->public_id,
|
'url' => 'payments/'.$payment->public_id,
|
||||||
'title' => trans('texts.edit_payment'),
|
'title' => trans('texts.edit_payment'),
|
||||||
'paymentTypes' => Cache::get('paymentTypes'),
|
'paymentTypes' => Cache::get('paymentTypes'),
|
||||||
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), ];
|
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
|
||||||
|
];
|
||||||
|
|
||||||
return View::make('payments.edit', $data);
|
return View::make('payments.edit', $data);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use Auth;
|
use Auth;
|
||||||
use URL;
|
use URL;
|
||||||
use View;
|
use View;
|
||||||
|
use Utils;
|
||||||
use Input;
|
use Input;
|
||||||
use Session;
|
use Session;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
@ -37,15 +38,40 @@ class ProductController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return Redirect::to('settings/' . ACCOUNT_PRODUCTS);
|
$columns = [
|
||||||
|
'checkbox',
|
||||||
|
'product',
|
||||||
|
'description',
|
||||||
|
'unit_cost'
|
||||||
|
];
|
||||||
|
|
||||||
|
if (Auth::user()->account->invoice_item_taxes) {
|
||||||
|
$columns[] = 'tax_rate';
|
||||||
|
}
|
||||||
|
$columns[] = 'action';
|
||||||
|
|
||||||
|
return View::make('list', [
|
||||||
|
'entityType' => ENTITY_PRODUCT,
|
||||||
|
'title' => trans('texts.products'),
|
||||||
|
'sortCol' => '4',
|
||||||
|
'columns' => Utils::trans($columns),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function show($publicId)
|
||||||
|
{
|
||||||
|
Session::reflash();
|
||||||
|
|
||||||
|
return Redirect::to("products/$publicId/edit");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function getDatatable()
|
public function getDatatable()
|
||||||
{
|
{
|
||||||
return $this->productService->getDatatable(Auth::user()->account_id);
|
return $this->productService->getDatatable(Auth::user()->account_id, Input::get('sSearch'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,11 +81,13 @@ class ProductController extends BaseController
|
|||||||
public function edit($publicId)
|
public function edit($publicId)
|
||||||
{
|
{
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
|
$product = Product::scope($publicId)->withTrashed()->firstOrFail();
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'account' => $account,
|
'account' => $account,
|
||||||
'taxRates' => $account->invoice_item_taxes ? TaxRate::scope()->get(['id', 'name', 'rate']) : null,
|
'taxRates' => $account->invoice_item_taxes ? TaxRate::scope()->get(['id', 'name', 'rate']) : null,
|
||||||
'product' => Product::scope($publicId)->firstOrFail(),
|
'product' => $product,
|
||||||
|
'entity' => $product,
|
||||||
'method' => 'PUT',
|
'method' => 'PUT',
|
||||||
'url' => 'products/'.$publicId,
|
'url' => 'products/'.$publicId,
|
||||||
'title' => trans('texts.edit_product'),
|
'title' => trans('texts.edit_product'),
|
||||||
@ -111,7 +139,7 @@ class ProductController extends BaseController
|
|||||||
private function save($productPublicId = false)
|
private function save($productPublicId = false)
|
||||||
{
|
{
|
||||||
if ($productPublicId) {
|
if ($productPublicId) {
|
||||||
$product = Product::scope($productPublicId)->firstOrFail();
|
$product = Product::scope($productPublicId)->withTrashed()->firstOrFail();
|
||||||
} else {
|
} else {
|
||||||
$product = Product::createNew();
|
$product = Product::createNew();
|
||||||
}
|
}
|
||||||
@ -134,12 +162,12 @@ class ProductController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function bulk()
|
public function bulk()
|
||||||
{
|
{
|
||||||
$action = Input::get('bulk_action');
|
$action = Input::get('action');
|
||||||
$ids = Input::get('bulk_public_id');
|
$ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids');
|
||||||
$count = $this->productService->bulk($ids, $action);
|
$count = $this->productService->bulk($ids, $action);
|
||||||
|
|
||||||
Session::flash('message', trans('texts.archived_product'));
|
Session::flash('message', trans('texts.archived_product'));
|
||||||
|
|
||||||
return Redirect::to('settings/' . ACCOUNT_PRODUCTS);
|
return $this->returnBulk(ENTITY_PRODUCT, $action, $ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,11 +154,7 @@ class QuoteController extends BaseController
|
|||||||
Session::flash('message', $message);
|
Session::flash('message', $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($action == 'restore' && $count == 1) {
|
return $this->returnBulk(ENTITY_QUOTE, $action, $ids);
|
||||||
return Redirect::to('quotes/'.Utils::getFirst($ids));
|
|
||||||
} else {
|
|
||||||
return Redirect::to('quotes');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function approve($invitationKey)
|
public function approve($invitationKey)
|
||||||
|
@ -11,6 +11,7 @@ use App\Models\Account;
|
|||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
|
use App\Models\Task;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ReportController
|
* Class ReportController
|
||||||
@ -56,8 +57,8 @@ class ReportController extends BaseController
|
|||||||
if (Input::get('report_type')) {
|
if (Input::get('report_type')) {
|
||||||
$reportType = Input::get('report_type');
|
$reportType = Input::get('report_type');
|
||||||
$dateField = Input::get('date_field');
|
$dateField = Input::get('date_field');
|
||||||
$startDate = Utils::toSqlDate(Input::get('start_date'), false);
|
$startDate = date_create(Input::get('start_date'));
|
||||||
$endDate = Utils::toSqlDate(Input::get('end_date'), false);
|
$endDate = date_create(Input::get('end_date'));
|
||||||
} else {
|
} else {
|
||||||
$reportType = ENTITY_INVOICE;
|
$reportType = ENTITY_INVOICE;
|
||||||
$dateField = FILTER_INVOICE_DATE;
|
$dateField = FILTER_INVOICE_DATE;
|
||||||
@ -71,15 +72,17 @@ class ReportController extends BaseController
|
|||||||
ENTITY_PRODUCT => trans('texts.product'),
|
ENTITY_PRODUCT => trans('texts.product'),
|
||||||
ENTITY_PAYMENT => trans('texts.payment'),
|
ENTITY_PAYMENT => trans('texts.payment'),
|
||||||
ENTITY_EXPENSE => trans('texts.expense'),
|
ENTITY_EXPENSE => trans('texts.expense'),
|
||||||
|
ENTITY_TASK => trans('texts.task'),
|
||||||
ENTITY_TAX_RATE => trans('texts.tax'),
|
ENTITY_TAX_RATE => trans('texts.tax'),
|
||||||
];
|
];
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
'startDate' => $startDate->format(Session::get(SESSION_DATE_FORMAT)),
|
'startDate' => $startDate->format('Y-m-d'),
|
||||||
'endDate' => $endDate->format(Session::get(SESSION_DATE_FORMAT)),
|
'endDate' => $endDate->format('Y-m-d'),
|
||||||
'reportTypes' => $reportTypes,
|
'reportTypes' => $reportTypes,
|
||||||
'reportType' => $reportType,
|
'reportType' => $reportType,
|
||||||
'title' => trans('texts.charts_and_reports'),
|
'title' => trans('texts.charts_and_reports'),
|
||||||
|
'account' => Auth::user()->account,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (Auth::user()->account->hasFeature(FEATURE_REPORTS)) {
|
if (Auth::user()->account->hasFeature(FEATURE_REPORTS)) {
|
||||||
@ -120,9 +123,37 @@ class ReportController extends BaseController
|
|||||||
return $this->generateTaxRateReport($startDate, $endDate, $dateField, $isExport);
|
return $this->generateTaxRateReport($startDate, $endDate, $dateField, $isExport);
|
||||||
} elseif ($reportType == ENTITY_EXPENSE) {
|
} elseif ($reportType == ENTITY_EXPENSE) {
|
||||||
return $this->generateExpenseReport($startDate, $endDate, $isExport);
|
return $this->generateExpenseReport($startDate, $endDate, $isExport);
|
||||||
|
} elseif ($reportType == ENTITY_TASK) {
|
||||||
|
return $this->generateTaskReport($startDate, $endDate, $isExport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function generateTaskReport($startDate, $endDate, $isExport)
|
||||||
|
{
|
||||||
|
$columns = ['client', 'date', 'description', 'duration'];
|
||||||
|
$displayData = [];
|
||||||
|
|
||||||
|
$tasks = Task::scope()
|
||||||
|
->with('client.contacts')
|
||||||
|
->withArchived()
|
||||||
|
->dateRange($startDate, $endDate);
|
||||||
|
|
||||||
|
foreach ($tasks->get() as $task) {
|
||||||
|
$displayData[] = [
|
||||||
|
$task->client ? ($isExport ? $task->client->getDisplayName() : $task->client->present()->link) : trans('texts.unassigned'),
|
||||||
|
link_to($task->present()->url, $task->getStartTime()),
|
||||||
|
$task->present()->description,
|
||||||
|
Utils::formatTime($task->getDuration()),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'columns' => $columns,
|
||||||
|
'displayData' => $displayData,
|
||||||
|
'reportTotals' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $startDate
|
* @param $startDate
|
||||||
* @param $endDate
|
* @param $endDate
|
||||||
@ -354,7 +385,7 @@ class ReportController extends BaseController
|
|||||||
$isExport ? $client->getDisplayName() : $client->present()->link,
|
$isExport ? $client->getDisplayName() : $client->present()->link,
|
||||||
$isExport ? $invoice->invoice_number : $invoice->present()->link,
|
$isExport ? $invoice->invoice_number : $invoice->present()->link,
|
||||||
$invoice->present()->invoice_date,
|
$invoice->present()->invoice_date,
|
||||||
$invoiceItem->qty,
|
round($invoiceItem->qty, 2),
|
||||||
$invoiceItem->product_key,
|
$invoiceItem->product_key,
|
||||||
];
|
];
|
||||||
//$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'paid', $payment ? $payment->amount : 0);
|
//$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'paid', $payment ? $payment->amount : 0);
|
||||||
@ -433,36 +464,31 @@ class ReportController extends BaseController
|
|||||||
*/
|
*/
|
||||||
private function generateExpenseReport($startDate, $endDate, $isExport)
|
private function generateExpenseReport($startDate, $endDate, $isExport)
|
||||||
{
|
{
|
||||||
$columns = ['vendor', 'client', 'date', 'expense_amount', 'invoiced_amount'];
|
$columns = ['vendor', 'client', 'date', 'expense_amount'];
|
||||||
|
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$displayData = [];
|
$displayData = [];
|
||||||
$reportTotals = [];
|
$reportTotals = [];
|
||||||
|
|
||||||
$expenses = Expense::scope()
|
$expenses = Expense::scope()
|
||||||
->withTrashed()
|
->withArchived()
|
||||||
->with('client.contacts', 'vendor')
|
->with('client.contacts', 'vendor')
|
||||||
->where('expense_date', '>=', $startDate)
|
->where('expense_date', '>=', $startDate)
|
||||||
->where('expense_date', '<=', $endDate);
|
->where('expense_date', '<=', $endDate);
|
||||||
|
|
||||||
|
|
||||||
foreach ($expenses->get() as $expense) {
|
foreach ($expenses->get() as $expense) {
|
||||||
$amount = $expense->amount;
|
$amount = $expense->amountWithTax();
|
||||||
$invoiced = $expense->present()->invoiced_amount;
|
|
||||||
|
|
||||||
$displayData[] = [
|
$displayData[] = [
|
||||||
$expense->vendor ? ($isExport ? $expense->vendor->name : $expense->vendor->present()->link) : '',
|
$expense->vendor ? ($isExport ? $expense->vendor->name : $expense->vendor->present()->link) : '',
|
||||||
$expense->client ? ($isExport ? $expense->client->getDisplayName() : $expense->client->present()->link) : '',
|
$expense->client ? ($isExport ? $expense->client->getDisplayName() : $expense->client->present()->link) : '',
|
||||||
$expense->present()->expense_date,
|
$expense->present()->expense_date,
|
||||||
Utils::formatMoney($amount, $expense->currency_id),
|
Utils::formatMoney($amount, $expense->currency_id),
|
||||||
Utils::formatMoney($invoiced, $expense->invoice_currency_id),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$reportTotals = $this->addToTotals($reportTotals, $expense->expense_currency_id, 'amount', $amount);
|
$reportTotals = $this->addToTotals($reportTotals, $expense->expense_currency_id, 'amount', $amount);
|
||||||
$reportTotals = $this->addToTotals($reportTotals, $expense->invoice_currency_id, 'amount', 0);
|
$reportTotals = $this->addToTotals($reportTotals, $expense->invoice_currency_id, 'amount', 0);
|
||||||
|
|
||||||
$reportTotals = $this->addToTotals($reportTotals, $expense->invoice_currency_id, 'invoiced', $invoiced);
|
|
||||||
$reportTotals = $this->addToTotals($reportTotals, $expense->expense_currency_id, 'invoiced', 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Codedge\Updater\UpdaterManager;
|
use Utils;
|
||||||
|
|
||||||
use App\Http\Requests;
|
|
||||||
use Redirect;
|
use Redirect;
|
||||||
|
use Codedge\Updater\UpdaterManager;
|
||||||
|
|
||||||
class SelfUpdateController extends BaseController
|
class SelfUpdateController extends BaseController
|
||||||
{
|
{
|
||||||
@ -21,6 +20,10 @@ class SelfUpdateController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function __construct(UpdaterManager $updater)
|
public function __construct(UpdaterManager $updater)
|
||||||
{
|
{
|
||||||
|
if (Utils::isNinjaProd()) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$this->updater = $updater;
|
$this->updater = $updater;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,15 +177,14 @@ class TaskController extends BaseController
|
|||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
|
'entity' => $task,
|
||||||
'clientPublicId' => $task->client ? $task->client->public_id : 0,
|
'clientPublicId' => $task->client ? $task->client->public_id : 0,
|
||||||
'method' => 'PUT',
|
'method' => 'PUT',
|
||||||
'url' => 'tasks/'.$task->public_id,
|
'url' => 'tasks/'.$task->public_id,
|
||||||
'title' => trans('texts.edit_task'),
|
'title' => trans('texts.edit_task'),
|
||||||
'duration' => $task->is_running ? $task->getCurrentDuration() : $task->getDuration(),
|
|
||||||
'actions' => $actions,
|
'actions' => $actions,
|
||||||
'timezone' => Auth::user()->account->timezone ? Auth::user()->account->timezone->name : DEFAULT_TIMEZONE,
|
'timezone' => Auth::user()->account->timezone ? Auth::user()->account->timezone->name : DEFAULT_TIMEZONE,
|
||||||
'datetimeFormat' => Auth::user()->account->getMomentDateTimeFormat(),
|
'datetimeFormat' => Auth::user()->account->getMomentDateTimeFormat(),
|
||||||
//'entityStatus' => $task->present()->status,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$data = array_merge($data, self::getViewModel());
|
$data = array_merge($data, self::getViewModel());
|
||||||
@ -295,16 +294,12 @@ class TaskController extends BaseController
|
|||||||
return Redirect::to("invoices/{$invoiceId}/edit")->with('tasks', $data);
|
return Redirect::to("invoices/{$invoiceId}/edit")->with('tasks', $data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$count = $this->taskRepo->bulk($ids, $action);
|
$count = $this->taskService->bulk($ids, $action);
|
||||||
|
|
||||||
$message = Utils::pluralize($action.'d_task', $count);
|
$message = Utils::pluralize($action.'d_task', $count);
|
||||||
Session::flash('message', $message);
|
Session::flash('message', $message);
|
||||||
|
|
||||||
if ($action == 'restore' && $count == 1) {
|
return $this->returnBulk($this->entityType, $action, $ids);
|
||||||
return Redirect::to('tasks/'.$ids[0].'/edit');
|
|
||||||
} else {
|
|
||||||
return Redirect::to('tasks');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,9 @@ class UserController extends BaseController
|
|||||||
public function edit($publicId)
|
public function edit($publicId)
|
||||||
{
|
{
|
||||||
$user = User::where('account_id', '=', Auth::user()->account_id)
|
$user = User::where('account_id', '=', Auth::user()->account_id)
|
||||||
->where('public_id', '=', $publicId)->firstOrFail();
|
->where('public_id', '=', $publicId)
|
||||||
|
->withTrashed()
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'user' => $user,
|
'user' => $user,
|
||||||
@ -157,7 +159,9 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
if ($userPublicId) {
|
if ($userPublicId) {
|
||||||
$user = User::where('account_id', '=', Auth::user()->account_id)
|
$user = User::where('account_id', '=', Auth::user()->account_id)
|
||||||
->where('public_id', '=', $userPublicId)->firstOrFail();
|
->where('public_id', '=', $userPublicId)
|
||||||
|
->withTrashed()
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
$rules['email'] = 'required|email|unique:users,email,'.$user->id.',id';
|
$rules['email'] = 'required|email|unique:users,email,'.$user->id.',id';
|
||||||
} else {
|
} else {
|
||||||
@ -334,7 +338,13 @@ class UserController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Redirect::to($referer);
|
// If the user is looking at an entity redirect to the dashboard
|
||||||
|
preg_match('/\/[0-9*][\/edit]*$/', $referer, $matches);
|
||||||
|
if (count($matches)) {
|
||||||
|
return Redirect::to('/dashboard');
|
||||||
|
} else {
|
||||||
|
return Redirect::to($referer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function unlinkAccount($userAccountId, $userId)
|
public function unlinkAccount($userAccountId, $userId)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php namespace App\Http\Controllers;
|
<?php namespace App\Http\Controllers;
|
||||||
// vendor
|
// vendor
|
||||||
|
use App\Http\Requests\UpdateVendorRequest;
|
||||||
|
use App\Http\Requests\VendorRequest;
|
||||||
use Utils;
|
use Utils;
|
||||||
use Response;
|
use Response;
|
||||||
use Input;
|
use Input;
|
||||||
@ -83,4 +85,73 @@ class VendorApiController extends BaseAPIController
|
|||||||
|
|
||||||
return $this->itemResponse($vendor);
|
return $this->itemResponse($vendor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Put(
|
||||||
|
* path="/vendors/{vendor_id}",
|
||||||
|
* tags={"vendor"},
|
||||||
|
* summary="Update a vendor",
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="body",
|
||||||
|
* name="body",
|
||||||
|
* @SWG\Schema(ref="#/definitions/Vendor")
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Update vendor",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Vendor"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function update(UpdateVendorRequest $request, $publicId)
|
||||||
|
{
|
||||||
|
if ($request->action) {
|
||||||
|
return $this->handleAction($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $request->input();
|
||||||
|
$data['public_id'] = $publicId;
|
||||||
|
$vendor = $this->vendorRepo->save($data, $request->entity());
|
||||||
|
|
||||||
|
$vendor->load(['vendor_contacts']);
|
||||||
|
|
||||||
|
return $this->itemResponse($vendor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Delete(
|
||||||
|
* path="/vendors/{vendor_id}",
|
||||||
|
* tags={"vendor"},
|
||||||
|
* summary="Delete a vendor",
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="body",
|
||||||
|
* name="body",
|
||||||
|
* @SWG\Schema(ref="#/definitions/Vendor")
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Delete vendor",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Vendor"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function destroy(VendorRequest $request)
|
||||||
|
{
|
||||||
|
$vendor = $request->entity();
|
||||||
|
|
||||||
|
$this->vendorRepo->delete($vendor);
|
||||||
|
|
||||||
|
return $this->itemResponse($vendor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,10 +185,6 @@ class VendorController extends BaseController
|
|||||||
$message = Utils::pluralize($action.'d_vendor', $count);
|
$message = Utils::pluralize($action.'d_vendor', $count);
|
||||||
Session::flash('message', $message);
|
Session::flash('message', $message);
|
||||||
|
|
||||||
if ($action == 'restore' && $count == 1) {
|
return $this->returnBulk($this->entityType, $action, $ids);
|
||||||
return Redirect::to('vendors/' . Utils::getFirst($ids));
|
|
||||||
} else {
|
|
||||||
return Redirect::to('vendors');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ class Kernel extends HttpKernel {
|
|||||||
'App\Http\Middleware\VerifyCsrfToken',
|
'App\Http\Middleware\VerifyCsrfToken',
|
||||||
'App\Http\Middleware\DuplicateSubmissionCheck',
|
'App\Http\Middleware\DuplicateSubmissionCheck',
|
||||||
'App\Http\Middleware\QueryLogging',
|
'App\Http\Middleware\QueryLogging',
|
||||||
'App\Http\Middleware\SessionDataCheckMiddleware',
|
|
||||||
'App\Http\Middleware\StartupCheck',
|
'App\Http\Middleware\StartupCheck',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -23,18 +23,22 @@ class ApiCheck {
|
|||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
$loggingIn = $request->is('api/v1/login') || $request->is('api/v1/register');
|
$loggingIn = $request->is('api/v1/login')
|
||||||
|
|| $request->is('api/v1/register')
|
||||||
|
|| $request->is('api/v1/oauth_login');
|
||||||
$headers = Utils::getApiHeaders();
|
$headers = Utils::getApiHeaders();
|
||||||
|
$hasApiSecret = false;
|
||||||
|
|
||||||
if ($secret = env(API_SECRET)) {
|
if ($secret = env(API_SECRET)) {
|
||||||
$hasApiSecret = hash_equals($request->api_secret ?: '', $secret);
|
$requestSecret = Request::header('X-Ninja-Secret') ?: ($request->api_secret ?: '');
|
||||||
|
$hasApiSecret = hash_equals($requestSecret, $secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($loggingIn) {
|
if ($loggingIn) {
|
||||||
// check API secret
|
// check API secret
|
||||||
if ( ! $hasApiSecret) {
|
if ( ! $hasApiSecret) {
|
||||||
sleep(ERROR_DELAY);
|
sleep(ERROR_DELAY);
|
||||||
return Response::json('Invalid secret', 403, $headers);
|
return Response::json('Invalid value for API_SECRET', 403, $headers);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// check for a valid token
|
// check for a valid token
|
||||||
|
@ -15,8 +15,7 @@ class DuplicateSubmissionCheck
|
|||||||
*/
|
*/
|
||||||
public function handle(Request $request, Closure $next)
|
public function handle(Request $request, Closure $next)
|
||||||
{
|
{
|
||||||
|
if ($request->is('api/v1/*') || $request->is('documents')) {
|
||||||
if ($request->is('api/v1/*')) {
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ class QueryLogging
|
|||||||
// Enable query logging for development
|
// Enable query logging for development
|
||||||
if (Utils::isNinjaDev()) {
|
if (Utils::isNinjaDev()) {
|
||||||
DB::enableQueryLog();
|
DB::enableQueryLog();
|
||||||
|
$timeStart = microtime(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $next($request);
|
$response = $next($request);
|
||||||
@ -32,7 +33,9 @@ class QueryLogging
|
|||||||
if (strstr($request->url(), '_debugbar') === false) {
|
if (strstr($request->url(), '_debugbar') === false) {
|
||||||
$queries = DB::getQueryLog();
|
$queries = DB::getQueryLog();
|
||||||
$count = count($queries);
|
$count = count($queries);
|
||||||
Log::info($request->method() . ' - ' . $request->url() . ": $count queries");
|
$timeEnd = microtime(true);
|
||||||
|
$time = $timeEnd - $timeStart;
|
||||||
|
Log::info($request->method() . ' - ' . $request->url() . ": $count queries - " . $time);
|
||||||
//Log::info($queries);
|
//Log::info($queries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
<?php namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
use Auth;
|
|
||||||
use Session;
|
|
||||||
|
|
||||||
// https://arjunphp.com/laravel5-inactivity-idle-session-logout/
|
|
||||||
class SessionDataCheckMiddleware {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check session data, if role is not valid logout the request
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Closure $next
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function handle($request, Closure $next)
|
|
||||||
{
|
|
||||||
$bag = Session::getMetadataBag();
|
|
||||||
$max = env('IDLE_TIMEOUT_MINUTES', 6 * 60) * 60; // minute to second conversion
|
|
||||||
$elapsed = time() - $bag->getLastUsed();
|
|
||||||
|
|
||||||
if ( ! $bag || $elapsed > $max) {
|
|
||||||
$request->session()->flush();
|
|
||||||
Auth::logout();
|
|
||||||
$request->session()->flash('warning', trans('texts.inactive_logout'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,7 +13,7 @@ use Event;
|
|||||||
use Schema;
|
use Schema;
|
||||||
use App\Models\Language;
|
use App\Models\Language;
|
||||||
use App\Models\InvoiceDesign;
|
use App\Models\InvoiceDesign;
|
||||||
use App\Events\UserSettingsChanged;
|
use App\Events\UserLoggedIn;
|
||||||
use App\Libraries\CurlUtils;
|
use App\Libraries\CurlUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,13 +118,13 @@ class StartupCheck
|
|||||||
|
|
||||||
// Make sure the account/user localization settings are in the session
|
// Make sure the account/user localization settings are in the session
|
||||||
if (Auth::check() && !Session::has(SESSION_TIMEZONE)) {
|
if (Auth::check() && !Session::has(SESSION_TIMEZONE)) {
|
||||||
Event::fire(new UserSettingsChanged());
|
Event::fire(new UserLoggedIn());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user is claiming a license (ie, additional invoices, white label, etc.)
|
// Check if the user is claiming a license (ie, additional invoices, white label, etc.)
|
||||||
if (isset($_SERVER['REQUEST_URI'])) {
|
if ( ! Utils::isNinjaProd() && isset($_SERVER['REQUEST_URI'])) {
|
||||||
$claimingLicense = Utils::startsWith($_SERVER['REQUEST_URI'], '/claim_license');
|
$claimingLicense = Utils::startsWith($_SERVER['REQUEST_URI'], '/claim_license');
|
||||||
if (!$claimingLicense && Input::has('license_key') && Input::has('product_id')) {
|
if ( ! $claimingLicense && Input::has('license_key') && Input::has('product_id')) {
|
||||||
$licenseKey = Input::get('license_key');
|
$licenseKey = Input::get('license_key');
|
||||||
$productId = Input::get('product_id');
|
$productId = Input::get('product_id');
|
||||||
|
|
||||||
@ -154,6 +154,8 @@ class StartupCheck
|
|||||||
$company->save();
|
$company->save();
|
||||||
|
|
||||||
Session::flash('message', trans('texts.bought_white_label'));
|
Session::flash('message', trans('texts.bought_white_label'));
|
||||||
|
} else {
|
||||||
|
Session::flash('error', trans('texts.invalid_white_label_license'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,11 +36,11 @@ class EntityRequest extends Request {
|
|||||||
|
|
||||||
$class = Utils::getEntityClass($this->entityType);
|
$class = Utils::getEntityClass($this->entityType);
|
||||||
|
|
||||||
if (method_exists($class, 'trashed')) {
|
if (method_exists($class, 'trashed')) {
|
||||||
$this->entity = $class::scope($publicId)->withTrashed()->firstOrFail();
|
$this->entity = $class::scope($publicId)->withTrashed()->firstOrFail();
|
||||||
} else {
|
} else {
|
||||||
$this->entity = $class::scope($publicId)->firstOrFail();
|
$this->entity = $class::scope($publicId)->firstOrFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->entity;
|
return $this->entity;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
class UpdateTaxRateRequest extends TaxRateRequest
|
class UpdateTaxRateRequest extends TaxRateRequest
|
||||||
{
|
{
|
||||||
// Expenses
|
|
||||||
/**
|
/**
|
||||||
* Determine if the user is authorized to make this request.
|
* Determine if the user is authorized to make this request.
|
||||||
*
|
*
|
||||||
|
52
app/Http/ViewComposers/ClientPortalHeaderComposer.php
Normal file
52
app/Http/ViewComposers/ClientPortalHeaderComposer.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\ViewComposers;
|
||||||
|
|
||||||
|
use DB;
|
||||||
|
use Cache;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
use App\Models\Contact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClientPortalHeaderComposer.php.
|
||||||
|
*
|
||||||
|
* @copyright See LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
class ClientPortalHeaderComposer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bind data to the view.
|
||||||
|
*
|
||||||
|
* @param View $view
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function compose(View $view)
|
||||||
|
{
|
||||||
|
$contactKey = session('contact_key');
|
||||||
|
|
||||||
|
if ( ! $contactKey) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact = Contact::where('contact_key', '=', $contactKey)
|
||||||
|
->with('client')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ( ! $contact || $contact->is_deleted) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$client = $contact->client;
|
||||||
|
|
||||||
|
$hasDocuments = DB::table('invoices')
|
||||||
|
->where('invoices.client_id', '=', $client->id)
|
||||||
|
->whereNull('invoices.deleted_at')
|
||||||
|
->join('documents', 'documents.invoice_id', '=', 'invoices.id')
|
||||||
|
->count();
|
||||||
|
|
||||||
|
$view->with('hasQuotes', $client->quotes->count());
|
||||||
|
$view->with('hasCredits', $client->creditsWithBalance->count());
|
||||||
|
$view->with('hasDocuments', $hasDocuments);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Application Routes
|
| Application Routes
|
||||||
@ -39,6 +38,7 @@ Route::post('/get_started', 'AccountController@getStarted');
|
|||||||
Route::group(['middleware' => 'auth:client'], function() {
|
Route::group(['middleware' => 'auth:client'], function() {
|
||||||
Route::get('view/{invitation_key}', 'ClientPortalController@view');
|
Route::get('view/{invitation_key}', 'ClientPortalController@view');
|
||||||
Route::get('download/{invitation_key}', 'ClientPortalController@download');
|
Route::get('download/{invitation_key}', 'ClientPortalController@download');
|
||||||
|
Route::put('sign/{invitation_key}', 'ClientPortalController@sign');
|
||||||
Route::get('view', 'HomeController@viewLogo');
|
Route::get('view', 'HomeController@viewLogo');
|
||||||
Route::get('approve/{invitation_key}', 'QuoteController@approve');
|
Route::get('approve/{invitation_key}', 'QuoteController@approve');
|
||||||
Route::get('payment/{invitation_key}/{gateway_type?}/{source_id?}', 'OnlinePaymentController@showPayment');
|
Route::get('payment/{invitation_key}/{gateway_type?}/{source_id?}', 'OnlinePaymentController@showPayment');
|
||||||
@ -52,18 +52,19 @@ Route::group(['middleware' => 'auth:client'], function() {
|
|||||||
Route::post('client/payment_methods/default', 'ClientPortalController@setDefaultPaymentMethod');
|
Route::post('client/payment_methods/default', 'ClientPortalController@setDefaultPaymentMethod');
|
||||||
Route::post('client/payment_methods/{source_id}/remove', 'ClientPortalController@removePaymentMethod');
|
Route::post('client/payment_methods/{source_id}/remove', 'ClientPortalController@removePaymentMethod');
|
||||||
Route::get('client/quotes', 'ClientPortalController@quoteIndex');
|
Route::get('client/quotes', 'ClientPortalController@quoteIndex');
|
||||||
|
Route::get('client/credits', 'ClientPortalController@creditIndex');
|
||||||
Route::get('client/invoices', 'ClientPortalController@invoiceIndex');
|
Route::get('client/invoices', 'ClientPortalController@invoiceIndex');
|
||||||
Route::get('client/invoices/recurring', 'ClientPortalController@recurringInvoiceIndex');
|
Route::get('client/invoices/recurring', 'ClientPortalController@recurringInvoiceIndex');
|
||||||
Route::post('client/invoices/auto_bill', 'ClientPortalController@setAutoBill');
|
Route::post('client/invoices/auto_bill', 'ClientPortalController@setAutoBill');
|
||||||
Route::get('client/documents', 'ClientPortalController@documentIndex');
|
Route::get('client/documents', 'ClientPortalController@documentIndex');
|
||||||
Route::get('client/payments', 'ClientPortalController@paymentIndex');
|
Route::get('client/payments', 'ClientPortalController@paymentIndex');
|
||||||
Route::get('client/dashboard', 'ClientPortalController@dashboard');
|
Route::get('client/dashboard/{contact_key?}', 'ClientPortalController@dashboard');
|
||||||
Route::get('client/dashboard/{contact_key}', 'ClientPortalController@contactIndex');
|
|
||||||
Route::get('client/documents/js/{documents}/{filename}', 'ClientPortalController@getDocumentVFSJS');
|
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}/{documents}/{filename?}', 'ClientPortalController@getDocument');
|
||||||
Route::get('client/documents/{invitation_key}/{filename?}', 'ClientPortalController@getInvoiceDocumentsZip');
|
Route::get('client/documents/{invitation_key}/{filename?}', 'ClientPortalController@getInvoiceDocumentsZip');
|
||||||
|
|
||||||
Route::get('api/client.quotes', ['as'=>'api.client.quotes', 'uses'=>'ClientPortalController@quoteDatatable']);
|
Route::get('api/client.quotes', ['as'=>'api.client.quotes', 'uses'=>'ClientPortalController@quoteDatatable']);
|
||||||
|
Route::get('api/client.credits', ['as'=>'api.client.credits', 'uses'=>'ClientPortalController@creditDatatable']);
|
||||||
Route::get('api/client.invoices', ['as'=>'api.client.invoices', 'uses'=>'ClientPortalController@invoiceDatatable']);
|
Route::get('api/client.invoices', ['as'=>'api.client.invoices', 'uses'=>'ClientPortalController@invoiceDatatable']);
|
||||||
Route::get('api/client.recurring_invoices', ['as'=>'api.client.recurring_invoices', 'uses'=>'ClientPortalController@recurringInvoiceDatatable']);
|
Route::get('api/client.recurring_invoices', ['as'=>'api.client.recurring_invoices', 'uses'=>'ClientPortalController@recurringInvoiceDatatable']);
|
||||||
Route::get('api/client.documents', ['as'=>'api.client.documents', 'uses'=>'ClientPortalController@documentDatatable']);
|
Route::get('api/client.documents', ['as'=>'api.client.documents', 'uses'=>'ClientPortalController@documentDatatable']);
|
||||||
@ -128,11 +129,12 @@ Route::group(['middleware' => 'auth:user'], function() {
|
|||||||
Route::get('hide_message', 'HomeController@hideMessage');
|
Route::get('hide_message', 'HomeController@hideMessage');
|
||||||
Route::get('force_inline_pdf', 'UserController@forcePDFJS');
|
Route::get('force_inline_pdf', 'UserController@forcePDFJS');
|
||||||
Route::get('account/get_search_data', ['as' => 'get_search_data', 'uses' => 'AccountController@getSearchData']);
|
Route::get('account/get_search_data', ['as' => 'get_search_data', 'uses' => 'AccountController@getSearchData']);
|
||||||
Route::get('check_invoice_number/{invoice_number}', 'InvoiceController@checkInvoiceNumber');
|
Route::get('check_invoice_number/{invoice_id?}', 'InvoiceController@checkInvoiceNumber');
|
||||||
Route::get('save_sidebar_state', 'UserController@saveSidebarState');
|
Route::post('save_sidebar_state', 'UserController@saveSidebarState');
|
||||||
|
|
||||||
Route::get('settings/user_details', 'AccountController@showUserDetails');
|
Route::get('settings/user_details', 'AccountController@showUserDetails');
|
||||||
Route::post('settings/user_details', 'AccountController@saveUserDetails');
|
Route::post('settings/user_details', 'AccountController@saveUserDetails');
|
||||||
|
Route::post('settings/payment_gateway_limits', 'AccountController@savePaymentGatewayLimits');
|
||||||
Route::post('users/change_password', 'UserController@changePassword');
|
Route::post('users/change_password', 'UserController@changePassword');
|
||||||
|
|
||||||
Route::resource('clients', 'ClientController');
|
Route::resource('clients', 'ClientController');
|
||||||
@ -186,6 +188,11 @@ Route::group(['middleware' => 'auth:user'], function() {
|
|||||||
Route::get('api/credits/{client_id?}', ['as'=>'api.credits', 'uses'=>'CreditController@getDatatable']);
|
Route::get('api/credits/{client_id?}', ['as'=>'api.credits', 'uses'=>'CreditController@getDatatable']);
|
||||||
Route::post('credits/bulk', 'CreditController@bulk');
|
Route::post('credits/bulk', 'CreditController@bulk');
|
||||||
|
|
||||||
|
Route::get('api/products', ['as'=>'api.products', 'uses'=>'ProductController@getDatatable']);
|
||||||
|
Route::resource('products', 'ProductController');
|
||||||
|
Route::post('products/bulk', 'ProductController@bulk');
|
||||||
|
|
||||||
|
|
||||||
Route::get('/resend_confirmation', 'AccountController@resendConfirmation');
|
Route::get('/resend_confirmation', 'AccountController@resendConfirmation');
|
||||||
Route::post('/update_setup', 'AppController@updateSetup');
|
Route::post('/update_setup', 'AppController@updateSetup');
|
||||||
|
|
||||||
@ -228,10 +235,6 @@ Route::group([
|
|||||||
Route::resource('tokens', 'TokenController');
|
Route::resource('tokens', 'TokenController');
|
||||||
Route::post('tokens/bulk', 'TokenController@bulk');
|
Route::post('tokens/bulk', 'TokenController@bulk');
|
||||||
|
|
||||||
Route::get('api/products', ['as'=>'api.products', 'uses'=>'ProductController@getDatatable']);
|
|
||||||
Route::resource('products', 'ProductController');
|
|
||||||
Route::post('products/bulk', 'ProductController@bulk');
|
|
||||||
|
|
||||||
Route::get('api/tax_rates', ['as'=>'api.tax_rates', 'uses'=>'TaxRateController@getDatatable']);
|
Route::get('api/tax_rates', ['as'=>'api.tax_rates', 'uses'=>'TaxRateController@getDatatable']);
|
||||||
Route::resource('tax_rates', 'TaxRateController');
|
Route::resource('tax_rates', 'TaxRateController');
|
||||||
Route::post('tax_rates/bulk', 'TaxRateController@bulk');
|
Route::post('tax_rates/bulk', 'TaxRateController@bulk');
|
||||||
@ -281,6 +284,7 @@ Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
|
|||||||
{
|
{
|
||||||
Route::get('ping', 'AccountApiController@ping');
|
Route::get('ping', 'AccountApiController@ping');
|
||||||
Route::post('login', 'AccountApiController@login');
|
Route::post('login', 'AccountApiController@login');
|
||||||
|
Route::post('oauth_login', 'AccountApiController@oauthLogin');
|
||||||
Route::post('register', 'AccountApiController@register');
|
Route::post('register', 'AccountApiController@register');
|
||||||
Route::get('static', 'AccountApiController@getStaticData');
|
Route::get('static', 'AccountApiController@getStaticData');
|
||||||
Route::get('accounts', 'AccountApiController@show');
|
Route::get('accounts', 'AccountApiController@show');
|
||||||
@ -305,12 +309,8 @@ Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
|
|||||||
Route::post('update_notifications', 'AccountApiController@updatePushNotifications');
|
Route::post('update_notifications', 'AccountApiController@updatePushNotifications');
|
||||||
Route::get('dashboard', 'DashboardApiController@index');
|
Route::get('dashboard', 'DashboardApiController@index');
|
||||||
Route::resource('documents', 'DocumentAPIController');
|
Route::resource('documents', 'DocumentAPIController');
|
||||||
|
|
||||||
// Vendor
|
|
||||||
Route::resource('vendors', 'VendorApiController');
|
Route::resource('vendors', 'VendorApiController');
|
||||||
|
Route::resource('expense_categories', 'ExpenseCategoryApiController');
|
||||||
//Expense
|
|
||||||
Route::resource('expenses', 'ExpenseApiController');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Redirects for legacy links
|
// Redirects for legacy links
|
||||||
@ -430,56 +430,50 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('ACTIVITY_TYPE_CREATE_CLIENT', 1);
|
define('ACTIVITY_TYPE_CREATE_CLIENT', 1);
|
||||||
define('ACTIVITY_TYPE_ARCHIVE_CLIENT', 2);
|
define('ACTIVITY_TYPE_ARCHIVE_CLIENT', 2);
|
||||||
define('ACTIVITY_TYPE_DELETE_CLIENT', 3);
|
define('ACTIVITY_TYPE_DELETE_CLIENT', 3);
|
||||||
|
|
||||||
define('ACTIVITY_TYPE_CREATE_INVOICE', 4);
|
define('ACTIVITY_TYPE_CREATE_INVOICE', 4);
|
||||||
define('ACTIVITY_TYPE_UPDATE_INVOICE', 5);
|
define('ACTIVITY_TYPE_UPDATE_INVOICE', 5);
|
||||||
define('ACTIVITY_TYPE_EMAIL_INVOICE', 6);
|
define('ACTIVITY_TYPE_EMAIL_INVOICE', 6);
|
||||||
define('ACTIVITY_TYPE_VIEW_INVOICE', 7);
|
define('ACTIVITY_TYPE_VIEW_INVOICE', 7);
|
||||||
define('ACTIVITY_TYPE_ARCHIVE_INVOICE', 8);
|
define('ACTIVITY_TYPE_ARCHIVE_INVOICE', 8);
|
||||||
define('ACTIVITY_TYPE_DELETE_INVOICE', 9);
|
define('ACTIVITY_TYPE_DELETE_INVOICE', 9);
|
||||||
|
|
||||||
define('ACTIVITY_TYPE_CREATE_PAYMENT', 10);
|
define('ACTIVITY_TYPE_CREATE_PAYMENT', 10);
|
||||||
//define('ACTIVITY_TYPE_UPDATE_PAYMENT', 11);
|
//define('ACTIVITY_TYPE_UPDATE_PAYMENT', 11);
|
||||||
define('ACTIVITY_TYPE_ARCHIVE_PAYMENT', 12);
|
define('ACTIVITY_TYPE_ARCHIVE_PAYMENT', 12);
|
||||||
define('ACTIVITY_TYPE_DELETE_PAYMENT', 13);
|
define('ACTIVITY_TYPE_DELETE_PAYMENT', 13);
|
||||||
define('ACTIVITY_TYPE_VOIDED_PAYMENT', 39);
|
|
||||||
define('ACTIVITY_TYPE_REFUNDED_PAYMENT', 40);
|
|
||||||
define('ACTIVITY_TYPE_FAILED_PAYMENT', 41);
|
|
||||||
|
|
||||||
define('ACTIVITY_TYPE_CREATE_CREDIT', 14);
|
define('ACTIVITY_TYPE_CREATE_CREDIT', 14);
|
||||||
//define('ACTIVITY_TYPE_UPDATE_CREDIT', 15);
|
//define('ACTIVITY_TYPE_UPDATE_CREDIT', 15);
|
||||||
define('ACTIVITY_TYPE_ARCHIVE_CREDIT', 16);
|
define('ACTIVITY_TYPE_ARCHIVE_CREDIT', 16);
|
||||||
define('ACTIVITY_TYPE_DELETE_CREDIT', 17);
|
define('ACTIVITY_TYPE_DELETE_CREDIT', 17);
|
||||||
|
|
||||||
define('ACTIVITY_TYPE_CREATE_QUOTE', 18);
|
define('ACTIVITY_TYPE_CREATE_QUOTE', 18);
|
||||||
define('ACTIVITY_TYPE_UPDATE_QUOTE', 19);
|
define('ACTIVITY_TYPE_UPDATE_QUOTE', 19);
|
||||||
define('ACTIVITY_TYPE_EMAIL_QUOTE', 20);
|
define('ACTIVITY_TYPE_EMAIL_QUOTE', 20);
|
||||||
define('ACTIVITY_TYPE_VIEW_QUOTE', 21);
|
define('ACTIVITY_TYPE_VIEW_QUOTE', 21);
|
||||||
define('ACTIVITY_TYPE_ARCHIVE_QUOTE', 22);
|
define('ACTIVITY_TYPE_ARCHIVE_QUOTE', 22);
|
||||||
define('ACTIVITY_TYPE_DELETE_QUOTE', 23);
|
define('ACTIVITY_TYPE_DELETE_QUOTE', 23);
|
||||||
|
|
||||||
define('ACTIVITY_TYPE_RESTORE_QUOTE', 24);
|
define('ACTIVITY_TYPE_RESTORE_QUOTE', 24);
|
||||||
define('ACTIVITY_TYPE_RESTORE_INVOICE', 25);
|
define('ACTIVITY_TYPE_RESTORE_INVOICE', 25);
|
||||||
define('ACTIVITY_TYPE_RESTORE_CLIENT', 26);
|
define('ACTIVITY_TYPE_RESTORE_CLIENT', 26);
|
||||||
define('ACTIVITY_TYPE_RESTORE_PAYMENT', 27);
|
define('ACTIVITY_TYPE_RESTORE_PAYMENT', 27);
|
||||||
define('ACTIVITY_TYPE_RESTORE_CREDIT', 28);
|
define('ACTIVITY_TYPE_RESTORE_CREDIT', 28);
|
||||||
define('ACTIVITY_TYPE_APPROVE_QUOTE', 29);
|
define('ACTIVITY_TYPE_APPROVE_QUOTE', 29);
|
||||||
|
|
||||||
// Vendors
|
|
||||||
define('ACTIVITY_TYPE_CREATE_VENDOR', 30);
|
define('ACTIVITY_TYPE_CREATE_VENDOR', 30);
|
||||||
define('ACTIVITY_TYPE_ARCHIVE_VENDOR', 31);
|
define('ACTIVITY_TYPE_ARCHIVE_VENDOR', 31);
|
||||||
define('ACTIVITY_TYPE_DELETE_VENDOR', 32);
|
define('ACTIVITY_TYPE_DELETE_VENDOR', 32);
|
||||||
define('ACTIVITY_TYPE_RESTORE_VENDOR', 33);
|
define('ACTIVITY_TYPE_RESTORE_VENDOR', 33);
|
||||||
|
|
||||||
// expenses
|
|
||||||
define('ACTIVITY_TYPE_CREATE_EXPENSE', 34);
|
define('ACTIVITY_TYPE_CREATE_EXPENSE', 34);
|
||||||
define('ACTIVITY_TYPE_ARCHIVE_EXPENSE', 35);
|
define('ACTIVITY_TYPE_ARCHIVE_EXPENSE', 35);
|
||||||
define('ACTIVITY_TYPE_DELETE_EXPENSE', 36);
|
define('ACTIVITY_TYPE_DELETE_EXPENSE', 36);
|
||||||
define('ACTIVITY_TYPE_RESTORE_EXPENSE', 37);
|
define('ACTIVITY_TYPE_RESTORE_EXPENSE', 37);
|
||||||
|
define('ACTIVITY_TYPE_VOIDED_PAYMENT', 39);
|
||||||
// tasks
|
define('ACTIVITY_TYPE_REFUNDED_PAYMENT', 40);
|
||||||
|
define('ACTIVITY_TYPE_FAILED_PAYMENT', 41);
|
||||||
define('ACTIVITY_TYPE_CREATE_TASK', 42);
|
define('ACTIVITY_TYPE_CREATE_TASK', 42);
|
||||||
define('ACTIVITY_TYPE_UPDATE_TASK', 43);
|
define('ACTIVITY_TYPE_UPDATE_TASK', 43);
|
||||||
|
define('ACTIVITY_TYPE_ARCHIVE_TASK', 44);
|
||||||
|
define('ACTIVITY_TYPE_DELETE_TASK', 45);
|
||||||
|
define('ACTIVITY_TYPE_RESTORE_TASK', 46);
|
||||||
|
define('ACTIVITY_TYPE_UPDATE_EXPENSE', 47);
|
||||||
|
|
||||||
|
|
||||||
define('DEFAULT_INVOICE_NUMBER', '0001');
|
define('DEFAULT_INVOICE_NUMBER', '0001');
|
||||||
define('RECENTLY_VIEWED_LIMIT', 20);
|
define('RECENTLY_VIEWED_LIMIT', 20);
|
||||||
@ -491,6 +485,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('MAX_IFRAME_URL_LENGTH', 250);
|
define('MAX_IFRAME_URL_LENGTH', 250);
|
||||||
define('MAX_LOGO_FILE_SIZE', 200); // KB
|
define('MAX_LOGO_FILE_SIZE', 200); // KB
|
||||||
define('MAX_FAILED_LOGINS', 10);
|
define('MAX_FAILED_LOGINS', 10);
|
||||||
|
define('MAX_INVOICE_ITEMS', env('MAX_INVOICE_ITEMS', 100));
|
||||||
define('MAX_DOCUMENT_SIZE', env('MAX_DOCUMENT_SIZE', 10000));// KB
|
define('MAX_DOCUMENT_SIZE', env('MAX_DOCUMENT_SIZE', 10000));// KB
|
||||||
define('MAX_EMAIL_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 10000));// Total KB
|
define('MAX_EMAIL_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 10000));// Total KB
|
||||||
define('MAX_ZIP_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 30000));// Total KB (uncompressed)
|
define('MAX_ZIP_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 30000));// Total KB (uncompressed)
|
||||||
@ -547,6 +542,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
|
|
||||||
define('SESSION_TIMEZONE', 'timezone');
|
define('SESSION_TIMEZONE', 'timezone');
|
||||||
define('SESSION_CURRENCY', 'currency');
|
define('SESSION_CURRENCY', 'currency');
|
||||||
|
define('SESSION_CURRENCY_DECORATOR', 'currency_decorator');
|
||||||
define('SESSION_DATE_FORMAT', 'dateFormat');
|
define('SESSION_DATE_FORMAT', 'dateFormat');
|
||||||
define('SESSION_DATE_PICKER_FORMAT', 'datePickerFormat');
|
define('SESSION_DATE_PICKER_FORMAT', 'datePickerFormat');
|
||||||
define('SESSION_DATETIME_FORMAT', 'datetimeFormat');
|
define('SESSION_DATETIME_FORMAT', 'datetimeFormat');
|
||||||
@ -601,6 +597,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('GATEWAY_CYBERSOURCE', 49);
|
define('GATEWAY_CYBERSOURCE', 49);
|
||||||
define('GATEWAY_WEPAY', 60);
|
define('GATEWAY_WEPAY', 60);
|
||||||
define('GATEWAY_BRAINTREE', 61);
|
define('GATEWAY_BRAINTREE', 61);
|
||||||
|
define('GATEWAY_CUSTOM', 62);
|
||||||
|
|
||||||
// The customer exists, but only as a local concept
|
// The customer exists, but only as a local concept
|
||||||
// The remote gateway doesn't understand the concept of customers
|
// The remote gateway doesn't understand the concept of customers
|
||||||
@ -623,6 +620,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('NINJA_DOCS_URL', env('NINJA_DOCS_URL', 'http://docs.invoiceninja.com/en/latest'));
|
define('NINJA_DOCS_URL', env('NINJA_DOCS_URL', 'http://docs.invoiceninja.com/en/latest'));
|
||||||
define('NINJA_DATE', '2000-01-01');
|
define('NINJA_DATE', '2000-01-01');
|
||||||
define('NINJA_VERSION', '2.7.2' . env('NINJA_VERSION_SUFFIX'));
|
define('NINJA_VERSION', '2.7.2' . env('NINJA_VERSION_SUFFIX'));
|
||||||
|
define('NINJA_VERSION', '2.8.0' . env('NINJA_VERSION_SUFFIX'));
|
||||||
|
|
||||||
define('SOCIAL_LINK_FACEBOOK', env('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja'));
|
define('SOCIAL_LINK_FACEBOOK', env('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja'));
|
||||||
define('SOCIAL_LINK_TWITTER', env('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja'));
|
define('SOCIAL_LINK_TWITTER', env('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja'));
|
||||||
@ -639,6 +637,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('EMAIL_MARKUP_URL', env('EMAIL_MARKUP_URL', 'https://developers.google.com/gmail/markup'));
|
define('EMAIL_MARKUP_URL', env('EMAIL_MARKUP_URL', 'https://developers.google.com/gmail/markup'));
|
||||||
define('OFX_HOME_URL', env('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all'));
|
define('OFX_HOME_URL', env('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all'));
|
||||||
define('GOOGLE_ANALYITCS_URL', env('GOOGLE_ANALYITCS_URL', 'https://www.google-analytics.com/collect'));
|
define('GOOGLE_ANALYITCS_URL', env('GOOGLE_ANALYITCS_URL', 'https://www.google-analytics.com/collect'));
|
||||||
|
define('TRANSIFEX_URL', env('TRANSIFEX_URL', 'https://www.transifex.com/invoice-ninja/invoice-ninja'));
|
||||||
|
|
||||||
define('MSBOT_LOGIN_URL', 'https://login.microsoftonline.com/common/oauth2/v2.0/token');
|
define('MSBOT_LOGIN_URL', 'https://login.microsoftonline.com/common/oauth2/v2.0/token');
|
||||||
define('MSBOT_LUIS_URL', 'https://api.projectoxford.ai/luis/v1/application');
|
define('MSBOT_LUIS_URL', 'https://api.projectoxford.ai/luis/v1/application');
|
||||||
@ -704,11 +703,12 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('PAYMENT_METHOD_STATUS_VERIFICATION_FAILED', 'verification_failed');
|
define('PAYMENT_METHOD_STATUS_VERIFICATION_FAILED', 'verification_failed');
|
||||||
define('PAYMENT_METHOD_STATUS_VERIFIED', 'verified');
|
define('PAYMENT_METHOD_STATUS_VERIFIED', 'verified');
|
||||||
|
|
||||||
define('GATEWAY_TYPE_CREDIT_CARD', 'credit_card');
|
define('GATEWAY_TYPE_CREDIT_CARD', 1);
|
||||||
define('GATEWAY_TYPE_BANK_TRANSFER', 'bank_transfer');
|
define('GATEWAY_TYPE_BANK_TRANSFER', 2);
|
||||||
define('GATEWAY_TYPE_PAYPAL', 'paypal');
|
define('GATEWAY_TYPE_PAYPAL', 3);
|
||||||
define('GATEWAY_TYPE_BITCOIN', 'bitcoin');
|
define('GATEWAY_TYPE_BITCOIN', 4);
|
||||||
define('GATEWAY_TYPE_DWOLLA', 'dwolla');
|
define('GATEWAY_TYPE_DWOLLA', 5);
|
||||||
|
define('GATEWAY_TYPE_CUSTOM', 6);
|
||||||
define('GATEWAY_TYPE_TOKEN', 'token');
|
define('GATEWAY_TYPE_TOKEN', 'token');
|
||||||
|
|
||||||
define('REMINDER1', 'reminder1');
|
define('REMINDER1', 'reminder1');
|
||||||
@ -744,6 +744,10 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
|
|
||||||
define('BANK_LIBRARY_OFX', 1);
|
define('BANK_LIBRARY_OFX', 1);
|
||||||
|
|
||||||
|
define('CURRENCY_DECORATOR_CODE', 'code');
|
||||||
|
define('CURRENCY_DECORATOR_SYMBOL', 'symbol');
|
||||||
|
define('CURRENCY_DECORATOR_NONE', 'none');
|
||||||
|
|
||||||
define('RESELLER_REVENUE_SHARE', 'A');
|
define('RESELLER_REVENUE_SHARE', 'A');
|
||||||
define('RESELLER_LIMITED_USERS', 'B');
|
define('RESELLER_LIMITED_USERS', 'B');
|
||||||
|
|
||||||
@ -852,6 +856,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
'invoiceStatus' => 'App\Models\InvoiceStatus',
|
'invoiceStatus' => 'App\Models\InvoiceStatus',
|
||||||
'frequencies' => 'App\Models\Frequency',
|
'frequencies' => 'App\Models\Frequency',
|
||||||
'gateways' => 'App\Models\Gateway',
|
'gateways' => 'App\Models\Gateway',
|
||||||
|
'gatewayTypes' => 'App\Models\GatewayType',
|
||||||
'fonts' => 'App\Models\Font',
|
'fonts' => 'App\Models\Font',
|
||||||
'banks' => 'App\Models\Bank',
|
'banks' => 'App\Models\Bank',
|
||||||
];
|
];
|
||||||
|
@ -152,7 +152,7 @@ class parseCSV {
|
|||||||
* @param input CSV file or string
|
* @param input CSV file or string
|
||||||
* @return nothing
|
* @return nothing
|
||||||
*/
|
*/
|
||||||
function parseCSV ($input = null, $offset = null, $limit = null, $conditions = null) {
|
function __construct ($input = null, $offset = null, $limit = null, $conditions = null) {
|
||||||
if ( $offset !== null ) $this->offset = $offset;
|
if ( $offset !== null ) $this->offset = $offset;
|
||||||
if ( $limit !== null ) $this->limit = $limit;
|
if ( $limit !== null ) $this->limit = $limit;
|
||||||
if ( count($conditions) > 0 ) $this->conditions = $conditions;
|
if ( count($conditions) > 0 ) $this->conditions = $conditions;
|
||||||
|
@ -24,6 +24,8 @@ class HistoryUtils
|
|||||||
ACTIVITY_TYPE_CREATE_CLIENT,
|
ACTIVITY_TYPE_CREATE_CLIENT,
|
||||||
ACTIVITY_TYPE_CREATE_TASK,
|
ACTIVITY_TYPE_CREATE_TASK,
|
||||||
ACTIVITY_TYPE_UPDATE_TASK,
|
ACTIVITY_TYPE_UPDATE_TASK,
|
||||||
|
ACTIVITY_TYPE_CREATE_EXPENSE,
|
||||||
|
ACTIVITY_TYPE_UPDATE_EXPENSE,
|
||||||
ACTIVITY_TYPE_CREATE_INVOICE,
|
ACTIVITY_TYPE_CREATE_INVOICE,
|
||||||
ACTIVITY_TYPE_UPDATE_INVOICE,
|
ACTIVITY_TYPE_UPDATE_INVOICE,
|
||||||
ACTIVITY_TYPE_EMAIL_INVOICE,
|
ACTIVITY_TYPE_EMAIL_INVOICE,
|
||||||
@ -35,7 +37,7 @@ class HistoryUtils
|
|||||||
];
|
];
|
||||||
|
|
||||||
$activities = Activity::scope()
|
$activities = Activity::scope()
|
||||||
->with(['client.contacts', 'invoice', 'task'])
|
->with(['client.contacts', 'invoice', 'task', 'expense'])
|
||||||
->whereIn('user_id', $userIds)
|
->whereIn('user_id', $userIds)
|
||||||
->whereIn('activity_type_id', $activityTypes)
|
->whereIn('activity_type_id', $activityTypes)
|
||||||
->orderBy('id', 'asc')
|
->orderBy('id', 'asc')
|
||||||
@ -52,6 +54,12 @@ class HistoryUtils
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$entity->setRelation('client', $activity->client);
|
$entity->setRelation('client', $activity->client);
|
||||||
|
} else if ($activity->activity_type_id == ACTIVITY_TYPE_CREATE_EXPENSE || $activity->activity_type_id == ACTIVITY_TYPE_UPDATE_EXPENSE) {
|
||||||
|
$entity = $activity->expense;
|
||||||
|
if ( ! $entity) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$entity->setRelation('client', $activity->client);
|
||||||
} else {
|
} else {
|
||||||
$entity = $activity->invoice;
|
$entity = $activity->invoice;
|
||||||
if ( ! $entity) {
|
if ( ! $entity) {
|
||||||
|
@ -22,6 +22,9 @@ class Utils
|
|||||||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday",
|
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static $months = [
|
||||||
|
'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december',
|
||||||
|
];
|
||||||
|
|
||||||
public static function isRegistered()
|
public static function isRegistered()
|
||||||
{
|
{
|
||||||
@ -92,6 +95,17 @@ class Utils
|
|||||||
return Utils::getResllerType() ? true : false;
|
return Utils::getResllerType() ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function isWhiteLabel()
|
||||||
|
{
|
||||||
|
if (Utils::isNinjaProd()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$account = \App\Models\Account::first();
|
||||||
|
|
||||||
|
return $account && $account->hasFeature(FEATURE_WHITE_LABEL);
|
||||||
|
}
|
||||||
|
|
||||||
public static function getResllerType()
|
public static function getResllerType()
|
||||||
{
|
{
|
||||||
return isset($_ENV['RESELLER_TYPE']) ? $_ENV['RESELLER_TYPE'] : false;
|
return isset($_ENV['RESELLER_TYPE']) ? $_ENV['RESELLER_TYPE'] : false;
|
||||||
@ -151,6 +165,11 @@ class Utils
|
|||||||
return Auth::check() && Auth::user()->isTrial();
|
return Auth::check() && Auth::user()->isTrial();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function isPaidPro()
|
||||||
|
{
|
||||||
|
return static::isPro() && ! static::isTrial();
|
||||||
|
}
|
||||||
|
|
||||||
public static function isEnglish()
|
public static function isEnglish()
|
||||||
{
|
{
|
||||||
return App::getLocale() == 'en';
|
return App::getLocale() == 'en';
|
||||||
@ -186,7 +205,7 @@ class Utils
|
|||||||
$response = new stdClass();
|
$response = new stdClass();
|
||||||
$response->message = isset($_ENV["{$userType}_MESSAGE"]) ? $_ENV["{$userType}_MESSAGE"] : '';
|
$response->message = isset($_ENV["{$userType}_MESSAGE"]) ? $_ENV["{$userType}_MESSAGE"] : '';
|
||||||
$response->id = isset($_ENV["{$userType}_ID"]) ? $_ENV["{$userType}_ID"] : '';
|
$response->id = isset($_ENV["{$userType}_ID"]) ? $_ENV["{$userType}_ID"] : '';
|
||||||
$response->version = env('NINJA_SELF_HOST_VERSION', NINJA_VERSION);
|
$response->version = NINJA_VERSION;
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
@ -354,7 +373,7 @@ class Utils
|
|||||||
return $data->first();
|
return $data->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function formatMoney($value, $currencyId = false, $countryId = false, $showCode = false)
|
public static function formatMoney($value, $currencyId = false, $countryId = false, $decorator = false)
|
||||||
{
|
{
|
||||||
$value = floatval($value);
|
$value = floatval($value);
|
||||||
|
|
||||||
@ -362,6 +381,10 @@ class Utils
|
|||||||
$currencyId = Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY);
|
$currencyId = Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$decorator) {
|
||||||
|
$decorator = Session::get(SESSION_CURRENCY_DECORATOR, CURRENCY_DECORATOR_SYMBOL);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$countryId && Auth::check()) {
|
if (!$countryId && Auth::check()) {
|
||||||
$countryId = Auth::user()->account->country_id;
|
$countryId = Auth::user()->account->country_id;
|
||||||
}
|
}
|
||||||
@ -387,7 +410,9 @@ class Utils
|
|||||||
$value = number_format($value, $precision, $decimal, $thousand);
|
$value = number_format($value, $precision, $decimal, $thousand);
|
||||||
$symbol = $currency->symbol;
|
$symbol = $currency->symbol;
|
||||||
|
|
||||||
if ($showCode || !$symbol) {
|
if ($decorator == CURRENCY_DECORATOR_NONE) {
|
||||||
|
return $value;
|
||||||
|
} elseif ($decorator == CURRENCY_DECORATOR_CODE || ! $symbol) {
|
||||||
return "{$value} {$code}";
|
return "{$value} {$code}";
|
||||||
} elseif ($swapSymbol) {
|
} elseif ($swapSymbol) {
|
||||||
return "{$value} " . trim($symbol);
|
return "{$value} " . trim($symbol);
|
||||||
@ -635,11 +660,22 @@ class Utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getMonthOptions()
|
||||||
|
{
|
||||||
|
$months = [];
|
||||||
|
|
||||||
|
for ($i=1; $i<=count(static::$months); $i++) {
|
||||||
|
$month = static::$months[$i-1];
|
||||||
|
$number = $i < 10 ? '0' . $i : $i;
|
||||||
|
$months["2000-{$number}-01"] = trans("texts.{$month}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $months;
|
||||||
|
}
|
||||||
|
|
||||||
private static function getMonth($offset)
|
private static function getMonth($offset)
|
||||||
{
|
{
|
||||||
$months = ['january', 'february', 'march', 'april', 'may', 'june',
|
$months = static::$months;
|
||||||
'july', 'august', 'september', 'october', 'november', 'december', ];
|
|
||||||
|
|
||||||
$month = intval(date('n')) - 1;
|
$month = intval(date('n')) - 1;
|
||||||
|
|
||||||
$month += $offset;
|
$month += $offset;
|
||||||
@ -1029,4 +1065,66 @@ class Utils
|
|||||||
return trans('texts.'.strtolower($day));
|
return trans('texts.'.strtolower($day));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getDocsUrl($path)
|
||||||
|
{
|
||||||
|
$page = '';
|
||||||
|
$parts = explode('/', $path);
|
||||||
|
$first = count($parts) ? $parts[0] : false;
|
||||||
|
$second = count($parts) > 1 ? $parts[1] : false;
|
||||||
|
|
||||||
|
$entityTypes = [
|
||||||
|
'clients',
|
||||||
|
'invoices',
|
||||||
|
'payments',
|
||||||
|
'recurring_invoices',
|
||||||
|
'credits',
|
||||||
|
'quotes',
|
||||||
|
'tasks',
|
||||||
|
'expenses',
|
||||||
|
'vendors',
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($path == 'dashboard') {
|
||||||
|
$page = '/introduction.html#dashboard';
|
||||||
|
} elseif (in_array($path, $entityTypes)) {
|
||||||
|
$page = "/{$path}.html#list-" . str_replace('_', '-', $path);
|
||||||
|
} elseif (in_array($first, $entityTypes)) {
|
||||||
|
$action = ($first == 'payments' || $first == 'credits') ? 'enter' : 'create';
|
||||||
|
$page = "/{$first}.html#{$action}-" . substr(str_replace('_', '-', $first), 0, -1);
|
||||||
|
} elseif ($first == 'expense_categories') {
|
||||||
|
$page = '/expenses.html#expense-categories';
|
||||||
|
} elseif ($first == 'settings') {
|
||||||
|
if ($second == 'bank_accounts') {
|
||||||
|
$page = ''; // TODO write docs
|
||||||
|
} elseif (in_array($second, \App\Models\Account::$basicSettings)) {
|
||||||
|
if ($second == 'products') {
|
||||||
|
$second = 'product_library';
|
||||||
|
} elseif ($second == 'notifications') {
|
||||||
|
$second = 'email_notifications';
|
||||||
|
}
|
||||||
|
$page = '/settings.html#' . str_replace('_', '-', $second);
|
||||||
|
} elseif (in_array($second, \App\Models\Account::$advancedSettings)) {
|
||||||
|
$page = "/{$second}.html";
|
||||||
|
} elseif ($second == 'customize_design') {
|
||||||
|
$page = '/invoice_design.html#customize';
|
||||||
|
}
|
||||||
|
} elseif ($first == 'tax_rates') {
|
||||||
|
$page = '/settings.html#tax-rates';
|
||||||
|
} elseif ($first == 'products') {
|
||||||
|
$page = '/settings.html#product-library';
|
||||||
|
} elseif ($first == 'users') {
|
||||||
|
$page = '/user_management.html#create-user';
|
||||||
|
}
|
||||||
|
|
||||||
|
return url(NINJA_DOCS_URL . $page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function calculateTaxes($amount, $taxRate1, $taxRate2)
|
||||||
|
{
|
||||||
|
$tax1 = round($amount * $taxRate1 / 100, 2);
|
||||||
|
$tax2 = round($amount * $taxRate2 / 100, 2);
|
||||||
|
|
||||||
|
return round($amount + $tax1 + $tax2, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<?php namespace App\Listeners;
|
<?php namespace App\Listeners;
|
||||||
|
|
||||||
use App\Events\TaskWasCreated;
|
|
||||||
use App\Events\TaskWasUpdated;
|
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Events\ClientWasCreated;
|
use App\Events\ClientWasCreated;
|
||||||
use App\Events\ClientWasDeleted;
|
use App\Events\ClientWasDeleted;
|
||||||
@ -33,6 +31,16 @@ use App\Events\CreditWasCreated;
|
|||||||
use App\Events\CreditWasDeleted;
|
use App\Events\CreditWasDeleted;
|
||||||
use App\Events\CreditWasArchived;
|
use App\Events\CreditWasArchived;
|
||||||
use App\Events\CreditWasRestored;
|
use App\Events\CreditWasRestored;
|
||||||
|
use App\Events\TaskWasCreated;
|
||||||
|
use App\Events\TaskWasUpdated;
|
||||||
|
use App\Events\TaskWasArchived;
|
||||||
|
use App\Events\TaskWasRestored;
|
||||||
|
use App\Events\TaskWasDeleted;
|
||||||
|
use App\Events\ExpenseWasCreated;
|
||||||
|
use App\Events\ExpenseWasUpdated;
|
||||||
|
use App\Events\ExpenseWasArchived;
|
||||||
|
use App\Events\ExpenseWasRestored;
|
||||||
|
use App\Events\ExpenseWasDeleted;
|
||||||
use App\Ninja\Repositories\ActivityRepository;
|
use App\Ninja\Repositories\ActivityRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,7 +131,9 @@ class ActivityListener
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$backupInvoice = Invoice::with('invoice_items', 'client.account', 'client.contacts')->find($event->invoice->id);
|
$backupInvoice = Invoice::with('invoice_items', 'client.account', 'client.contacts')
|
||||||
|
->withArchived()
|
||||||
|
->find($event->invoice->id);
|
||||||
|
|
||||||
$activity = $this->activityRepo->create(
|
$activity = $this->activityRepo->create(
|
||||||
$event->invoice,
|
$event->invoice,
|
||||||
@ -489,9 +499,92 @@ class ActivityListener
|
|||||||
*/
|
*/
|
||||||
public function updatedTask(TaskWasUpdated $event)
|
public function updatedTask(TaskWasUpdated $event)
|
||||||
{
|
{
|
||||||
|
if ( ! $event->task->isChanged()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->activityRepo->create(
|
$this->activityRepo->create(
|
||||||
$event->task,
|
$event->task,
|
||||||
ACTIVITY_TYPE_UPDATE_TASK
|
ACTIVITY_TYPE_UPDATE_TASK
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function archivedTask(TaskWasArchived $event)
|
||||||
|
{
|
||||||
|
if ($event->task->is_deleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->activityRepo->create(
|
||||||
|
$event->task,
|
||||||
|
ACTIVITY_TYPE_ARCHIVE_TASK
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deletedTask(TaskWasDeleted $event)
|
||||||
|
{
|
||||||
|
$this->activityRepo->create(
|
||||||
|
$event->task,
|
||||||
|
ACTIVITY_TYPE_DELETE_TASK
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function restoredTask(TaskWasRestored $event)
|
||||||
|
{
|
||||||
|
$this->activityRepo->create(
|
||||||
|
$event->task,
|
||||||
|
ACTIVITY_TYPE_RESTORE_TASK
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function createdExpense(ExpenseWasCreated $event)
|
||||||
|
{
|
||||||
|
$this->activityRepo->create(
|
||||||
|
$event->expense,
|
||||||
|
ACTIVITY_TYPE_CREATE_EXPENSE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatedExpense(ExpenseWasUpdated $event)
|
||||||
|
{
|
||||||
|
if ( ! $event->expense->isChanged()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->activityRepo->create(
|
||||||
|
$event->expense,
|
||||||
|
ACTIVITY_TYPE_UPDATE_EXPENSE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function archivedExpense(ExpenseWasArchived $event)
|
||||||
|
{
|
||||||
|
if ($event->expense->is_deleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->activityRepo->create(
|
||||||
|
$event->expense,
|
||||||
|
ACTIVITY_TYPE_ARCHIVE_EXPENSE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deletedExpense(ExpenseWasDeleted $event)
|
||||||
|
{
|
||||||
|
$this->activityRepo->create(
|
||||||
|
$event->expense,
|
||||||
|
ACTIVITY_TYPE_DELETE_EXPENSE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function restoredExpense(ExpenseWasRestored $event)
|
||||||
|
{
|
||||||
|
$this->activityRepo->create(
|
||||||
|
$event->expense,
|
||||||
|
ACTIVITY_TYPE_RESTORE_EXPENSE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,16 @@ class Account extends Eloquent
|
|||||||
'enable_second_tax_rate',
|
'enable_second_tax_rate',
|
||||||
'include_item_taxes_inline',
|
'include_item_taxes_inline',
|
||||||
'start_of_week',
|
'start_of_week',
|
||||||
|
'financial_year_start',
|
||||||
|
'enable_client_portal',
|
||||||
|
'enable_client_portal_dashboard',
|
||||||
|
'enable_portal_password',
|
||||||
|
'send_portal_password',
|
||||||
|
'enable_buy_now_buttons',
|
||||||
|
'show_accept_invoice_terms',
|
||||||
|
'show_accept_quote_terms',
|
||||||
|
'require_invoice_signature',
|
||||||
|
'require_quote_signature',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,6 +112,21 @@ class Account extends Eloquent
|
|||||||
ACCOUNT_USER_MANAGEMENT,
|
ACCOUNT_USER_MANAGEMENT,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static $modules = [
|
||||||
|
ENTITY_RECURRING_INVOICE => 1,
|
||||||
|
ENTITY_CREDIT => 2,
|
||||||
|
ENTITY_QUOTE => 4,
|
||||||
|
ENTITY_TASK => 8,
|
||||||
|
ENTITY_EXPENSE => 16,
|
||||||
|
ENTITY_VENDOR => 32,
|
||||||
|
];
|
||||||
|
|
||||||
|
public static $dashboardSections = [
|
||||||
|
'total_revenue' => 1,
|
||||||
|
'average_invoice' => 2,
|
||||||
|
'outstanding' => 4,
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
*/
|
*/
|
||||||
@ -438,7 +463,7 @@ class Account extends Eloquent
|
|||||||
* @param bool $hideSymbol
|
* @param bool $hideSymbol
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function formatMoney($amount, $client = null, $hideSymbol = false)
|
public function formatMoney($amount, $client = null, $decorator = false)
|
||||||
{
|
{
|
||||||
if ($client && $client->currency_id) {
|
if ($client && $client->currency_id) {
|
||||||
$currencyId = $client->currency_id;
|
$currencyId = $client->currency_id;
|
||||||
@ -456,9 +481,11 @@ class Account extends Eloquent
|
|||||||
$countryId = false;
|
$countryId = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$hideSymbol = $this->show_currency_code || $hideSymbol;
|
if ( ! $decorator) {
|
||||||
|
$decorator = $this->show_currency_code ? CURRENCY_DECORATOR_CODE : CURRENCY_DECORATOR_SYMBOL;
|
||||||
|
}
|
||||||
|
|
||||||
return Utils::formatMoney($amount, $currencyId, $countryId, $hideSymbol);
|
return Utils::formatMoney($amount, $currencyId, $countryId, $decorator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -610,14 +637,14 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $invitation
|
* @param bool $invitation
|
||||||
* @param bool $gatewayType
|
* @param mixed $gatewayTypeId
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function paymentDriver($invitation = false, $gatewayType = false)
|
public function paymentDriver($invitation = false, $gatewayTypeId = false)
|
||||||
{
|
{
|
||||||
/** @var AccountGateway $accountGateway */
|
/** @var AccountGateway $accountGateway */
|
||||||
if ($accountGateway = $this->getGatewayByType($gatewayType)) {
|
if ($accountGateway = $this->getGatewayByType($gatewayTypeId)) {
|
||||||
return $accountGateway->paymentDriver($invitation, $gatewayType);
|
return $accountGateway->paymentDriver($invitation, $gatewayTypeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -735,6 +762,22 @@ class Account extends Eloquent
|
|||||||
return Document::getDirectFileUrl($this->logo, $this->getLogoDisk());
|
return Document::getDirectFileUrl($this->logo, $this->getLogoDisk());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getLogoPath()
|
||||||
|
{
|
||||||
|
if ( ! $this->hasLogo()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$disk = $this->getLogoDisk();
|
||||||
|
$adapter = $disk->getAdapter();
|
||||||
|
|
||||||
|
if ($adapter instanceof \League\Flysystem\Adapter\Local) {
|
||||||
|
return $adapter->applyPathPrefix($this->logo);
|
||||||
|
} else {
|
||||||
|
return Document::getDirectFileUrl($this->logo, $this->getLogoDisk());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
@ -1024,6 +1067,7 @@ class Account extends Eloquent
|
|||||||
$locale = ($client && $client->language_id) ? $client->language->locale : ($this->language_id ? $this->Language->locale : DEFAULT_LOCALE);
|
$locale = ($client && $client->language_id) ? $client->language->locale : ($this->language_id ? $this->Language->locale : DEFAULT_LOCALE);
|
||||||
|
|
||||||
Session::put(SESSION_CURRENCY, $currencyId);
|
Session::put(SESSION_CURRENCY, $currencyId);
|
||||||
|
Session::put(SESSION_CURRENCY_DECORATOR, $this->show_currency_code ? CURRENCY_DECORATOR_CODE : CURRENCY_DECORATOR_SYMBOL);
|
||||||
Session::put(SESSION_LOCALE, $locale);
|
Session::put(SESSION_LOCALE, $locale);
|
||||||
|
|
||||||
App::setLocale($locale);
|
App::setLocale($locale);
|
||||||
@ -1812,6 +1856,43 @@ class Account extends Eloquent
|
|||||||
public function getFontFolders(){
|
public function getFontFolders(){
|
||||||
return array_map(function($item){return $item['folder'];}, $this->getFontsData());
|
return array_map(function($item){return $item['folder'];}, $this->getFontsData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isModuleEnabled($entityType)
|
||||||
|
{
|
||||||
|
if (in_array($entityType, [
|
||||||
|
ENTITY_CLIENT,
|
||||||
|
ENTITY_INVOICE,
|
||||||
|
ENTITY_PRODUCT,
|
||||||
|
ENTITY_PAYMENT,
|
||||||
|
])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->enabled_modules & static::$modules[$entityType];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showAuthenticatePanel($invoice)
|
||||||
|
{
|
||||||
|
return $this->showAcceptTerms($invoice) || $this->showSignature($invoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showAcceptTerms($invoice)
|
||||||
|
{
|
||||||
|
if ( ! $this->isPro() || ! $invoice->terms) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $invoice->is_quote ? $this->show_accept_quote_terms : $this->show_accept_invoice_terms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showSignature($invoice)
|
||||||
|
{
|
||||||
|
if ( ! $this->isPro()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $invoice->is_quote ? $this->require_quote_signature : $this->require_invoice_signature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Account::updated(function ($account)
|
Account::updated(function ($account)
|
||||||
|
@ -73,14 +73,14 @@ class AccountGateway extends EntityModel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $invitation
|
* @param bool $invitation
|
||||||
* @param bool $gatewayType
|
* @param mixed $gatewayTypeId
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function paymentDriver($invitation = false, $gatewayType = false)
|
public function paymentDriver($invitation = false, $gatewayTypeId = false)
|
||||||
{
|
{
|
||||||
$class = static::paymentDriverClass($this->gateway->provider);
|
$class = static::paymentDriverClass($this->gateway->provider);
|
||||||
|
|
||||||
return new $class($this, $invitation, $gatewayType);
|
return new $class($this, $invitation, $gatewayTypeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
32
app/Models/AccountGatewaySettings.php
Normal file
32
app/Models/AccountGatewaySettings.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php namespace App\Models;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AccountGatewaySettings
|
||||||
|
*/
|
||||||
|
class AccountGatewaySettings extends EntityModel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $dates = ['updated_at'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected static $hasPublicId = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function gatewayType()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\GatewayType');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCreatedAtAttribute($value)
|
||||||
|
{
|
||||||
|
// to Disable created_at
|
||||||
|
}
|
||||||
|
}
|
@ -83,6 +83,11 @@ class Activity extends Eloquent
|
|||||||
return $this->belongsTo('App\Models\Task')->withTrashed();
|
return $this->belongsTo('App\Models\Task')->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function expense()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Expense')->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
public function key()
|
public function key()
|
||||||
{
|
{
|
||||||
return sprintf('%s-%s-%s', $this->activity_type_id, $this->client_id, $this->created_at->timestamp);
|
return sprintf('%s-%s-%s', $this->activity_type_id, $this->client_id, $this->created_at->timestamp);
|
||||||
@ -101,9 +106,8 @@ class Activity extends Eloquent
|
|||||||
$contactId = $this->contact_id;
|
$contactId = $this->contact_id;
|
||||||
$payment = $this->payment;
|
$payment = $this->payment;
|
||||||
$credit = $this->credit;
|
$credit = $this->credit;
|
||||||
|
$expense = $this->expense;
|
||||||
$isSystem = $this->is_system;
|
$isSystem = $this->is_system;
|
||||||
|
|
||||||
/** @var Task $task */
|
|
||||||
$task = $this->task;
|
$task = $this->task;
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
@ -117,6 +121,7 @@ class Activity extends Eloquent
|
|||||||
'adjustment' => $this->adjustment ? $account->formatMoney($this->adjustment, $this) : null,
|
'adjustment' => $this->adjustment ? $account->formatMoney($this->adjustment, $this) : null,
|
||||||
'credit' => $credit ? $account->formatMoney($credit->amount, $client) : null,
|
'credit' => $credit ? $account->formatMoney($credit->amount, $client) : null,
|
||||||
'task' => $task ? link_to($task->getRoute(), substr($task->description, 0, 30).'...') : null,
|
'task' => $task ? link_to($task->getRoute(), substr($task->description, 0, 30).'...') : null,
|
||||||
|
'expense' => $expense ? link_to($expense->getRoute(), substr($expense->public_notes, 0, 30).'...') : null,
|
||||||
];
|
];
|
||||||
|
|
||||||
return trans("texts.activity_{$activityTypeId}", $data);
|
return trans("texts.activity_{$activityTypeId}", $data);
|
||||||
|
@ -89,6 +89,10 @@ class Client extends EntityModel
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public static $fieldWebsite = 'website';
|
public static $fieldWebsite = 'website';
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $fieldVatNumber = 'vat_number';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
@ -106,6 +110,7 @@ class Client extends EntityModel
|
|||||||
Client::$fieldCountry,
|
Client::$fieldCountry,
|
||||||
Client::$fieldNotes,
|
Client::$fieldNotes,
|
||||||
Client::$fieldWebsite,
|
Client::$fieldWebsite,
|
||||||
|
Client::$fieldVatNumber,
|
||||||
Contact::$fieldFirstName,
|
Contact::$fieldFirstName,
|
||||||
Contact::$fieldLastName,
|
Contact::$fieldLastName,
|
||||||
Contact::$fieldPhone,
|
Contact::$fieldPhone,
|
||||||
@ -132,6 +137,7 @@ class Client extends EntityModel
|
|||||||
'country' => 'country',
|
'country' => 'country',
|
||||||
'note' => 'notes',
|
'note' => 'notes',
|
||||||
'site|website' => 'website',
|
'site|website' => 'website',
|
||||||
|
'vat' => 'vat_number',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +165,14 @@ class Client extends EntityModel
|
|||||||
return $this->hasMany('App\Models\Invoice');
|
return $this->hasMany('App\Models\Invoice');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function quotes()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Invoice')->where('invoice_type_id', '=', INVOICE_TYPE_QUOTE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
*/
|
*/
|
||||||
@ -223,6 +237,14 @@ class Client extends EntityModel
|
|||||||
return $this->hasMany('App\Models\Credit');
|
return $this->hasMany('App\Models\Credit');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function creditsWithBalance()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Credit')->where('balance', '>', 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
@ -329,7 +351,7 @@ class Client extends EntityModel
|
|||||||
|
|
||||||
$contact = $this->contacts[0];
|
$contact = $this->contacts[0];
|
||||||
|
|
||||||
return $contact->getDisplayName() ?: trans('texts.unnamed_client');
|
return $contact->getDisplayName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use Auth;
|
use Auth;
|
||||||
use Eloquent;
|
use Eloquent;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
use Utils;
|
use Utils;
|
||||||
use Validator;
|
use Validator;
|
||||||
|
|
||||||
@ -14,6 +15,12 @@ class EntityModel extends Eloquent
|
|||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
public $timestamps = true;
|
public $timestamps = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected static $hasPublicId = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@ -56,13 +63,16 @@ class EntityModel extends Eloquent
|
|||||||
$lastEntity = $className::whereAccountId($entity->account_id);
|
$lastEntity = $className::whereAccountId($entity->account_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$lastEntity = $lastEntity->orderBy('public_id', 'DESC')
|
|
||||||
->first();
|
|
||||||
|
|
||||||
if ($lastEntity) {
|
if (static::$hasPublicId) {
|
||||||
$entity->public_id = $lastEntity->public_id + 1;
|
$lastEntity = $lastEntity->orderBy('public_id', 'DESC')
|
||||||
} else {
|
->first();
|
||||||
$entity->public_id = 1;
|
|
||||||
|
if ($lastEntity) {
|
||||||
|
$entity->public_id = $lastEntity->public_id + 1;
|
||||||
|
} else {
|
||||||
|
$entity->public_id = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
@ -244,6 +254,7 @@ class EntityModel extends Eloquent
|
|||||||
$icons = [
|
$icons = [
|
||||||
'dashboard' => 'tachometer',
|
'dashboard' => 'tachometer',
|
||||||
'clients' => 'users',
|
'clients' => 'users',
|
||||||
|
'products' => 'cube',
|
||||||
'invoices' => 'file-pdf-o',
|
'invoices' => 'file-pdf-o',
|
||||||
'payments' => 'credit-card',
|
'payments' => 'credit-card',
|
||||||
'recurring_invoices' => 'files-o',
|
'recurring_invoices' => 'files-o',
|
||||||
@ -253,9 +264,21 @@ class EntityModel extends Eloquent
|
|||||||
'expenses' => 'file-image-o',
|
'expenses' => 'file-image-o',
|
||||||
'vendors' => 'building',
|
'vendors' => 'building',
|
||||||
'settings' => 'cog',
|
'settings' => 'cog',
|
||||||
|
'self-update' => 'download',
|
||||||
];
|
];
|
||||||
|
|
||||||
return array_get($icons, $entityType);
|
return array_get($icons, $entityType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isDirty return true if the field's new value is the same as the old one
|
||||||
|
public function isChanged()
|
||||||
|
{
|
||||||
|
foreach ($this->fillable as $field) {
|
||||||
|
if ($this->$field != $this->getOriginal($field)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php namespace App\Models;
|
<?php namespace App\Models;
|
||||||
|
|
||||||
|
use Utils;
|
||||||
use Laracasts\Presenter\PresentableTrait;
|
use Laracasts\Presenter\PresentableTrait;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use App\Events\ExpenseWasCreated;
|
use App\Events\ExpenseWasCreated;
|
||||||
@ -31,6 +32,7 @@ class Expense extends EntityModel
|
|||||||
'client_id',
|
'client_id',
|
||||||
'vendor_id',
|
'vendor_id',
|
||||||
'expense_currency_id',
|
'expense_currency_id',
|
||||||
|
'expense_date',
|
||||||
'invoice_currency_id',
|
'invoice_currency_id',
|
||||||
'amount',
|
'amount',
|
||||||
'foreign_amount',
|
'foreign_amount',
|
||||||
@ -46,6 +48,29 @@ class Expense extends EntityModel
|
|||||||
'tax_name2',
|
'tax_name2',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static function getImportColumns()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'client',
|
||||||
|
'vendor',
|
||||||
|
'amount',
|
||||||
|
'public_notes',
|
||||||
|
'expense_category',
|
||||||
|
'expense_date',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getImportMap()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'amount|total' => 'amount',
|
||||||
|
'category' => 'expense_category',
|
||||||
|
'client' => 'client',
|
||||||
|
'vendor' => 'vendor',
|
||||||
|
'notes|details' => 'public_notes',
|
||||||
|
'date' => 'expense_date',
|
||||||
|
];
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
*/
|
*/
|
||||||
@ -107,7 +132,13 @@ class Expense extends EntityModel
|
|||||||
*/
|
*/
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->transaction_id ?: '#' . $this->public_id;
|
if ($this->transaction_id) {
|
||||||
|
return $this->transaction_id;
|
||||||
|
} elseif ($this->public_notes) {
|
||||||
|
return mb_strimwidth($this->public_notes, 0, 16, "...");
|
||||||
|
} else {
|
||||||
|
return '#' . $this->public_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -175,6 +206,11 @@ class Expense extends EntityModel
|
|||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function amountWithTax()
|
||||||
|
{
|
||||||
|
return Utils::calculateTaxes($this->amount, $this->tax_rate1, $this->tax_rate2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expense::creating(function ($expense) {
|
Expense::creating(function ($expense) {
|
||||||
@ -196,7 +232,3 @@ Expense::updated(function ($expense) {
|
|||||||
Expense::deleting(function ($expense) {
|
Expense::deleting(function ($expense) {
|
||||||
$expense->setNullValues();
|
$expense->setNullValues();
|
||||||
});
|
});
|
||||||
|
|
||||||
Expense::deleted(function ($expense) {
|
|
||||||
event(new ExpenseWasDeleted($expense));
|
|
||||||
});
|
|
||||||
|
@ -14,6 +14,12 @@ class Gateway extends Eloquent
|
|||||||
*/
|
*/
|
||||||
public $timestamps = true;
|
public $timestamps = true;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'provider',
|
||||||
|
'is_offsite',
|
||||||
|
'sort_order',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@ -39,6 +45,7 @@ class Gateway extends Eloquent
|
|||||||
GATEWAY_BRAINTREE,
|
GATEWAY_BRAINTREE,
|
||||||
GATEWAY_AUTHORIZE_NET,
|
GATEWAY_AUTHORIZE_NET,
|
||||||
GATEWAY_MOLLIE,
|
GATEWAY_MOLLIE,
|
||||||
|
GATEWAY_CUSTOM,
|
||||||
];
|
];
|
||||||
|
|
||||||
// allow adding these gateway if another gateway
|
// allow adding these gateway if another gateway
|
||||||
@ -174,6 +181,18 @@ class Gateway extends Eloquent
|
|||||||
*/
|
*/
|
||||||
public function getFields()
|
public function getFields()
|
||||||
{
|
{
|
||||||
return Omnipay::create($this->provider)->getDefaultParameters();
|
if ($this->isCustom()) {
|
||||||
|
return [
|
||||||
|
'name' => '',
|
||||||
|
'text' => '',
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return Omnipay::create($this->provider)->getDefaultParameters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isCustom()
|
||||||
|
{
|
||||||
|
return $this->id === GATEWAY_CUSTOM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
app/Models/GatewayType.php
Normal file
34
app/Models/GatewayType.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php namespace App\Models;
|
||||||
|
|
||||||
|
use Eloquent;
|
||||||
|
use Cache;
|
||||||
|
use Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GatewayType
|
||||||
|
*/
|
||||||
|
class GatewayType extends Eloquent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAliasFromId($id)
|
||||||
|
{
|
||||||
|
return Utils::getFromCache($id, 'gatewayTypes')->alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getIdFromAlias($alias)
|
||||||
|
{
|
||||||
|
return Cache::get('gatewayTypes')->where('alias', $alias)->first()->id;
|
||||||
|
}
|
||||||
|
}
|
@ -134,4 +134,13 @@ class Invitation extends EntityModel
|
|||||||
$invoice->markViewed();
|
$invoice->markViewed();
|
||||||
$client->markLoggedIn();
|
$client->markLoggedIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function signatureDiv()
|
||||||
|
{
|
||||||
|
if ( ! $this->signature_base64) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('<img src="data:image/svg+xml;base64,%s"></img><p/>%s: %s', $this->signature_base64, trans('texts.signed'), Utils::fromSqlDateTime($this->signature_date));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,6 +514,11 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
return storage_path() . '/pdfcache/cache-' . $this->id . '.pdf';
|
return storage_path() . '/pdfcache/cache-' . $this->id . '.pdf';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function canBePaid()
|
||||||
|
{
|
||||||
|
return floatval($this->balance) > 0 && ! $this->is_deleted;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $invoice
|
* @param $invoice
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -11,4 +11,12 @@ class PaymentType extends Eloquent
|
|||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function gatewayType()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\GatewayType');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,16 @@ class Task extends EntityModel
|
|||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
use PresentableTrait;
|
use PresentableTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'client_id',
|
||||||
|
'description',
|
||||||
|
'time_log',
|
||||||
|
'is_running',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
@ -82,6 +92,18 @@ class Task extends EntityModel
|
|||||||
return self::calcStartTime($this);
|
return self::calcStartTime($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getLastStartTime()
|
||||||
|
{
|
||||||
|
$parts = json_decode($this->time_log) ?: [];
|
||||||
|
|
||||||
|
if (count($parts)) {
|
||||||
|
$index = count($parts) - 1;
|
||||||
|
return $parts[$index][0];
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $task
|
* @param $task
|
||||||
* @return int
|
* @return int
|
||||||
@ -165,6 +187,14 @@ class Task extends EntityModel
|
|||||||
|
|
||||||
return '#' . $this->public_id;
|
return '#' . $this->public_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function scopeDateRange($query, $startDate, $endDate)
|
||||||
|
{
|
||||||
|
$query->whereRaw('cast(substring(time_log, 3, 10) as unsigned) >= ' . $startDate->format('U'));
|
||||||
|
$query->whereRaw('cast(substring(time_log, 3, 10) as unsigned) <= ' . $endDate->format('U'));
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ trait PresentsInvoice
|
|||||||
'invoice.partial_due',
|
'invoice.partial_due',
|
||||||
'invoice.custom_text_value1',
|
'invoice.custom_text_value1',
|
||||||
'invoice.custom_text_value2',
|
'invoice.custom_text_value2',
|
||||||
|
'.blank',
|
||||||
],
|
],
|
||||||
INVOICE_FIELDS_CLIENT => [
|
INVOICE_FIELDS_CLIENT => [
|
||||||
'client.client_name',
|
'client.client_name',
|
||||||
@ -97,9 +98,11 @@ trait PresentsInvoice
|
|||||||
'client.city_state_postal',
|
'client.city_state_postal',
|
||||||
'client.country',
|
'client.country',
|
||||||
'client.email',
|
'client.email',
|
||||||
|
'client.phone',
|
||||||
'client.contact_name',
|
'client.contact_name',
|
||||||
'client.custom_value1',
|
'client.custom_value1',
|
||||||
'client.custom_value2',
|
'client.custom_value2',
|
||||||
|
'.blank',
|
||||||
],
|
],
|
||||||
INVOICE_FIELDS_ACCOUNT => [
|
INVOICE_FIELDS_ACCOUNT => [
|
||||||
'account.company_name',
|
'account.company_name',
|
||||||
@ -114,6 +117,7 @@ trait PresentsInvoice
|
|||||||
'account.country',
|
'account.country',
|
||||||
'account.custom_value1',
|
'account.custom_value1',
|
||||||
'account.custom_value2',
|
'account.custom_value2',
|
||||||
|
'.blank',
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -198,6 +202,7 @@ trait PresentsInvoice
|
|||||||
'company_name',
|
'company_name',
|
||||||
'website',
|
'website',
|
||||||
'phone',
|
'phone',
|
||||||
|
'blank',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
|
@ -5,19 +5,14 @@ use Event;
|
|||||||
use App\Libraries\Utils;
|
use App\Libraries\Utils;
|
||||||
use App\Events\UserSettingsChanged;
|
use App\Events\UserSettingsChanged;
|
||||||
use App\Events\UserSignedUp;
|
use App\Events\UserSignedUp;
|
||||||
use Illuminate\Auth\Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Foundation\Auth\Access\Authorizable;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Auth\Passwords\CanResetPassword;
|
|
||||||
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
|
|
||||||
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
|
|
||||||
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class User
|
* Class User
|
||||||
*/
|
*/
|
||||||
class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract {
|
class User extends Authenticatable
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@ -27,8 +22,6 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
|||||||
'edit_all' => 0b0100,
|
'edit_all' => 0b0100,
|
||||||
];
|
];
|
||||||
|
|
||||||
use Authenticatable, Authorizable, CanResetPassword;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The database table used by the model.
|
* The database table used by the model.
|
||||||
*
|
*
|
||||||
@ -102,26 +95,6 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
|||||||
return PERSON_USER;
|
return PERSON_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unique identifier for the user.
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getAuthIdentifier()
|
|
||||||
{
|
|
||||||
return $this->getKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the password for the user.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getAuthPassword()
|
|
||||||
{
|
|
||||||
return $this->password;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the e-mail address where password reminders are sent.
|
* Get the e-mail address where password reminders are sent.
|
||||||
*
|
*
|
||||||
@ -258,31 +231,6 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
|||||||
return MAX_NUM_VENDORS;
|
return MAX_NUM_VENDORS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getRememberToken()
|
|
||||||
{
|
|
||||||
return $this->remember_token;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $value
|
|
||||||
*/
|
|
||||||
public function setRememberToken($value)
|
|
||||||
{
|
|
||||||
$this->remember_token = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getRememberTokenName()
|
|
||||||
{
|
|
||||||
return 'remember_token';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function clearSession()
|
public function clearSession()
|
||||||
{
|
{
|
||||||
$keys = [
|
$keys = [
|
||||||
@ -425,7 +373,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
|||||||
|
|
||||||
public function caddAddUsers()
|
public function caddAddUsers()
|
||||||
{
|
{
|
||||||
if ( ! Utils::isNinja()) {
|
if ( ! Utils::isNinjaProd()) {
|
||||||
return true;
|
return true;
|
||||||
} elseif ( ! $this->hasFeature(FEATURE_USERS)) {
|
} elseif ( ! $this->hasFeature(FEATURE_USERS)) {
|
||||||
return false;
|
return false;
|
||||||
@ -441,6 +389,12 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
|||||||
|
|
||||||
return $numUsers < $company->num_users;
|
return $numUsers < $company->num_users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function canCreateOrEdit($entityType, $entity = false)
|
||||||
|
{
|
||||||
|
return (($entity && $this->can('edit', $entity))
|
||||||
|
|| (!$entity && $this->can('create', $entityType)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
User::updating(function ($user) {
|
User::updating(function ($user) {
|
||||||
|
@ -211,7 +211,8 @@ class Vendor extends EntityModel
|
|||||||
*/
|
*/
|
||||||
public function addVendorContact($data, $isPrimary = false)
|
public function addVendorContact($data, $isPrimary = false)
|
||||||
{
|
{
|
||||||
$publicId = isset($data['public_id']) ? $data['public_id'] : false;
|
//$publicId = isset($data['public_id']) ? $data['public_id'] : false;
|
||||||
|
$publicId = isset($data['public_id']) ? $data['public_id'] : (isset($data['id']) ? $data['id'] : false);
|
||||||
|
|
||||||
if ($publicId && $publicId != '-1') {
|
if ($publicId && $publicId != '-1') {
|
||||||
$contact = VendorContact::scope($publicId)->firstOrFail();
|
$contact = VendorContact::scope($publicId)->firstOrFail();
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
<?php namespace App\Ninja\Datatables;
|
<?php namespace App\Ninja\Datatables;
|
||||||
|
|
||||||
|
use App\Models\AccountGatewaySettings;
|
||||||
|
use App\Models\GatewayType;
|
||||||
use URL;
|
use URL;
|
||||||
|
use Cache;
|
||||||
|
use Utils;
|
||||||
|
use Session;
|
||||||
use App\Models\AccountGateway;
|
use App\Models\AccountGateway;
|
||||||
|
|
||||||
class AccountGatewayDatatable extends EntityDatatable
|
class AccountGatewayDatatable extends EntityDatatable
|
||||||
{
|
{
|
||||||
|
private static $accountGateways;
|
||||||
|
|
||||||
public $entityType = ENTITY_ACCOUNT_GATEWAY;
|
public $entityType = ENTITY_ACCOUNT_GATEWAY;
|
||||||
|
|
||||||
public function columns()
|
public function columns()
|
||||||
@ -15,10 +22,14 @@ class AccountGatewayDatatable extends EntityDatatable
|
|||||||
function ($model) {
|
function ($model) {
|
||||||
if ($model->deleted_at) {
|
if ($model->deleted_at) {
|
||||||
return $model->name;
|
return $model->name;
|
||||||
|
} elseif ($model->gateway_id == GATEWAY_CUSTOM) {
|
||||||
|
$accountGateway = $this->getAccountGateway($model->id);
|
||||||
|
$name = $accountGateway->getConfigField('name') . ' [' . trans('texts.custom') . ']';
|
||||||
|
return link_to("gateways/{$model->public_id}/edit", $name)->toHtml();
|
||||||
} elseif ($model->gateway_id != GATEWAY_WEPAY) {
|
} elseif ($model->gateway_id != GATEWAY_WEPAY) {
|
||||||
return link_to("gateways/{$model->public_id}/edit", $model->name)->toHtml();
|
return link_to("gateways/{$model->public_id}/edit", $model->name)->toHtml();
|
||||||
} else {
|
} else {
|
||||||
$accountGateway = AccountGateway::find($model->id);
|
$accountGateway = $this->getAccountGateway($model->id);
|
||||||
$config = $accountGateway->getConfig();
|
$config = $accountGateway->getConfig();
|
||||||
$endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
|
$endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
|
||||||
$wepayAccountId = $config->accountId;
|
$wepayAccountId = $config->accountId;
|
||||||
@ -45,12 +56,56 @@ class AccountGatewayDatatable extends EntityDatatable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'limit',
|
||||||
|
function ($model) {
|
||||||
|
if ($model->gateway_id == GATEWAY_CUSTOM) {
|
||||||
|
$gatewayTypes = [GATEWAY_TYPE_CUSTOM];
|
||||||
|
} else {
|
||||||
|
$accountGateway = $this->getAccountGateway($model->id);
|
||||||
|
$paymentDriver = $accountGateway->paymentDriver();
|
||||||
|
$gatewayTypes = $paymentDriver->gatewayTypes();
|
||||||
|
$gatewayTypes = array_diff($gatewayTypes, array(GATEWAY_TYPE_TOKEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = '';
|
||||||
|
foreach ($gatewayTypes as $gatewayTypeId) {
|
||||||
|
$accountGatewaySettings = AccountGatewaySettings::scope()->where('account_gateway_settings.gateway_type_id',
|
||||||
|
'=', $gatewayTypeId)->first();
|
||||||
|
$gatewayType = GatewayType::find($gatewayTypeId);
|
||||||
|
|
||||||
|
if (count($gatewayTypes) > 1) {
|
||||||
|
if ($html) {
|
||||||
|
$html .= '<br>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= $gatewayType->name . ' — ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($accountGatewaySettings && $accountGatewaySettings->min_limit !== null && $accountGatewaySettings->max_limit !== null) {
|
||||||
|
$html .= Utils::formatMoney($accountGatewaySettings->min_limit) . ' - ' . Utils::formatMoney($accountGatewaySettings->max_limit);
|
||||||
|
} elseif ($accountGatewaySettings && $accountGatewaySettings->min_limit !== null) {
|
||||||
|
$html .= trans('texts.min_limit',
|
||||||
|
array('min' => Utils::formatMoney($accountGatewaySettings->min_limit))
|
||||||
|
);
|
||||||
|
} elseif ($accountGatewaySettings && $accountGatewaySettings->max_limit !== null) {
|
||||||
|
$html .= trans('texts.max_limit',
|
||||||
|
array('max' => Utils::formatMoney($accountGatewaySettings->max_limit))
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$html .= trans('texts.no_limit');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function actions()
|
public function actions()
|
||||||
{
|
{
|
||||||
return [
|
$actions = [
|
||||||
[
|
[
|
||||||
uctrans('texts.resend_confirmation_email'),
|
uctrans('texts.resend_confirmation_email'),
|
||||||
function ($model) {
|
function ($model) {
|
||||||
@ -78,7 +133,7 @@ class AccountGatewayDatatable extends EntityDatatable
|
|||||||
], [
|
], [
|
||||||
uctrans('texts.manage_account'),
|
uctrans('texts.manage_account'),
|
||||||
function ($model) {
|
function ($model) {
|
||||||
$accountGateway = AccountGateway::find($model->id);
|
$accountGateway = $this->getAccountGateway($model->id);
|
||||||
$endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
|
$endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
|
||||||
return [
|
return [
|
||||||
'url' => $endpoint.'account/'.$accountGateway->getConfig()->accountId,
|
'url' => $endpoint.'account/'.$accountGateway->getConfig()->accountId,
|
||||||
@ -98,6 +153,46 @@ class AccountGatewayDatatable extends EntityDatatable
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
foreach (Cache::get('gatewayTypes') as $gatewayType) {
|
||||||
|
$actions[] = [
|
||||||
|
trans('texts.set_limits', ['gateway_type' => $gatewayType->name]),
|
||||||
|
function () use ($gatewayType) {
|
||||||
|
$accountGatewaySettings = AccountGatewaySettings::scope()
|
||||||
|
->where('account_gateway_settings.gateway_type_id', '=', $gatewayType->id)
|
||||||
|
->first();
|
||||||
|
$min = $accountGatewaySettings && $accountGatewaySettings->min_limit !== null ? $accountGatewaySettings->min_limit : 'null';
|
||||||
|
$max = $accountGatewaySettings && $accountGatewaySettings->max_limit !== null ? $accountGatewaySettings->max_limit : 'null';
|
||||||
|
|
||||||
|
return "javascript:showLimitsModal('{$gatewayType->name}', {$gatewayType->id}, $min, $max)";
|
||||||
|
},
|
||||||
|
function ($model) use ($gatewayType) {
|
||||||
|
// Only show this action if the given gateway supports this gateway type
|
||||||
|
if ($model->gateway_id == GATEWAY_CUSTOM) {
|
||||||
|
return $gatewayType->id == GATEWAY_TYPE_CUSTOM;
|
||||||
|
} else {
|
||||||
|
$accountGateway = $this->getAccountGateway($model->id);
|
||||||
|
$paymentDriver = $accountGateway->paymentDriver();
|
||||||
|
$gatewayTypes = $paymentDriver->gatewayTypes();
|
||||||
|
|
||||||
|
return in_array($gatewayType->id, $gatewayTypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAccountGateway($id)
|
||||||
|
{
|
||||||
|
if (isset(static::$accountGateways[$id])) {
|
||||||
|
return static::$accountGateways[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$accountGateways[$id] = AccountGateway::find($id);
|
||||||
|
|
||||||
|
return static::$accountGateways[$id];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,9 @@ class ActivityDatatable extends EntityDatatable
|
|||||||
'payment' => $model->payment ?: '',
|
'payment' => $model->payment ?: '',
|
||||||
'credit' => $model->payment_amount ? Utils::formatMoney($model->credit, $model->currency_id, $model->country_id) : '',
|
'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,
|
'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
|
'adjustment' => $model->adjustment ? Utils::formatMoney($model->adjustment, $model->currency_id, $model->country_id) : null,
|
||||||
|
'task' => $model->task_public_id ? link_to('/tasks/' . $model->task_public_id, substr($model->task_description, 0, 30).'...') : null,
|
||||||
|
'expense' => $model->expense_public_id ? link_to('/expenses/' . $model->expense_public_id, substr($model->expense_public_notes, 0, 30).'...') : null,
|
||||||
];
|
];
|
||||||
|
|
||||||
return trans("texts.activity_{$model->activity_type_id}", $data);
|
return trans("texts.activity_{$model->activity_type_id}", $data);
|
||||||
|
@ -93,7 +93,7 @@ class ClientDatatable extends EntityDatatable
|
|||||||
return URL::to("quotes/create/{$model->public_id}");
|
return URL::to("quotes/create/{$model->public_id}");
|
||||||
},
|
},
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return Auth::user()->hasFeature(FEATURE_QUOTES) && Auth::user()->can('create', ENTITY_INVOICE);
|
return Auth::user()->hasFeature(FEATURE_QUOTES) && Auth::user()->can('create', ENTITY_QUOTE);
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -46,7 +46,7 @@ class ExpenseDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'expense_date',
|
'expense_date',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
if(!Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id])){
|
if(!Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id])){
|
||||||
return Utils::fromSqlDate($model->expense_date);
|
return Utils::fromSqlDate($model->expense_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,14 +56,16 @@ class ExpenseDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'amount',
|
'amount',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
|
$amount = Utils::calculateTaxes($model->amount, $model->tax_rate1, $model->tax_rate2);
|
||||||
|
$str = Utils::formatMoney($amount, $model->expense_currency_id);
|
||||||
|
|
||||||
// show both the amount and the converted amount
|
// show both the amount and the converted amount
|
||||||
if ($model->exchange_rate != 1) {
|
if ($model->exchange_rate != 1) {
|
||||||
$converted = round($model->amount * $model->exchange_rate, 2);
|
$converted = round($amount * $model->exchange_rate, 2);
|
||||||
return Utils::formatMoney($model->amount, $model->expense_currency_id) . ' | ' .
|
$str .= ' | ' . Utils::formatMoney($converted, $model->invoice_currency_id);
|
||||||
Utils::formatMoney($converted, $model->invoice_currency_id);
|
|
||||||
} else {
|
|
||||||
return Utils::formatMoney($model->amount, $model->expense_currency_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $str;
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -16,7 +16,7 @@ class InvoiceDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'invoice_number',
|
'invoice_number',
|
||||||
function ($model) use ($entityType) {
|
function ($model) use ($entityType) {
|
||||||
if(!Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id])){
|
if(!Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->user_id])){
|
||||||
return $model->invoice_number;
|
return $model->invoice_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class PaymentDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'invoice_number',
|
'invoice_number',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
if(!Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id])){
|
if(!Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->invoice_user_id])){
|
||||||
return $model->invoice_number;
|
return $model->invoice_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,11 @@ class PaymentDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'payment_date',
|
'payment_date',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return Utils::dateToString($model->payment_date);
|
if ($model->is_deleted) {
|
||||||
|
return Utils::dateToString($model->payment_date);
|
||||||
|
} else {
|
||||||
|
return link_to("payments/{$model->public_id}/edit", Utils::dateToString($model->payment_date))->toHtml();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -123,12 +127,11 @@ class PaymentDatatable extends EntityDatatable
|
|||||||
return "javascript:showRefundModal({$model->public_id}, '{$max_refund}', '{$formatted}', '{$symbol}')";
|
return "javascript:showRefundModal({$model->public_id}, '{$max_refund}', '{$formatted}', '{$symbol}')";
|
||||||
},
|
},
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]) && $model->payment_status_id >= PAYMENT_STATUS_COMPLETED &&
|
return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id])
|
||||||
$model->refunded < $model->amount &&
|
&& $model->payment_status_id >= PAYMENT_STATUS_COMPLETED
|
||||||
(
|
&& $model->refunded < $model->amount
|
||||||
($model->transaction_reference && in_array($model->gateway_id , static::$refundableGateways))
|
&& $model->transaction_reference
|
||||||
|| $model->payment_type_id == PAYMENT_TYPE_CREDIT
|
&& in_array($model->gateway_id , static::$refundableGateways);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
@ -58,7 +58,17 @@ class RecurringInvoiceDatatable extends EntityDatatable
|
|||||||
function ($model) {
|
function ($model) {
|
||||||
return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
|
return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
[
|
||||||
|
trans("texts.clone_invoice"),
|
||||||
|
function ($model) {
|
||||||
|
return URL::to("invoices/{$model->public_id}/clone");
|
||||||
|
},
|
||||||
|
function ($model) {
|
||||||
|
return Auth::user()->can('create', ENTITY_INVOICE);
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,9 @@ class TaskDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'created_at',
|
'created_at',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
|
if(!Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id])){
|
||||||
|
return Task::calcStartTime($model);
|
||||||
|
}
|
||||||
return link_to("tasks/{$model->public_id}/edit", Task::calcStartTime($model))->toHtml();
|
return link_to("tasks/{$model->public_id}/edit", Task::calcStartTime($model))->toHtml();
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -182,10 +182,21 @@ class BaseTransformer extends TransformerAbstract
|
|||||||
* @param $name
|
* @param $name
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
protected function getVendorId($name)
|
public function getVendorId($name)
|
||||||
{
|
{
|
||||||
$name = strtolower($name);
|
$name = strtolower($name);
|
||||||
return isset($this->maps[ENTITY_VENDOR][$name]) ? $this->maps[ENTITY_VENDOR][$name] : null;
|
return isset($this->maps[ENTITY_VENDOR][$name]) ? $this->maps[ENTITY_VENDOR][$name] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $name
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function getExpenseCategoryId($name)
|
||||||
|
{
|
||||||
|
$name = strtolower($name);
|
||||||
|
return isset($this->maps[ENTITY_EXPENSE_CATEGORY][$name]) ? $this->maps[ENTITY_EXPENSE_CATEGORY][$name] : null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ class ClientTransformer extends BaseTransformer
|
|||||||
'postal_code' => $this->getString($data, 'postal_code'),
|
'postal_code' => $this->getString($data, 'postal_code'),
|
||||||
'private_notes' => $this->getString($data, 'notes'),
|
'private_notes' => $this->getString($data, 'notes'),
|
||||||
'website' => $this->getString($data, 'website'),
|
'website' => $this->getString($data, 'website'),
|
||||||
|
'vat_number' => $this->getString($data, 'vat_number'),
|
||||||
'contacts' => [
|
'contacts' => [
|
||||||
[
|
[
|
||||||
'first_name' => $this->getString($data, 'first_name'),
|
'first_name' => $this->getString($data, 'first_name'),
|
||||||
|
28
app/Ninja/Import/CSV/ExpenseTransformer.php
Normal file
28
app/Ninja/Import/CSV/ExpenseTransformer.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php namespace App\Ninja\Import\CSV;
|
||||||
|
|
||||||
|
use App\Ninja\Import\BaseTransformer;
|
||||||
|
use League\Fractal\Resource\Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class InvoiceTransformer
|
||||||
|
*/
|
||||||
|
class ExpenseTransformer extends BaseTransformer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
* @return bool|Item
|
||||||
|
*/
|
||||||
|
public function transform($data)
|
||||||
|
{
|
||||||
|
return new Item($data, function ($data) {
|
||||||
|
return [
|
||||||
|
'amount' => isset($data->amount) ? (float) $data->amount : null,
|
||||||
|
'vendor_id' => isset($data->vendor) ? $this->getVendorId($data->vendor) : null,
|
||||||
|
'client_id' => isset($data->client) ? $this->getClientId($data->client) : null,
|
||||||
|
'expense_date' => isset($data->expense_date) ? date('Y-m-d', strtotime($data->expense_date)) : null,
|
||||||
|
'public_notes' => $this->getString($data, 'public_notes'),
|
||||||
|
'expense_category_id' => isset($data->expense_category) ? $this->getExpenseCategoryId($data->expense_category) : null,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
<?php namespace App\Ninja\Mailers;
|
<?php namespace App\Ninja\Mailers;
|
||||||
|
|
||||||
|
use Utils;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Mail;
|
use Mail;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
@ -112,6 +113,8 @@ class Mailer
|
|||||||
$invitation = $data['invitation'];
|
$invitation = $data['invitation'];
|
||||||
$invitation->email_error = $emailError;
|
$invitation->email_error = $emailError;
|
||||||
$invitation->save();
|
$invitation->save();
|
||||||
|
} elseif ( ! Utils::isNinja()) {
|
||||||
|
Utils::logError(Utils::getErrorString($exception));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $emailError;
|
return $emailError;
|
||||||
|
@ -2,16 +2,19 @@
|
|||||||
|
|
||||||
use URL;
|
use URL;
|
||||||
use Session;
|
use Session;
|
||||||
|
use Utils;
|
||||||
use Request;
|
use Request;
|
||||||
use Omnipay;
|
use Omnipay;
|
||||||
use Exception;
|
use Exception;
|
||||||
use CreditCard;
|
use CreditCard;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use App\Models\AccountGatewayToken;
|
use App\Models\AccountGatewayToken;
|
||||||
|
use App\Models\AccountGatewaySettings;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Models\PaymentMethod;
|
use App\Models\PaymentMethod;
|
||||||
use App\Models\Country;
|
use App\Models\Country;
|
||||||
|
use App\Models\GatewayType;
|
||||||
|
|
||||||
class BasePaymentDriver
|
class BasePaymentDriver
|
||||||
{
|
{
|
||||||
@ -119,6 +122,12 @@ class BasePaymentDriver
|
|||||||
|
|
||||||
$gateway = $this->accountGateway->gateway;
|
$gateway = $this->accountGateway->gateway;
|
||||||
|
|
||||||
|
if ( ! $this->meetsGatewayTypeLimits($this->gatewayType)) {
|
||||||
|
// The customer must have hacked the URL
|
||||||
|
Session::flash('error', trans('texts.limits_not_met'));
|
||||||
|
return redirect()->to('view/' . $this->invitation->invitation_key);
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->isGatewayType(GATEWAY_TYPE_TOKEN) || $gateway->is_offsite) {
|
if ($this->isGatewayType(GATEWAY_TYPE_TOKEN) || $gateway->is_offsite) {
|
||||||
if (Session::has('error')) {
|
if (Session::has('error')) {
|
||||||
Session::reflash();
|
Session::reflash();
|
||||||
@ -158,12 +167,14 @@ class BasePaymentDriver
|
|||||||
// check if a custom view exists for this provider
|
// check if a custom view exists for this provider
|
||||||
protected function paymentView()
|
protected function paymentView()
|
||||||
{
|
{
|
||||||
$file = sprintf('%s/views/payments/%s/%s.blade.php', resource_path(), $this->providerName(), $this->gatewayType);
|
$gatewayTypeAlias = GatewayType::getAliasFromId($this->gatewayType);
|
||||||
|
|
||||||
|
$file = sprintf('%s/views/payments/%s/%s.blade.php', resource_path(), $this->providerName(), $gatewayTypeAlias);
|
||||||
|
|
||||||
if (file_exists($file)) {
|
if (file_exists($file)) {
|
||||||
return sprintf('payments.%s/%s', $this->providerName(), $this->gatewayType);
|
return sprintf('payments.%s/%s', $this->providerName(), $gatewayTypeAlias);
|
||||||
} else {
|
} else {
|
||||||
return sprintf('payments.%s', $this->gatewayType);
|
return sprintf('payments.%s', $gatewayTypeAlias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,8 +253,22 @@ class BasePaymentDriver
|
|||||||
->wherePublicId($this->sourceId)
|
->wherePublicId($this->sourceId)
|
||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
}
|
}
|
||||||
} elseif ($this->shouldCreateToken()) {
|
|
||||||
$paymentMethod = $this->createToken();
|
if ( ! $this->meetsGatewayTypeLimits($paymentMethod->payment_type->gateway_type_id)) {
|
||||||
|
// The customer must have hacked the URL
|
||||||
|
Session::flash('error', trans('texts.limits_not_met'));
|
||||||
|
return redirect()->to('view/' . $this->invitation->invitation_key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($this->shouldCreateToken()) {
|
||||||
|
$paymentMethod = $this->createToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $this->meetsGatewayTypeLimits($this->gatewayType)) {
|
||||||
|
// The customer must have hacked the URL
|
||||||
|
Session::flash('error', trans('texts.limits_not_met'));
|
||||||
|
return redirect()->to('view/' . $this->invitation->invitation_key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isTwoStep()) {
|
if ($this->isTwoStep()) {
|
||||||
@ -323,7 +348,8 @@ class BasePaymentDriver
|
|||||||
protected function paymentDetails($paymentMethod = false)
|
protected function paymentDetails($paymentMethod = false)
|
||||||
{
|
{
|
||||||
$invoice = $this->invoice();
|
$invoice = $this->invoice();
|
||||||
$completeUrl = url('complete/' . $this->invitation->invitation_key . '/' . $this->gatewayType);
|
$gatewayTypeAlias = $this->gatewayType == GATEWAY_TYPE_TOKEN ? $this->gatewayType : GatewayType::getAliasFromId($this->gatewayType);
|
||||||
|
$completeUrl = url('complete/' . $this->invitation->invitation_key . '/' . $gatewayTypeAlias);
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'amount' => $invoice->getRequestedAmount(),
|
'amount' => $invoice->getRequestedAmount(),
|
||||||
@ -760,6 +786,10 @@ class BasePaymentDriver
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! $this->meetsGatewayTypeLimits($paymentMethod->payment_type->gateway_type_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$url = URL::to("/payment/{$this->invitation->invitation_key}/token/".$paymentMethod->public_id);
|
$url = URL::to("/payment/{$this->invitation->invitation_key}/token/".$paymentMethod->public_id);
|
||||||
|
|
||||||
if ($paymentMethod->payment_type_id == PAYMENT_TYPE_ACH) {
|
if ($paymentMethod->payment_type_id == PAYMENT_TYPE_ACH) {
|
||||||
@ -787,27 +817,68 @@ class BasePaymentDriver
|
|||||||
{
|
{
|
||||||
$links = [];
|
$links = [];
|
||||||
|
|
||||||
foreach ($this->gatewayTypes() as $gatewayType) {
|
foreach ($this->gatewayTypes() as $gatewayTypeId) {
|
||||||
if ($gatewayType === GATEWAY_TYPE_TOKEN) {
|
if ($gatewayTypeId === GATEWAY_TYPE_TOKEN) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! $this->meetsGatewayTypeLimits($gatewayTypeId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gatewayTypeAlias = GatewayType::getAliasFromId($gatewayTypeId);
|
||||||
|
|
||||||
|
if ($gatewayTypeId == GATEWAY_TYPE_CUSTOM) {
|
||||||
|
$url = "javascript:showCustomModal();";
|
||||||
|
$label = e($this->accountGateway->getConfigField('name'));
|
||||||
|
} else {
|
||||||
|
$url = $this->paymentUrl($gatewayTypeAlias);
|
||||||
|
$label = trans("texts.{$gatewayTypeAlias}");
|
||||||
|
}
|
||||||
|
|
||||||
$links[] = [
|
$links[] = [
|
||||||
'url' => $this->paymentUrl($gatewayType),
|
'gatewayTypeId' => $gatewayTypeId,
|
||||||
'label' => trans("texts.{$gatewayType}")
|
'url' => $url,
|
||||||
|
'label' => $label,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $links;
|
return $links;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function paymentUrl($gatewayType)
|
protected function meetsGatewayTypeLimits($gatewayTypeId)
|
||||||
|
{
|
||||||
|
if ( !$gatewayTypeId ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$accountGatewaySettings = AccountGatewaySettings::scope(false, $this->invitation->account_id)
|
||||||
|
->where('account_gateway_settings.gateway_type_id', '=', $gatewayTypeId)->first();
|
||||||
|
|
||||||
|
if ($accountGatewaySettings) {
|
||||||
|
$invoice = $this->invoice();
|
||||||
|
|
||||||
|
if ($accountGatewaySettings->min_limit !== null && $invoice->balance < $accountGatewaySettings->min_limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($accountGatewaySettings->max_limit !== null && $invoice->balance > $accountGatewaySettings->max_limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function paymentUrl($gatewayTypeAlias)
|
||||||
{
|
{
|
||||||
$account = $this->account();
|
$account = $this->account();
|
||||||
$url = URL::to("/payment/{$this->invitation->invitation_key}/{$gatewayType}");
|
$url = URL::to("/payment/{$this->invitation->invitation_key}/{$gatewayTypeAlias}");
|
||||||
|
|
||||||
|
$gatewayTypeId = GatewayType::getIdFromAlias($gatewayTypeAlias);
|
||||||
|
|
||||||
// PayPal doesn't allow being run in an iframe so we need to open in new tab
|
// PayPal doesn't allow being run in an iframe so we need to open in new tab
|
||||||
if ($gatewayType === GATEWAY_TYPE_PAYPAL) {
|
if ($gatewayTypeId === GATEWAY_TYPE_PAYPAL) {
|
||||||
$url .= '#braintree_paypal';
|
$url .= '#braintree_paypal';
|
||||||
|
|
||||||
if ($account->iframe_url) {
|
if ($account->iframe_url) {
|
||||||
|
12
app/Ninja/PaymentDrivers/CustomPaymentDriver.php
Normal file
12
app/Ninja/PaymentDrivers/CustomPaymentDriver.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php namespace App\Ninja\PaymentDrivers;
|
||||||
|
|
||||||
|
class CustomPaymentDriver extends BasePaymentDriver
|
||||||
|
{
|
||||||
|
public function gatewayTypes()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
GATEWAY_TYPE_CUSTOM
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -151,14 +151,17 @@ class StripePaymentDriver extends BasePaymentDriver
|
|||||||
protected function creatingPaymentMethod($paymentMethod)
|
protected function creatingPaymentMethod($paymentMethod)
|
||||||
{
|
{
|
||||||
$data = $this->tokenResponse;
|
$data = $this->tokenResponse;
|
||||||
|
$source = false;
|
||||||
|
|
||||||
if (!empty($data['object']) && ($data['object'] == 'card' || $data['object'] == 'bank_account')) {
|
if (!empty($data['object']) && ($data['object'] == 'card' || $data['object'] == 'bank_account')) {
|
||||||
$source = $data;
|
$source = $data;
|
||||||
} elseif (!empty($data['object']) && $data['object'] == 'customer') {
|
} elseif (!empty($data['object']) && $data['object'] == 'customer') {
|
||||||
$sources = !empty($data['sources']) ? $data['sources'] : $data['cards'];
|
$sources = !empty($data['sources']) ? $data['sources'] : $data['cards'];
|
||||||
$source = reset($sources['data']);
|
$source = reset($sources['data']);
|
||||||
} else {
|
} elseif (!empty($data['source'])) {
|
||||||
$source = !empty($data['source']) ? $data['source'] : $data['card'];
|
$source = $data['source'];
|
||||||
|
} elseif (!empty($data['card'])) {
|
||||||
|
$source = $data['card'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! $source) {
|
if ( ! $source) {
|
||||||
|
@ -23,22 +23,4 @@ class ClientPresenter extends EntityPresenter {
|
|||||||
|
|
||||||
return $account->formatMoney($client->paid_to_date, $client);
|
return $account->formatMoney($client->paid_to_date, $client);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function status()
|
|
||||||
{
|
|
||||||
$class = $text = '';
|
|
||||||
|
|
||||||
if ($this->entity->is_deleted) {
|
|
||||||
$class = 'danger';
|
|
||||||
$text = trans('texts.deleted');
|
|
||||||
} elseif ($this->entity->trashed()) {
|
|
||||||
$class = 'warning';
|
|
||||||
$text = trans('texts.archived');
|
|
||||||
} else {
|
|
||||||
$class = 'success';
|
|
||||||
$text = trans('texts.active');
|
|
||||||
}
|
|
||||||
|
|
||||||
return "<span class=\"label label-{$class}\">{$text}</span>";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,24 @@ class EntityPresenter extends Presenter
|
|||||||
return URL::to($link);
|
return URL::to($link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function statusLabel()
|
||||||
|
{
|
||||||
|
$class = $text = '';
|
||||||
|
|
||||||
|
if ($this->entity->is_deleted) {
|
||||||
|
$class = 'danger';
|
||||||
|
$text = trans('texts.deleted');
|
||||||
|
} elseif ($this->entity->trashed()) {
|
||||||
|
$class = 'warning';
|
||||||
|
$text = trans('texts.archived');
|
||||||
|
} else {
|
||||||
|
//$class = 'success';
|
||||||
|
//$text = trans('texts.active');
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<span style=\"font-size:13px\" class=\"label label-{$class}\">{$text}</span>";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
|
@ -24,12 +24,4 @@ class ExpensePresenter extends EntityPresenter
|
|||||||
return Utils::fromSqlDate($this->entity->expense_date);
|
return Utils::fromSqlDate($this->entity->expense_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function invoiced_amount()
|
|
||||||
{
|
|
||||||
return $this->entity->invoice_id ? $this->entity->convertedAmount() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,11 @@ class TaskPresenter extends EntityPresenter
|
|||||||
return $this->entity->user->getDisplayName();
|
return $this->entity->user->getDisplayName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function description()
|
||||||
|
{
|
||||||
|
return substr($this->entity->description, 0, 40) . (strlen($this->entity->description) > 40 ? '...' : '');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $account
|
* @param $account
|
||||||
* @return mixed
|
* @return mixed
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use Auth;
|
use Auth;
|
||||||
use Request;
|
use Request;
|
||||||
|
use Input;
|
||||||
use Session;
|
use Session;
|
||||||
use Utils;
|
use Utils;
|
||||||
use URL;
|
use URL;
|
||||||
@ -27,6 +28,11 @@ class AccountRepository
|
|||||||
public function create($firstName = '', $lastName = '', $email = '', $password = '')
|
public function create($firstName = '', $lastName = '', $email = '', $password = '')
|
||||||
{
|
{
|
||||||
$company = new Company();
|
$company = new Company();
|
||||||
|
$company->utm_source = Input::get('utm_source');
|
||||||
|
$company->utm_medium = Input::get('utm_medium');
|
||||||
|
$company->utm_campaign = Input::get('utm_campaign');
|
||||||
|
$company->utm_term = Input::get('utm_term');
|
||||||
|
$company->utm_content = Input::get('utm_content');
|
||||||
$company->save();
|
$company->save();
|
||||||
|
|
||||||
$account = new Account();
|
$account = new Account();
|
||||||
|
@ -74,6 +74,8 @@ class ActivityRepository
|
|||||||
->leftJoin('invoices', 'invoices.id', '=', 'activities.invoice_id')
|
->leftJoin('invoices', 'invoices.id', '=', 'activities.invoice_id')
|
||||||
->leftJoin('payments', 'payments.id', '=', 'activities.payment_id')
|
->leftJoin('payments', 'payments.id', '=', 'activities.payment_id')
|
||||||
->leftJoin('credits', 'credits.id', '=', 'activities.credit_id')
|
->leftJoin('credits', 'credits.id', '=', 'activities.credit_id')
|
||||||
|
->leftJoin('tasks', 'tasks.id', '=', 'activities.task_id')
|
||||||
|
->leftJoin('expenses', 'expenses.id', '=', 'activities.expense_id')
|
||||||
->where('clients.id', '=', $clientId)
|
->where('clients.id', '=', $clientId)
|
||||||
->where('contacts.is_primary', '=', 1)
|
->where('contacts.is_primary', '=', 1)
|
||||||
->whereNull('contacts.deleted_at')
|
->whereNull('contacts.deleted_at')
|
||||||
@ -102,7 +104,11 @@ class ActivityRepository
|
|||||||
'contacts.email as email',
|
'contacts.email as email',
|
||||||
'payments.transaction_reference as payment',
|
'payments.transaction_reference as payment',
|
||||||
'payments.amount as payment_amount',
|
'payments.amount as payment_amount',
|
||||||
'credits.amount as credit'
|
'credits.amount as credit',
|
||||||
|
'tasks.description as task_description',
|
||||||
|
'tasks.public_id as task_public_id',
|
||||||
|
'expenses.public_notes as expense_public_notes',
|
||||||
|
'expenses.public_id as expense_public_id'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ class ClientRepository extends BaseRepository
|
|||||||
->where('clients.account_id', '=', \Auth::user()->account_id)
|
->where('clients.account_id', '=', \Auth::user()->account_id)
|
||||||
->where('contacts.is_primary', '=', true)
|
->where('contacts.is_primary', '=', true)
|
||||||
->where('contacts.deleted_at', '=', null)
|
->where('contacts.deleted_at', '=', null)
|
||||||
|
//->whereRaw('(clients.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
|
||||||
->select(
|
->select(
|
||||||
DB::raw('COALESCE(clients.currency_id, accounts.currency_id) currency_id'),
|
DB::raw('COALESCE(clients.currency_id, accounts.currency_id) currency_id'),
|
||||||
DB::raw('COALESCE(clients.country_id, accounts.country_id) country_id'),
|
DB::raw('COALESCE(clients.country_id, accounts.country_id) country_id'),
|
||||||
@ -78,7 +79,10 @@ class ClientRepository extends BaseRepository
|
|||||||
$client = Client::createNew();
|
$client = Client::createNew();
|
||||||
} else {
|
} else {
|
||||||
$client = Client::scope($publicId)->with('contacts')->firstOrFail();
|
$client = Client::scope($publicId)->with('contacts')->firstOrFail();
|
||||||
\Log::warning('Entity not set in client repo save');
|
}
|
||||||
|
|
||||||
|
if ($client->is_deleted) {
|
||||||
|
return $client;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert currency code to id
|
// convert currency code to id
|
||||||
@ -107,7 +111,11 @@ class ClientRepository extends BaseRepository
|
|||||||
|
|
||||||
// If the primary is set ensure it's listed first
|
// If the primary is set ensure it's listed first
|
||||||
usort($contacts, function ($left, $right) {
|
usort($contacts, function ($left, $right) {
|
||||||
return (isset($right['is_primary']) ? $right['is_primary'] : 1) - (isset($left['is_primary']) ? $left['is_primary'] : 0);
|
if (isset($right['is_primary']) && isset($left['is_primary'])) {
|
||||||
|
return $right['is_primary'] - $left['is_primary'];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach ($contacts as $contact) {
|
foreach ($contacts as $contact) {
|
||||||
|
@ -58,6 +58,32 @@ class CreditRepository extends BaseRepository
|
|||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getClientDatatable($clientId)
|
||||||
|
{
|
||||||
|
$query = DB::table('credits')
|
||||||
|
->join('accounts', 'accounts.id', '=', 'credits.account_id')
|
||||||
|
->join('clients', 'clients.id', '=', 'credits.client_id')
|
||||||
|
->where('credits.client_id', '=', $clientId)
|
||||||
|
->where('clients.deleted_at', '=', null)
|
||||||
|
->where('credits.deleted_at', '=', null)
|
||||||
|
->where('credits.balance', '>', 0)
|
||||||
|
->select(
|
||||||
|
DB::raw('COALESCE(clients.currency_id, accounts.currency_id) currency_id'),
|
||||||
|
DB::raw('COALESCE(clients.country_id, accounts.country_id) country_id'),
|
||||||
|
'credits.amount',
|
||||||
|
'credits.balance',
|
||||||
|
'credits.credit_date'
|
||||||
|
);
|
||||||
|
|
||||||
|
$table = \Datatable::query($query)
|
||||||
|
->addColumn('credit_date', function ($model) { return Utils::fromSqlDate($model->credit_date); })
|
||||||
|
->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); })
|
||||||
|
->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); })
|
||||||
|
->make();
|
||||||
|
|
||||||
|
return $table;
|
||||||
|
}
|
||||||
|
|
||||||
public function save($input, $credit = null)
|
public function save($input, $credit = null)
|
||||||
{
|
{
|
||||||
$publicId = isset($data['public_id']) ? $data['public_id'] : false;
|
$publicId = isset($data['public_id']) ? $data['public_id'] : false;
|
||||||
|
@ -39,12 +39,14 @@ class DashboardRepository
|
|||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
$balance = 0;
|
||||||
$records = $this->rawChartData($entityType, $account, $groupBy, $startDate, $endDate, $currencyId);
|
$records = $this->rawChartData($entityType, $account, $groupBy, $startDate, $endDate, $currencyId);
|
||||||
|
|
||||||
array_map(function ($item) use (&$data, &$count, $groupBy) {
|
array_map(function ($item) use (&$data, &$count, &$balance, $groupBy) {
|
||||||
$data[$item->$groupBy] = $item->total;
|
$data[$item->$groupBy] = $item->total;
|
||||||
$count += $item->count;
|
$count += $item->count;
|
||||||
}, $records->get());
|
$balance += isset($item->balance) ? $item->balance : 0;
|
||||||
|
}, $records);
|
||||||
|
|
||||||
$padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month');
|
$padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month');
|
||||||
$endDate->modify('+1 '.$padding);
|
$endDate->modify('+1 '.$padding);
|
||||||
@ -84,9 +86,9 @@ class DashboardRepository
|
|||||||
if ($entityType == ENTITY_INVOICE) {
|
if ($entityType == ENTITY_INVOICE) {
|
||||||
$totals->invoices = array_sum($data);
|
$totals->invoices = array_sum($data);
|
||||||
$totals->average = $count ? round($totals->invoices / $count, 2) : 0;
|
$totals->average = $count ? round($totals->invoices / $count, 2) : 0;
|
||||||
|
$totals->balance = $balance;
|
||||||
} elseif ($entityType == ENTITY_PAYMENT) {
|
} elseif ($entityType == ENTITY_PAYMENT) {
|
||||||
$totals->revenue = array_sum($data);
|
$totals->revenue = array_sum($data);
|
||||||
$totals->balance = $totals->invoices - $totals->revenue;
|
|
||||||
} elseif ($entityType == ENTITY_EXPENSE) {
|
} elseif ($entityType == ENTITY_EXPENSE) {
|
||||||
//$totals->profit = $totals->revenue - array_sum($data);
|
//$totals->profit = $totals->revenue - array_sum($data);
|
||||||
$totals->expenses = array_sum($data);
|
$totals->expenses = array_sum($data);
|
||||||
@ -106,6 +108,10 @@ class DashboardRepository
|
|||||||
|
|
||||||
private function rawChartData($entityType, $account, $groupBy, $startDate, $endDate, $currencyId)
|
private function rawChartData($entityType, $account, $groupBy, $startDate, $endDate, $currencyId)
|
||||||
{
|
{
|
||||||
|
if ( ! in_array($groupBy, ['DAYOFYEAR', 'WEEK', 'MONTH'])) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
$accountId = $account->id;
|
$accountId = $account->id;
|
||||||
$currencyId = intval($currencyId);
|
$currencyId = intval($currencyId);
|
||||||
$timeframe = 'concat(YEAR('.$entityType.'_date), '.$groupBy.'('.$entityType.'_date))';
|
$timeframe = 'concat(YEAR('.$entityType.'_date), '.$groupBy.'('.$entityType.'_date))';
|
||||||
@ -128,7 +134,7 @@ class DashboardRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($entityType == ENTITY_INVOICE) {
|
if ($entityType == ENTITY_INVOICE) {
|
||||||
$records->select(DB::raw('sum(invoices.amount) as total, count(invoices.id) as count, '.$timeframe.' as '.$groupBy))
|
$records->select(DB::raw('sum(invoices.amount) as total, sum(invoices.balance) as balance, count(invoices.id) as count, '.$timeframe.' as '.$groupBy))
|
||||||
->where('invoice_type_id', '=', INVOICE_TYPE_STANDARD)
|
->where('invoice_type_id', '=', INVOICE_TYPE_STANDARD)
|
||||||
->where('is_recurring', '=', false);
|
->where('is_recurring', '=', false);
|
||||||
} elseif ($entityType == ENTITY_PAYMENT) {
|
} elseif ($entityType == ENTITY_PAYMENT) {
|
||||||
@ -137,10 +143,10 @@ class DashboardRepository
|
|||||||
->where('invoices.is_deleted', '=', false)
|
->where('invoices.is_deleted', '=', false)
|
||||||
->whereNotIn('payment_status_id', [PAYMENT_STATUS_VOIDED, PAYMENT_STATUS_FAILED]);
|
->whereNotIn('payment_status_id', [PAYMENT_STATUS_VOIDED, PAYMENT_STATUS_FAILED]);
|
||||||
} elseif ($entityType == ENTITY_EXPENSE) {
|
} elseif ($entityType == ENTITY_EXPENSE) {
|
||||||
$records->select(DB::raw('sum(expenses.amount) as total, count(expenses.id) as count, '.$timeframe.' as '.$groupBy));
|
$records->select(DB::raw('sum(expenses.amount + (expenses.amount * expenses.tax_rate1 / 100) + (expenses.amount * expenses.tax_rate2 / 100)) as total, count(expenses.id) as count, '.$timeframe.' as '.$groupBy));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $records;
|
return $records->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function totals($accountId, $userId, $viewAll)
|
public function totals($accountId, $userId, $viewAll)
|
||||||
@ -175,29 +181,39 @@ class DashboardRepository
|
|||||||
return $metrics->groupBy('accounts.id')->first();
|
return $metrics->groupBy('accounts.id')->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function paidToDate($accountId, $userId, $viewAll)
|
public function paidToDate($account, $userId, $viewAll)
|
||||||
{
|
{
|
||||||
|
$accountId = $account->id;
|
||||||
$select = DB::raw(
|
$select = DB::raw(
|
||||||
'SUM('.DB::getQueryGrammar()->wrap('clients.paid_to_date', true).') as value,'
|
'SUM('.DB::getQueryGrammar()->wrap('payments.amount', true).' - '.DB::getQueryGrammar()->wrap('payments.refunded', true).') as value,'
|
||||||
.DB::getQueryGrammar()->wrap('clients.currency_id', true).' as currency_id'
|
.DB::getQueryGrammar()->wrap('clients.currency_id', true).' as currency_id'
|
||||||
);
|
);
|
||||||
$paidToDate = DB::table('accounts')
|
$paidToDate = DB::table('payments')
|
||||||
->select($select)
|
->select($select)
|
||||||
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
|
->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id')
|
||||||
->where('accounts.id', '=', $accountId)
|
->leftJoin('clients', 'clients.id', '=', 'invoices.client_id')
|
||||||
->where('clients.is_deleted', '=', false);
|
->where('payments.account_id', '=', $accountId)
|
||||||
|
->where('clients.is_deleted', '=', false)
|
||||||
|
->where('invoices.is_deleted', '=', false)
|
||||||
|
->whereNotIn('payments.payment_status_id', [PAYMENT_STATUS_VOIDED, PAYMENT_STATUS_FAILED]);
|
||||||
|
|
||||||
if (!$viewAll){
|
if (!$viewAll){
|
||||||
$paidToDate = $paidToDate->where('clients.user_id', '=', $userId);
|
$paidToDate->where('invoices.user_id', '=', $userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $paidToDate->groupBy('accounts.id')
|
if ($account->financial_year_start) {
|
||||||
->groupBy(DB::raw('CASE WHEN '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' IS NULL THEN CASE WHEN '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' IS NULL THEN 1 ELSE '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' END ELSE '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' END'))
|
$yearStart = str_replace('2000', date('Y'), $account->financial_year_start);
|
||||||
|
$paidToDate->where('payments.payment_date', '>=', $yearStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $paidToDate->groupBy('payments.account_id')
|
||||||
|
->groupBy(DB::raw('CASE WHEN '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' IS NULL THEN '.($account->currency_id ?: DEFAULT_CURRENCY).' ELSE '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' END'))
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function averages($accountId, $userId, $viewAll)
|
public function averages($account, $userId, $viewAll)
|
||||||
{
|
{
|
||||||
|
$accountId = $account->id;
|
||||||
$select = DB::raw(
|
$select = DB::raw(
|
||||||
'AVG('.DB::getQueryGrammar()->wrap('invoices.amount', true).') as invoice_avg, '
|
'AVG('.DB::getQueryGrammar()->wrap('invoices.amount', true).') as invoice_avg, '
|
||||||
.DB::getQueryGrammar()->wrap('clients.currency_id', true).' as currency_id'
|
.DB::getQueryGrammar()->wrap('clients.currency_id', true).' as currency_id'
|
||||||
@ -213,7 +229,12 @@ class DashboardRepository
|
|||||||
->where('invoices.is_recurring', '=', false);
|
->where('invoices.is_recurring', '=', false);
|
||||||
|
|
||||||
if (!$viewAll){
|
if (!$viewAll){
|
||||||
$averageInvoice = $averageInvoice->where('invoices.user_id', '=', $userId);
|
$averageInvoice->where('invoices.user_id', '=', $userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($account->financial_year_start) {
|
||||||
|
$yearStart = str_replace('2000', date('Y'), $account->financial_year_start);
|
||||||
|
$averageInvoice->where('invoices.invoice_date', '>=', $yearStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $averageInvoice->groupBy('accounts.id')
|
return $averageInvoice->groupBy('accounts.id')
|
||||||
@ -252,7 +273,7 @@ class DashboardRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $activities->orderBy('activities.created_at', 'desc')
|
return $activities->orderBy('activities.created_at', 'desc')
|
||||||
->with('client.contacts', 'user', 'invoice', 'payment', 'credit', 'account', 'task')
|
->with('client.contacts', 'user', 'invoice', 'payment', 'credit', 'account', 'task', 'expense', 'contact')
|
||||||
->take(50)
|
->take(50)
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
@ -335,8 +356,12 @@ class DashboardRepository
|
|||||||
|
|
||||||
public function expenses($accountId, $userId, $viewAll)
|
public function expenses($accountId, $userId, $viewAll)
|
||||||
{
|
{
|
||||||
|
$amountField = DB::getQueryGrammar()->wrap('expenses.amount', true);
|
||||||
|
$taxRate1Field = DB::getQueryGrammar()->wrap('expenses.tax_rate1', true);
|
||||||
|
$taxRate2Field = DB::getQueryGrammar()->wrap('expenses.tax_rate2', true);
|
||||||
|
|
||||||
$select = DB::raw(
|
$select = DB::raw(
|
||||||
'SUM('.DB::getQueryGrammar()->wrap('expenses.amount', true).') as value,'
|
"SUM({$amountField} + ({$amountField} * {$taxRate1Field} / 100) + ({$amountField} * {$taxRate2Field} / 100)) as value,"
|
||||||
.DB::getQueryGrammar()->wrap('expenses.expense_currency_id', true).' as currency_id'
|
.DB::getQueryGrammar()->wrap('expenses.expense_currency_id', true).' as currency_id'
|
||||||
);
|
);
|
||||||
$paidToDate = DB::table('accounts')
|
$paidToDate = DB::table('accounts')
|
||||||
|
@ -12,6 +12,11 @@ class ExpenseCategoryRepository extends BaseRepository
|
|||||||
return 'App\Models\ExpenseCategory';
|
return 'App\Models\ExpenseCategory';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function all()
|
||||||
|
{
|
||||||
|
return ExpenseCategory::scope()->get();
|
||||||
|
}
|
||||||
|
|
||||||
public function find($filter = null)
|
public function find($filter = null)
|
||||||
{
|
{
|
||||||
$query = DB::table('expense_categories')
|
$query = DB::table('expense_categories')
|
||||||
|
@ -76,6 +76,8 @@ class ExpenseRepository extends BaseRepository
|
|||||||
'expenses.expense_currency_id',
|
'expenses.expense_currency_id',
|
||||||
'expenses.invoice_currency_id',
|
'expenses.invoice_currency_id',
|
||||||
'expenses.user_id',
|
'expenses.user_id',
|
||||||
|
'expenses.tax_rate1',
|
||||||
|
'expenses.tax_rate2',
|
||||||
'expense_categories.name as category',
|
'expense_categories.name as category',
|
||||||
'invoices.public_id as invoice_public_id',
|
'invoices.public_id as invoice_public_id',
|
||||||
'invoices.user_id as invoice_user_id',
|
'invoices.user_id as invoice_user_id',
|
||||||
@ -118,20 +120,24 @@ class ExpenseRepository extends BaseRepository
|
|||||||
// do nothing
|
// do nothing
|
||||||
} elseif ($publicId) {
|
} elseif ($publicId) {
|
||||||
$expense = Expense::scope($publicId)->firstOrFail();
|
$expense = Expense::scope($publicId)->firstOrFail();
|
||||||
\Log::warning('Entity not set in expense repo save');
|
if (Utils::isNinjaDev()) {
|
||||||
|
\Log::warning('Entity not set in expense repo save');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$expense = Expense::createNew();
|
$expense = Expense::createNew();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($expense->is_deleted) {
|
||||||
|
return $expense;
|
||||||
|
}
|
||||||
|
|
||||||
// First auto fill
|
// First auto fill
|
||||||
$expense->fill($input);
|
$expense->fill($input);
|
||||||
|
|
||||||
$expense->expense_date = Utils::toSqlDate($input['expense_date']);
|
if (isset($input['expense_date'])) {
|
||||||
|
$expense->expense_date = Utils::toSqlDate($input['expense_date']);
|
||||||
if (isset($input['private_notes'])) {
|
|
||||||
$expense->private_notes = trim($input['private_notes']);
|
|
||||||
}
|
}
|
||||||
$expense->public_notes = trim($input['public_notes']);
|
|
||||||
$expense->should_be_invoiced = isset($input['should_be_invoiced']) && floatval($input['should_be_invoiced']) || $expense->client_id ? true : false;
|
$expense->should_be_invoiced = isset($input['should_be_invoiced']) && floatval($input['should_be_invoiced']) || $expense->client_id ? true : false;
|
||||||
|
|
||||||
if ( ! $expense->expense_currency_id) {
|
if ( ! $expense->expense_currency_id) {
|
||||||
@ -143,7 +149,9 @@ class ExpenseRepository extends BaseRepository
|
|||||||
|
|
||||||
$rate = isset($input['exchange_rate']) ? Utils::parseFloat($input['exchange_rate']) : 1;
|
$rate = isset($input['exchange_rate']) ? Utils::parseFloat($input['exchange_rate']) : 1;
|
||||||
$expense->exchange_rate = round($rate, 4);
|
$expense->exchange_rate = round($rate, 4);
|
||||||
$expense->amount = round(Utils::parseFloat($input['amount']), 2);
|
if (isset($input['amount'])) {
|
||||||
|
$expense->amount = round(Utils::parseFloat($input['amount']), 2);
|
||||||
|
}
|
||||||
|
|
||||||
$expense->save();
|
$expense->save();
|
||||||
|
|
||||||
@ -173,27 +181,4 @@ class ExpenseRepository extends BaseRepository
|
|||||||
|
|
||||||
return $expense;
|
return $expense;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bulk($ids, $action)
|
|
||||||
{
|
|
||||||
$expenses = Expense::withTrashed()->scope($ids)->get();
|
|
||||||
|
|
||||||
foreach ($expenses as $expense) {
|
|
||||||
if ($action == 'restore') {
|
|
||||||
$expense->restore();
|
|
||||||
|
|
||||||
$expense->is_deleted = false;
|
|
||||||
$expense->save();
|
|
||||||
} else {
|
|
||||||
if ($action == 'delete') {
|
|
||||||
$expense->is_deleted = true;
|
|
||||||
$expense->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
$expense->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count($tasks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ class InvoiceRepository extends BaseRepository
|
|||||||
->where('contacts.deleted_at', '=', null)
|
->where('contacts.deleted_at', '=', null)
|
||||||
->where('invoices.is_recurring', '=', false)
|
->where('invoices.is_recurring', '=', false)
|
||||||
->where('contacts.is_primary', '=', true)
|
->where('contacts.is_primary', '=', true)
|
||||||
|
//->whereRaw('(clients.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
|
||||||
->select(
|
->select(
|
||||||
DB::raw('COALESCE(clients.currency_id, accounts.currency_id) currency_id'),
|
DB::raw('COALESCE(clients.currency_id, accounts.currency_id) currency_id'),
|
||||||
DB::raw('COALESCE(clients.country_id, accounts.country_id) country_id'),
|
DB::raw('COALESCE(clients.country_id, accounts.country_id) country_id'),
|
||||||
@ -280,7 +281,13 @@ class InvoiceRepository extends BaseRepository
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$invoice = Invoice::scope($publicId)->firstOrFail();
|
$invoice = Invoice::scope($publicId)->firstOrFail();
|
||||||
\Log::warning('Entity not set in invoice repo save');
|
if (Utils::isNinjaDev()) {
|
||||||
|
\Log::warning('Entity not set in invoice repo save');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($invoice->is_deleted) {
|
||||||
|
return $invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice->fill($data);
|
$invoice->fill($data);
|
||||||
@ -306,9 +313,6 @@ class InvoiceRepository extends BaseRepository
|
|||||||
if (isset($data['is_amount_discount'])) {
|
if (isset($data['is_amount_discount'])) {
|
||||||
$invoice->is_amount_discount = $data['is_amount_discount'] ? true : false;
|
$invoice->is_amount_discount = $data['is_amount_discount'] ? true : false;
|
||||||
}
|
}
|
||||||
if (isset($data['partial'])) {
|
|
||||||
$invoice->partial = round(Utils::parseFloat($data['partial']), 2);
|
|
||||||
}
|
|
||||||
if (isset($data['invoice_date_sql'])) {
|
if (isset($data['invoice_date_sql'])) {
|
||||||
$invoice->invoice_date = $data['invoice_date_sql'];
|
$invoice->invoice_date = $data['invoice_date_sql'];
|
||||||
} elseif (isset($data['invoice_date'])) {
|
} elseif (isset($data['invoice_date'])) {
|
||||||
@ -477,6 +481,10 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$invoice->balance = $total;
|
$invoice->balance = $total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($data['partial'])) {
|
||||||
|
$invoice->partial = max(0,min(round(Utils::parseFloat($data['partial']), 2), $invoice->balance));
|
||||||
|
}
|
||||||
|
|
||||||
$invoice->amount = $total;
|
$invoice->amount = $total;
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
|
|
||||||
@ -653,6 +661,9 @@ class InvoiceRepository extends BaseRepository
|
|||||||
if ($quotePublicId) {
|
if ($quotePublicId) {
|
||||||
$clone->invoice_type_id = INVOICE_TYPE_STANDARD;
|
$clone->invoice_type_id = INVOICE_TYPE_STANDARD;
|
||||||
$clone->quote_id = $quotePublicId;
|
$clone->quote_id = $quotePublicId;
|
||||||
|
if ($account->invoice_terms) {
|
||||||
|
$clone->terms = $account->invoice_terms;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$clone->save();
|
$clone->save();
|
||||||
|
@ -150,11 +150,17 @@ class PaymentRepository extends BaseRepository
|
|||||||
// do nothing
|
// do nothing
|
||||||
} elseif ($publicId) {
|
} elseif ($publicId) {
|
||||||
$payment = Payment::scope($publicId)->firstOrFail();
|
$payment = Payment::scope($publicId)->firstOrFail();
|
||||||
\Log::warning('Entity not set in payment repo save');
|
if (Utils::isNinjaDev()) {
|
||||||
|
\Log::warning('Entity not set in payment repo save');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$payment = Payment::createNew();
|
$payment = Payment::createNew();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($payment->is_deleted) {
|
||||||
|
return $payment;
|
||||||
|
}
|
||||||
|
|
||||||
$paymentTypeId = false;
|
$paymentTypeId = false;
|
||||||
if (isset($input['payment_type_id'])) {
|
if (isset($input['payment_type_id'])) {
|
||||||
$paymentTypeId = $input['payment_type_id'] ? $input['payment_type_id'] : null;
|
$paymentTypeId = $input['payment_type_id'] ? $input['payment_type_id'] : null;
|
||||||
|
@ -17,15 +17,14 @@ class ProductRepository extends BaseRepository
|
|||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function find($accountId)
|
public function find($accountId, $filter = null)
|
||||||
{
|
{
|
||||||
return DB::table('products')
|
$query = DB::table('products')
|
||||||
->leftJoin('tax_rates', function($join) {
|
->leftJoin('tax_rates', function($join) {
|
||||||
$join->on('tax_rates.id', '=', 'products.default_tax_rate_id')
|
$join->on('tax_rates.id', '=', 'products.default_tax_rate_id')
|
||||||
->whereNull('tax_rates.deleted_at');
|
->whereNull('tax_rates.deleted_at');
|
||||||
})
|
})
|
||||||
->where('products.account_id', '=', $accountId)
|
->where('products.account_id', '=', $accountId)
|
||||||
->where('products.deleted_at', '=', null)
|
|
||||||
->select(
|
->select(
|
||||||
'products.public_id',
|
'products.public_id',
|
||||||
'products.product_key',
|
'products.product_key',
|
||||||
@ -35,6 +34,19 @@ class ProductRepository extends BaseRepository
|
|||||||
'tax_rates.rate as tax_rate',
|
'tax_rates.rate as tax_rate',
|
||||||
'products.deleted_at'
|
'products.deleted_at'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($filter) {
|
||||||
|
$query->where(function ($query) use ($filter) {
|
||||||
|
$query->where('products.product_key', 'like', '%'.$filter.'%')
|
||||||
|
->orWhere('products.notes', 'like', '%'.$filter.'%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!\Session::get('show_trash:product')) {
|
||||||
|
$query->where('products.deleted_at', '=', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save($data, $product = null)
|
public function save($data, $product = null)
|
||||||
|
@ -5,8 +5,13 @@ use Session;
|
|||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
|
|
||||||
class TaskRepository
|
class TaskRepository extends BaseRepository
|
||||||
{
|
{
|
||||||
|
public function getClassName()
|
||||||
|
{
|
||||||
|
return 'App\Models\Task';
|
||||||
|
}
|
||||||
|
|
||||||
public function find($clientPublicId = null, $filter = null)
|
public function find($clientPublicId = null, $filter = null)
|
||||||
{
|
{
|
||||||
$query = \DB::table('tasks')
|
$query = \DB::table('tasks')
|
||||||
@ -67,12 +72,15 @@ class TaskRepository
|
|||||||
if ($task) {
|
if ($task) {
|
||||||
// do nothing
|
// do nothing
|
||||||
} elseif ($publicId) {
|
} elseif ($publicId) {
|
||||||
$task = Task::scope($publicId)->firstOrFail();
|
$task = Task::scope($publicId)->withTrashed()->firstOrFail();
|
||||||
\Log::warning('Entity not set in task repo save');
|
|
||||||
} else {
|
} else {
|
||||||
$task = Task::createNew();
|
$task = Task::createNew();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($task->is_deleted) {
|
||||||
|
return $task;
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($data['client']) && $data['client']) {
|
if (isset($data['client']) && $data['client']) {
|
||||||
$task->client_id = Client::getPrivateId($data['client']);
|
$task->client_id = Client::getPrivateId($data['client']);
|
||||||
}
|
}
|
||||||
@ -109,26 +117,4 @@ class TaskRepository
|
|||||||
return $task;
|
return $task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bulk($ids, $action)
|
|
||||||
{
|
|
||||||
$tasks = Task::withTrashed()->scope($ids)->get();
|
|
||||||
|
|
||||||
foreach ($tasks as $task) {
|
|
||||||
if ($action == 'restore') {
|
|
||||||
$task->restore();
|
|
||||||
|
|
||||||
$task->is_deleted = false;
|
|
||||||
$task->save();
|
|
||||||
} else {
|
|
||||||
if ($action == 'delete') {
|
|
||||||
$task->is_deleted = true;
|
|
||||||
$task->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
$task->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count($tasks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php namespace App\Ninja\Repositories;
|
<?php namespace App\Ninja\Repositories;
|
||||||
|
|
||||||
|
use Utils;
|
||||||
use DB;
|
use DB;
|
||||||
use App\Models\Vendor;
|
use App\Models\Vendor;
|
||||||
|
|
||||||
@ -70,7 +71,13 @@ class VendorRepository extends BaseRepository
|
|||||||
$vendor = Vendor::createNew();
|
$vendor = Vendor::createNew();
|
||||||
} else {
|
} else {
|
||||||
$vendor = Vendor::scope($publicId)->with('vendor_contacts')->firstOrFail();
|
$vendor = Vendor::scope($publicId)->with('vendor_contacts')->firstOrFail();
|
||||||
\Log::warning('Entity not set in vendor repo save');
|
if (Utils::isNinjaDev()) {
|
||||||
|
\Log::warning('Entity not set in vendor repo save');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($vendor->is_deleted) {
|
||||||
|
return $vendor;
|
||||||
}
|
}
|
||||||
|
|
||||||
$vendor->fill($data);
|
$vendor->fill($data);
|
||||||
@ -78,12 +85,22 @@ class VendorRepository extends BaseRepository
|
|||||||
|
|
||||||
$first = true;
|
$first = true;
|
||||||
$vendorcontacts = isset($data['vendor_contact']) ? [$data['vendor_contact']] : $data['vendor_contacts'];
|
$vendorcontacts = isset($data['vendor_contact']) ? [$data['vendor_contact']] : $data['vendor_contacts'];
|
||||||
|
$vendorcontactIds = [];
|
||||||
|
|
||||||
foreach ($vendorcontacts as $vendorcontact) {
|
foreach ($vendorcontacts as $vendorcontact) {
|
||||||
$vendorcontact = $vendor->addVendorContact($vendorcontact, $first);
|
$vendorcontact = $vendor->addVendorContact($vendorcontact, $first);
|
||||||
|
$vendorcontactIds[] = $vendorcontact->public_id;
|
||||||
$first = false;
|
$first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! $vendor->wasRecentlyCreated) {
|
||||||
|
foreach ($vendor->vendor_contacts as $contact) {
|
||||||
|
if (!in_array($contact->public_id, $vendorcontactIds)) {
|
||||||
|
$contact->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $vendor;
|
return $vendor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ class ActivityTransformer extends EntityTransformer
|
|||||||
protected $availableIncludes = [ ];
|
protected $availableIncludes = [ ];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Client $client
|
* @param Activity $activity
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function transform(Activity $activity)
|
public function transform(Activity $activity)
|
||||||
@ -29,7 +29,10 @@ class ActivityTransformer extends EntityTransformer
|
|||||||
'invoice_id' => $activity->invoice ? $activity->invoice->public_id : null,
|
'invoice_id' => $activity->invoice ? $activity->invoice->public_id : null,
|
||||||
'payment_id' => $activity->payment ? $activity->payment->public_id : null,
|
'payment_id' => $activity->payment ? $activity->payment->public_id : null,
|
||||||
'credit_id' => $activity->credit ? $activity->credit->public_id : null,
|
'credit_id' => $activity->credit ? $activity->credit->public_id : null,
|
||||||
'updated_at' => $this->getTimestamp($activity->updated_at)
|
'updated_at' => $this->getTimestamp($activity->updated_at),
|
||||||
|
'expense_id' => $activity->expense_id ? $activity->expense->public_id : null,
|
||||||
|
'is_system' => (bool) $activity->is_system ? $activity->is_system : null,
|
||||||
|
'contact_id' => $activity->contact_id ? $activity->contact->public_id : null
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,16 @@ class ExpenseTransformer extends EntityTransformer
|
|||||||
'transaction_id' => $expense->transaction_id,
|
'transaction_id' => $expense->transaction_id,
|
||||||
'bank_id' => $expense->bank_id,
|
'bank_id' => $expense->bank_id,
|
||||||
'expense_currency_id' => (int) $expense->expense_currency_id,
|
'expense_currency_id' => (int) $expense->expense_currency_id,
|
||||||
|
'expense_category_id' => (int) $expense->expense_category_id,
|
||||||
'amount' => (float) $expense->amount,
|
'amount' => (float) $expense->amount,
|
||||||
'expense_date' => $expense->expense_date,
|
'expense_date' => $expense->expense_date,
|
||||||
'exchange_rate' => (float) $expense->exchange_rate,
|
'exchange_rate' => (float) $expense->exchange_rate,
|
||||||
'invoice_currency_id' => (int) $expense->invoice_currency_id,
|
'invoice_currency_id' => (int) $expense->invoice_currency_id,
|
||||||
'is_deleted' => (bool) $expense->is_deleted,
|
'is_deleted' => (bool) $expense->is_deleted,
|
||||||
|
'tax_name1' => $expense->tax_name1,
|
||||||
|
'tax_name2' => $expense->tax_name2,
|
||||||
|
'tax_rate1' => $expense->tax_rate1,
|
||||||
|
'tax_rate2' => $expense->tax_rate2,
|
||||||
'client_id' => $this->client ? $this->client->public_id : (isset($expense->client->public_id) ? (int) $expense->client->public_id : null),
|
'client_id' => $this->client ? $this->client->public_id : (isset($expense->client->public_id) ? (int) $expense->client->public_id : null),
|
||||||
'invoice_id' => isset($expense->invoice->public_id) ? (int) $expense->invoice->public_id : null,
|
'invoice_id' => isset($expense->invoice->public_id) ? (int) $expense->invoice->public_id : null,
|
||||||
'vendor_id' => isset($expense->vendor->public_id) ? (int) $expense->vendor->public_id : null,
|
'vendor_id' => isset($expense->vendor->public_id) ? (int) $expense->vendor->public_id : null,
|
||||||
|
@ -31,6 +31,7 @@ class UserAccountTransformer extends EntityTransformer
|
|||||||
'name' => $user->account->present()->name,
|
'name' => $user->account->present()->name,
|
||||||
'token' => $user->account->getToken($user->id, $this->tokenName),
|
'token' => $user->account->getToken($user->id, $this->tokenName),
|
||||||
'default_url' => SITE_URL,
|
'default_url' => SITE_URL,
|
||||||
|
'plan' => $user->account->company->plan,
|
||||||
'logo' => $user->account->logo,
|
'logo' => $user->account->logo,
|
||||||
'logo_url' => $user->account->getLogoURL(),
|
'logo_url' => $user->account->getLogoURL(),
|
||||||
];
|
];
|
||||||
|
@ -23,7 +23,7 @@ class AccountGatewayPolicy extends EntityPolicy
|
|||||||
* @param User $user
|
* @param User $user
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function create(User $user) {
|
public static function create(User $user, $item) {
|
||||||
return $user->hasPermission('admin');
|
return $user->hasPermission('admin');
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,7 +22,7 @@ class BankAccountPolicy extends EntityPolicy
|
|||||||
* @param User $user
|
* @param User $user
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function create(User $user) {
|
public static function create(User $user, $item) {
|
||||||
return $user->hasPermission('admin');
|
return $user->hasPermission('admin');
|
||||||
}
|
}
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user