mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-08 13:44:31 -04:00
Merge pull request #4239 from turbo124/v5-develop
Version Bump + linking tasks and expenses to invoices
This commit is contained in:
commit
959e4936cd
1
.env.ci
1
.env.ci
@ -19,3 +19,4 @@ DB_HOST=127.0.0.1
|
|||||||
NINJA_ENVIRONMENT=hosted
|
NINJA_ENVIRONMENT=hosted
|
||||||
COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}'
|
COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}'
|
||||||
TRAVIS=true
|
TRAVIS=true
|
||||||
|
API_SECRET=superdoopersecrethere
|
||||||
|
@ -55,10 +55,5 @@ NINJA_ENVIRONMENT=selfhost
|
|||||||
PHANTOMJS_KEY='a-demo-key-with-low-quota-per-ip-address'
|
PHANTOMJS_KEY='a-demo-key-with-low-quota-per-ip-address'
|
||||||
PHANTOMJS_SECRET=
|
PHANTOMJS_SECRET=
|
||||||
|
|
||||||
SELF_UPDATER_REPO_VENDOR = invoiceninja
|
|
||||||
SELF_UPDATER_REPO_NAME = invoiceninja
|
|
||||||
SELF_UPDATER_USE_BRANCH = v2
|
|
||||||
SELF_UPDATER_MAILTO_ADDRESS = user@example.com
|
|
||||||
SELF_UPDATER_MAILTO_NAME = "John Doe"
|
|
||||||
COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}'
|
COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}'
|
||||||
SENTRY_LARAVEL_DSN=https://cc7e8e2c678041689e53e409b7dba236@sentry.invoicing.co/5
|
SENTRY_LARAVEL_DSN=https://cc7e8e2c678041689e53e409b7dba236@sentry.invoicing.co/5
|
@ -1 +1 @@
|
|||||||
5.0.22
|
5.0.23
|
||||||
|
@ -507,7 +507,7 @@ class CompanySettings extends BaseSettings
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides class defaults on init.
|
* Provides class defaults on init.
|
||||||
* @return object
|
* @return stdClass
|
||||||
*/
|
*/
|
||||||
public static function defaults(): stdClass
|
public static function defaults(): stdClass
|
||||||
{
|
{
|
||||||
|
@ -149,7 +149,7 @@ class FreeCompanySettings extends BaseSettings
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides class defaults on init.
|
* Provides class defaults on init.
|
||||||
* @return object
|
* @return stdClass
|
||||||
*/
|
*/
|
||||||
public static function defaults(): stdClass
|
public static function defaults(): stdClass
|
||||||
{
|
{
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace App\Exceptions;
|
namespace App\Exceptions;
|
||||||
|
|
||||||
use App\Exceptions\GenericPaymentDriverFailure;
|
use App\Exceptions\GenericPaymentDriverFailure;
|
||||||
|
use App\Models\Account;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
use Illuminate\Auth\AuthenticationException;
|
use Illuminate\Auth\AuthenticationException;
|
||||||
@ -27,14 +28,14 @@ use Illuminate\Support\Arr;
|
|||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use PDOException;
|
use PDOException;
|
||||||
|
use Sentry\State\Scope;
|
||||||
use Swift_TransportException;
|
use Swift_TransportException;
|
||||||
use Symfony\Component\Console\Exception\CommandNotFoundException;
|
use Symfony\Component\Console\Exception\CommandNotFoundException;
|
||||||
use function Sentry\configureScope;
|
|
||||||
use Sentry\State\Scope;
|
|
||||||
use Symfony\Component\Debug\Exception\FatalThrowableError;
|
use Symfony\Component\Debug\Exception\FatalThrowableError;
|
||||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
use function Sentry\configureScope;
|
||||||
|
|
||||||
class Handler extends ExceptionHandler
|
class Handler extends ExceptionHandler
|
||||||
{
|
{
|
||||||
@ -71,9 +72,12 @@ class Handler extends ExceptionHandler
|
|||||||
{
|
{
|
||||||
if (! Schema::hasTable('accounts')) {
|
if (! Schema::hasTable('accounts')) {
|
||||||
info('account table not found');
|
info('account table not found');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// if(Account::count() == 0){
|
||||||
|
// info("handler - account table not found");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
if (app()->bound('sentry') && $this->shouldReport($exception)) {
|
if (app()->bound('sentry') && $this->shouldReport($exception)) {
|
||||||
app('sentry')->configureScope(function (Scope $scope): void {
|
app('sentry')->configureScope(function (Scope $scope): void {
|
||||||
|
@ -87,11 +87,6 @@ class SetupController extends Controller
|
|||||||
$_ENV['MAIL_FROM_ADDRESS'] = $request->input('mail_address');
|
$_ENV['MAIL_FROM_ADDRESS'] = $request->input('mail_address');
|
||||||
$_ENV['MAIL_PASSWORD'] = $request->input('mail_password');
|
$_ENV['MAIL_PASSWORD'] = $request->input('mail_password');
|
||||||
$_ENV['NINJA_ENVIRONMENT'] = 'selfhost';
|
$_ENV['NINJA_ENVIRONMENT'] = 'selfhost';
|
||||||
$_ENV['SELF_UPDATER_REPO_VENDOR'] = 'invoiceninja';
|
|
||||||
$_ENV['SELF_UPDATER_REPO_NAME'] = 'invoiceninja';
|
|
||||||
$_ENV['SELF_UPDATER_USE_BRANCH'] = 'v2';
|
|
||||||
$_ENV['SELF_UPDATER_MAILTO_ADDRESS'] = $request->input('mail_address');
|
|
||||||
$_ENV['SELF_UPDATER_MAILTO_NAME'] = $request->input('mail_name');
|
|
||||||
$_ENV['DB_CONNECTION'] = 'db-ninja-01';
|
$_ENV['DB_CONNECTION'] = 'db-ninja-01';
|
||||||
|
|
||||||
$config = '';
|
$config = '';
|
||||||
|
@ -34,12 +34,14 @@ class SetEmailDb
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($request->input('email') && config('ninja.db.multi_db_enabled')) {
|
if ($request->input('email') && config('ninja.db.multi_db_enabled')) {
|
||||||
|
info("trying to find db");
|
||||||
if (! MultiDB::userFindAndSetDb($request->input('email'))) {
|
if (! MultiDB::userFindAndSetDb($request->input('email'))) {
|
||||||
return response()->json($error, 403);
|
return response()->json($error, 400);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
return response()->json($error, 403);
|
// else {
|
||||||
}
|
// return response()->json($error, 403);
|
||||||
|
// }
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ class UpdateClientRequest extends Request
|
|||||||
* are saveable
|
* are saveable
|
||||||
*
|
*
|
||||||
* @param object $settings
|
* @param object $settings
|
||||||
* @return object $settings
|
* @return stdClass $settings
|
||||||
*/
|
*/
|
||||||
private function filterSaveableSettings($settings)
|
private function filterSaveableSettings($settings)
|
||||||
{
|
{
|
||||||
|
@ -76,7 +76,7 @@ class UpdateCompanyRequest extends Request
|
|||||||
* are saveable
|
* are saveable
|
||||||
*
|
*
|
||||||
* @param object $settings
|
* @param object $settings
|
||||||
* @return object $settings
|
* @return stdClass $settings
|
||||||
*/
|
*/
|
||||||
private function filterSaveableSettings($settings)
|
private function filterSaveableSettings($settings)
|
||||||
{
|
{
|
||||||
|
@ -58,7 +58,7 @@ class UpdateGroupSettingRequest extends Request
|
|||||||
* are saveable
|
* are saveable
|
||||||
*
|
*
|
||||||
* @param object $settings
|
* @param object $settings
|
||||||
* @return object $settings
|
* @return stdClass $settings
|
||||||
*/
|
*/
|
||||||
private function filterSaveableSettings($settings)
|
private function filterSaveableSettings($settings)
|
||||||
{
|
{
|
||||||
|
@ -38,8 +38,8 @@ class StoreTaskRequest extends Request
|
|||||||
{
|
{
|
||||||
$rules = [];
|
$rules = [];
|
||||||
|
|
||||||
$rules['number'] = Rule::unique('tasks')
|
if(isset($this->number))
|
||||||
->where('company_id', auth()->user()->company()->id);
|
$rules['number'] = Rule::unique('tasks')->where('company_id', auth()->user()->company()->id);
|
||||||
|
|
||||||
return $this->globalRules($rules);
|
return $this->globalRules($rules);
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,8 @@ class UpdateTaskRequest extends Request
|
|||||||
{
|
{
|
||||||
$rules = [];
|
$rules = [];
|
||||||
|
|
||||||
$rules['number'] = Rule::unique('tasks')
|
if(isset($this->number))
|
||||||
->where('company_id', auth()->user()->company()->id)
|
$rules['number'] = Rule::unique('tasks')->where('company_id', auth()->user()->company()->id)->ignore($this->task->id);
|
||||||
->ignore($this->task->id);
|
|
||||||
|
|
||||||
return $this->globalRules($rules);
|
return $this->globalRules($rules);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ namespace App\Jobs\Cron;
|
|||||||
use App\Jobs\RecurringInvoice\SendRecurring;
|
use App\Jobs\RecurringInvoice\SendRecurring;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
@ -46,6 +47,9 @@ class RecurringInvoicesCron
|
|||||||
|
|
||||||
$recurring_invoices = RecurringInvoice::whereDate('next_send_date', '=', now())
|
$recurring_invoices = RecurringInvoice::whereDate('next_send_date', '=', now())
|
||||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||||
|
->whereHas('company', function(Builder $query){
|
||||||
|
$query->where('is_disabled', false);
|
||||||
|
})
|
||||||
->cursor();
|
->cursor();
|
||||||
|
|
||||||
Log::info(now()->format('Y-m-d') . ' Sending Recurring Invoices. Count = '.$recurring_invoices->count());
|
Log::info(now()->format('Y-m-d') . ' Sending Recurring Invoices. Count = '.$recurring_invoices->count());
|
||||||
@ -66,6 +70,9 @@ class RecurringInvoicesCron
|
|||||||
|
|
||||||
$recurring_invoices = RecurringInvoice::whereDate('next_send_date', '=', now())
|
$recurring_invoices = RecurringInvoice::whereDate('next_send_date', '=', now())
|
||||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||||
|
->whereHas('company', function(Builder $query){
|
||||||
|
$query->where('is_disabled', false);
|
||||||
|
})
|
||||||
->cursor();
|
->cursor();
|
||||||
|
|
||||||
Log::info(now()->format('Y-m-d') . ' Sending Recurring Invoices. Count = '.$recurring_invoices->count().' On Database # '.$db);
|
Log::info(now()->format('Y-m-d') . ' Sending Recurring Invoices. Count = '.$recurring_invoices->count().' On Database # '.$db);
|
||||||
|
@ -94,7 +94,9 @@ class EmailEntity extends BaseMailerJob implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
if($this->company->is_disabled)
|
||||||
|
return true;
|
||||||
|
|
||||||
MultiDB::setDB($this->company->db);
|
MultiDB::setDB($this->company->db);
|
||||||
|
|
||||||
$this->setMailDriver();
|
$this->setMailDriver();
|
||||||
|
@ -57,7 +57,7 @@ class BaseMailerJob implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now that our token is refresh and valid we can boot the
|
* Now that our token is refreshed and valid we can boot the
|
||||||
* mail driver at runtime and also set the token which will persist
|
* mail driver at runtime and also set the token which will persist
|
||||||
* just for this request.
|
* just for this request.
|
||||||
*/
|
*/
|
||||||
|
@ -71,14 +71,13 @@ class EntityPaidMailer extends BaseMailerJob implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
/*If we are migrating data we don't want to fire these notification*/
|
||||||
|
if ($this->company->is_disabled)
|
||||||
|
return true;
|
||||||
|
|
||||||
//Set DB
|
//Set DB
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
/*If we are migrating data we don't want to fire these notification*/
|
|
||||||
if ($this->company->company_users->first()->is_migrating) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we need to set an email driver do it now
|
//if we need to set an email driver do it now
|
||||||
$this->setMailDriver();
|
$this->setMailDriver();
|
||||||
|
|
||||||
|
@ -75,6 +75,10 @@ class EntitySentMailer extends BaseMailerJob implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
/*If we are migrating data we don't want to fire these notification*/
|
||||||
|
if ($this->company->is_disabled)
|
||||||
|
return true;
|
||||||
|
|
||||||
//Set DB
|
//Set DB
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
@ -75,7 +75,10 @@ class EntityViewedMailer extends BaseMailerJob implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
/*If we are migrating data we don't want to fire these notification*/
|
||||||
|
if ($this->company->is_disabled)
|
||||||
|
return true;
|
||||||
|
|
||||||
//Set DB
|
//Set DB
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
@ -67,6 +67,10 @@ class MailRouter extends BaseMailerJob implements ShouldQueue
|
|||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
/*If we are migrating data we don't want to fire these notification*/
|
||||||
|
if ($this->company->is_disabled)
|
||||||
|
return true;
|
||||||
|
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
//if we need to set an email driver do it now
|
//if we need to set an email driver do it now
|
||||||
|
@ -76,6 +76,10 @@ class PaymentFailureMailer extends BaseMailerJob implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
/*If we are migrating data we don't want to fire these notification*/
|
||||||
|
if ($this->company->is_disabled)
|
||||||
|
return true;
|
||||||
|
|
||||||
//Set DB
|
//Set DB
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
@ -32,18 +32,21 @@ class EmailPayment extends BaseMailerJob implements ShouldQueue
|
|||||||
|
|
||||||
private $contact;
|
private $contact;
|
||||||
|
|
||||||
|
private $company;
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
* @param Payment $payment
|
* @param Payment $payment
|
||||||
* @param $email_builder
|
* @param $email_builder
|
||||||
* @param $contact
|
* @param $contact
|
||||||
|
* @param $company
|
||||||
*/
|
*/
|
||||||
public function __construct(Payment $payment, $email_builder, $contact)
|
public function __construct(Payment $payment, $email_builder, $contact, company)
|
||||||
{
|
{
|
||||||
$this->payment = $payment;
|
$this->payment = $payment;
|
||||||
$this->email_builder = $email_builder;
|
$this->email_builder = $email_builder;
|
||||||
$this->contact = $contact;
|
$this->contact = $contact;
|
||||||
|
$this->company = $company;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +57,9 @@ class EmailPayment extends BaseMailerJob implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
if($this->company->is_disabled)
|
||||||
|
return true;
|
||||||
|
|
||||||
if ($this->contact->email) {
|
if ($this->contact->email) {
|
||||||
|
|
||||||
MultiDB::setDb($this->payment->company->db); //this may fail if we don't pass the serialized object with the company record
|
MultiDB::setDb($this->payment->company->db); //this may fail if we don't pass the serialized object with the company record
|
||||||
|
@ -54,6 +54,9 @@ class UserEmailChanged extends BaseMailerJob implements ShouldQueue
|
|||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
if($this->company->is_disabled)
|
||||||
|
return true;
|
||||||
|
|
||||||
//Set DB
|
//Set DB
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
@ -79,7 +79,8 @@ class StartMigration implements ShouldQueue
|
|||||||
|
|
||||||
auth()->user()->setCompany($this->company);
|
auth()->user()->setCompany($this->company);
|
||||||
|
|
||||||
$this->company->setMigration(true);
|
$this->company->is_disabled = true;
|
||||||
|
$this->company->save();
|
||||||
|
|
||||||
$zip = new ZipArchive();
|
$zip = new ZipArchive();
|
||||||
$archive = $zip->open($this->filepath);
|
$archive = $zip->open($this->filepath);
|
||||||
|
@ -41,7 +41,7 @@ class WebhookHandler implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle() :bool
|
public function handle() :bool
|
||||||
{
|
{
|
||||||
if (! $this->entity->company || $this->entity->company->company_users->first()->is_migrating == true) {
|
if (! $this->entity->company || $this->entity->company->is_disabled) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,12 +48,13 @@ class PaymentNotification implements ShouldQueue
|
|||||||
MultiDB::setDb($event->company->db);
|
MultiDB::setDb($event->company->db);
|
||||||
|
|
||||||
$payment = $event->payment;
|
$payment = $event->payment;
|
||||||
|
|
||||||
|
if ($event->company->is_disabled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*User notifications*/
|
/*User notifications*/
|
||||||
foreach ($payment->company->company_users as $company_user) {
|
foreach ($payment->company->company_users as $company_user) {
|
||||||
if ($company_user->is_migrating) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = $company_user->user;
|
$user = $company_user->user;
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
* of settings which have been merged from
|
* of settings which have been merged from
|
||||||
* Client > Group > Company levels.
|
* Client > Group > Company levels.
|
||||||
*
|
*
|
||||||
* @return object stdClass object of settings
|
* @return stdClass stdClass object of settings
|
||||||
*/
|
*/
|
||||||
public function getMergedSettings() :object
|
public function getMergedSettings() :object
|
||||||
{
|
{
|
||||||
|
@ -107,6 +107,7 @@ class Company extends BaseModel
|
|||||||
'enable_shop_api',
|
'enable_shop_api',
|
||||||
'invoice_task_timelog',
|
'invoice_task_timelog',
|
||||||
'auto_start_tasks',
|
'auto_start_tasks',
|
||||||
|
'is_disabled',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
@ -443,13 +444,5 @@ class Company extends BaseModel
|
|||||||
return $this->slack_webhook_url;
|
return $this->slack_webhook_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setMigration($status)
|
|
||||||
{
|
|
||||||
$company_users = CompanyUser::where('company_id', $this->id)->get();
|
|
||||||
|
|
||||||
foreach ($company_users as $cu) {
|
|
||||||
$cu->is_migrating = $status;
|
|
||||||
$cu->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -324,32 +324,32 @@ class CompanyGateway extends BaseModel
|
|||||||
* @param $invoice_count
|
* @param $invoice_count
|
||||||
* @return stdClass
|
* @return stdClass
|
||||||
*/
|
*/
|
||||||
public function calcGatewayFeeObject($amount, $invoice_count)
|
// public function calcGatewayFeeObject($amount, $invoice_count)
|
||||||
{
|
// {
|
||||||
$total_gateway_fee = $this->calcGatewayFee($amount);
|
// $total_gateway_fee = $this->calcGatewayFee($amount);
|
||||||
|
|
||||||
$fee_object = new stdClass;
|
// $fee_object = new stdClass;
|
||||||
|
|
||||||
$fees_and_limits = $this->getFeesAndLimits();
|
// $fees_and_limits = $this->getFeesAndLimits();
|
||||||
|
|
||||||
if (! $fees_and_limits) {
|
// if (! $fees_and_limits) {
|
||||||
return $fee_object;
|
// return $fee_object;
|
||||||
}
|
// }
|
||||||
|
|
||||||
$fee_component_amount = $fees_and_limits->fee_amount ?: 0;
|
// $fee_component_amount = $fees_and_limits->fee_amount ?: 0;
|
||||||
$fee_component_percent = $fees_and_limits->fee_percent ? ($amount * $fees_and_limits->fee_percent / 100) : 0;
|
// $fee_component_percent = $fees_and_limits->fee_percent ? ($amount * $fees_and_limits->fee_percent / 100) : 0;
|
||||||
|
|
||||||
$combined_fee_component = $fee_component_amount + $fee_component_percent;
|
// $combined_fee_component = $fee_component_amount + $fee_component_percent;
|
||||||
|
|
||||||
$fee_component_tax_name1 = $fees_and_limits->fee_tax_name1 ?: '';
|
// $fee_component_tax_name1 = $fees_and_limits->fee_tax_name1 ?: '';
|
||||||
$fee_component_tax_rate1 = $fees_and_limits->fee_tax_rate1 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate1 / 100) : 0;
|
// $fee_component_tax_rate1 = $fees_and_limits->fee_tax_rate1 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate1 / 100) : 0;
|
||||||
|
|
||||||
$fee_component_tax_name2 = $fees_and_limits->fee_tax_name2 ?: '';
|
// $fee_component_tax_name2 = $fees_and_limits->fee_tax_name2 ?: '';
|
||||||
$fee_component_tax_rate2 = $fees_and_limits->fee_tax_rate2 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate2 / 100) : 0;
|
// $fee_component_tax_rate2 = $fees_and_limits->fee_tax_rate2 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate2 / 100) : 0;
|
||||||
|
|
||||||
$fee_component_tax_name3 = $fees_and_limits->fee_tax_name3 ?: '';
|
// $fee_component_tax_name3 = $fees_and_limits->fee_tax_name3 ?: '';
|
||||||
$fee_component_tax_rate3 = $fees_and_limits->fee_tax_rate3 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate3 / 100) : 0;
|
// $fee_component_tax_rate3 = $fees_and_limits->fee_tax_rate3 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate3 / 100) : 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public function resolveRouteBinding($value, $field = NULL)
|
public function resolveRouteBinding($value, $field = NULL)
|
||||||
{
|
{
|
||||||
|
@ -185,7 +185,7 @@ class Credit extends BaseModel
|
|||||||
/**
|
/**
|
||||||
* Access the invoice calculator object.
|
* Access the invoice calculator object.
|
||||||
*
|
*
|
||||||
* @return object The invoice calculator object getters
|
* @return stdClass The invoice calculator object getters
|
||||||
*/
|
*/
|
||||||
public function calc()
|
public function calc()
|
||||||
{
|
{
|
||||||
|
@ -209,6 +209,15 @@ class Invoice extends BaseModel
|
|||||||
return $this->hasMany(Credit::class);
|
return $this->hasMany(Credit::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function tasks()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Task::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function expenses()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Expense::class);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Service entry points.
|
* Service entry points.
|
||||||
*/
|
*/
|
||||||
@ -356,7 +365,7 @@ class Invoice extends BaseModel
|
|||||||
/**
|
/**
|
||||||
* Access the invoice calculator object.
|
* Access the invoice calculator object.
|
||||||
*
|
*
|
||||||
* @return object The invoice calculator object getters
|
* @return stdClass The invoice calculator object getters
|
||||||
*/
|
*/
|
||||||
public function calc()
|
public function calc()
|
||||||
{
|
{
|
||||||
|
@ -159,7 +159,7 @@ class Quote extends BaseModel
|
|||||||
/**
|
/**
|
||||||
* Access the quote calculator object.
|
* Access the quote calculator object.
|
||||||
*
|
*
|
||||||
* @return object The quote calculator object getters
|
* @return stdClass The quote calculator object getters
|
||||||
*/
|
*/
|
||||||
public function calc()
|
public function calc()
|
||||||
{
|
{
|
||||||
|
@ -72,7 +72,7 @@ class BasePaymentDriver
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Omnipay driver.
|
* Returns the Omnipay driver.
|
||||||
* @return object Omnipay initialized object
|
* @return stdClass Omnipay initialized object
|
||||||
*/
|
*/
|
||||||
protected function gateway()
|
protected function gateway()
|
||||||
{
|
{
|
||||||
|
@ -314,6 +314,7 @@ class BaseRepository
|
|||||||
if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) {
|
if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) {
|
||||||
$model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount']));
|
$model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount']));
|
||||||
$model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save();
|
$model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save();
|
||||||
|
$model->service()->linkEntities()->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $model->design_id) {
|
if (! $model->design_id) {
|
||||||
|
@ -41,6 +41,10 @@ class PaymentRepository extends BaseRepository
|
|||||||
$this->credit_repo = $credit_repo;
|
$this->credit_repo = $credit_repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
|
||||||
public function getClassName()
|
public function getClassName()
|
||||||
{
|
{
|
||||||
return Payment::class;
|
return Payment::class;
|
||||||
|
@ -31,7 +31,7 @@ class RecurringInvoiceRepository extends BaseRepository
|
|||||||
|
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
|
|
||||||
$invoice_calc = new InvoiceSum($invoice, $invoice->settings);
|
$invoice_calc = new InvoiceSum($invoice);
|
||||||
|
|
||||||
$invoice->service()
|
$invoice->service()
|
||||||
->applyNumber()
|
->applyNumber()
|
||||||
|
@ -30,9 +30,9 @@ class TaskRepository extends BaseRepository
|
|||||||
/**
|
/**
|
||||||
* Gets the class name.
|
* Gets the class name.
|
||||||
*
|
*
|
||||||
* @return string The class name.
|
* @return string The class name.
|
||||||
*/
|
*/
|
||||||
public function getClassName()
|
public function getClassName()
|
||||||
{
|
{
|
||||||
return Task::class;
|
return Task::class;
|
||||||
}
|
}
|
||||||
@ -40,8 +40,8 @@ class TaskRepository extends BaseRepository
|
|||||||
/**
|
/**
|
||||||
* Saves the task and its contacts.
|
* Saves the task and its contacts.
|
||||||
*
|
*
|
||||||
* @param array $data The data
|
* @param array $data The data
|
||||||
* @param \App\Models\task $task The task
|
* @param \App\Models\Task $task The task
|
||||||
*
|
*
|
||||||
* @return task|null task Object
|
* @return task|null task Object
|
||||||
*/
|
*/
|
||||||
|
@ -43,11 +43,10 @@ class UserRepository extends BaseRepository
|
|||||||
* @param array $data The data
|
* @param array $data The data
|
||||||
* @param \App\Models\user $user The user
|
* @param \App\Models\user $user The user
|
||||||
*
|
*
|
||||||
* @param bool $is_migrating
|
|
||||||
* @param bool $unset_company_user
|
* @param bool $unset_company_user
|
||||||
* @return user|\App\Models\user|null user Object
|
* @return user|\App\Models\user|null user Object
|
||||||
*/
|
*/
|
||||||
public function save(array $data, User $user, $is_migrating = false, $unset_company_user = false)
|
public function save(array $data, User $user, $unset_company_user = false)
|
||||||
{
|
{
|
||||||
$details = $data;
|
$details = $data;
|
||||||
|
|
||||||
@ -85,13 +84,11 @@ class UserRepository extends BaseRepository
|
|||||||
if (! $cu) {
|
if (! $cu) {
|
||||||
$data['company_user']['account_id'] = $account->id;
|
$data['company_user']['account_id'] = $account->id;
|
||||||
$data['company_user']['notifications'] = CompanySettings::notificationDefaults();
|
$data['company_user']['notifications'] = CompanySettings::notificationDefaults();
|
||||||
$data['company_user']['is_migrating'] = $is_migrating;
|
|
||||||
$user->companies()->attach($company->id, $data['company_user']);
|
$user->companies()->attach($company->id, $data['company_user']);
|
||||||
} else {
|
} else {
|
||||||
$cu->fill($data['company_user']);
|
$cu->fill($data['company_user']);
|
||||||
$cu->restore();
|
$cu->restore();
|
||||||
$cu->tokens()->restore();
|
$cu->tokens()->restore();
|
||||||
$cu->is_migrating = true;
|
|
||||||
$cu->save();
|
$cu->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,8 +105,6 @@ class UserRepository extends BaseRepository
|
|||||||
public function destroy(array $data, User $user)
|
public function destroy(array $data, User $user)
|
||||||
{
|
{
|
||||||
|
|
||||||
info("destroy user");
|
|
||||||
|
|
||||||
if (array_key_exists('company_user', $data)) {
|
if (array_key_exists('company_user', $data)) {
|
||||||
$this->forced_includes = 'company_users';
|
$this->forced_includes = 'company_users';
|
||||||
|
|
||||||
@ -136,8 +131,6 @@ info("destroy user");
|
|||||||
public function delete($user)
|
public function delete($user)
|
||||||
{
|
{
|
||||||
|
|
||||||
info("delete user");
|
|
||||||
|
|
||||||
$company = auth()->user()->company();
|
$company = auth()->user()->company();
|
||||||
|
|
||||||
$cu = CompanyUser::whereUserId($user->id)
|
$cu = CompanyUser::whereUserId($user->id)
|
||||||
|
@ -14,8 +14,10 @@ namespace App\Services\Invoice;
|
|||||||
use App\Jobs\Entity\CreateEntityPdf;
|
use App\Jobs\Entity\CreateEntityPdf;
|
||||||
use App\Jobs\Util\UnlinkFile;
|
use App\Jobs\Util\UnlinkFile;
|
||||||
use App\Models\CompanyGateway;
|
use App\Models\CompanyGateway;
|
||||||
|
use App\Models\Expense;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
|
use App\Models\Task;
|
||||||
use App\Services\Client\ClientService;
|
use App\Services\Client\ClientService;
|
||||||
use App\Services\Invoice\ApplyNumber;
|
use App\Services\Invoice\ApplyNumber;
|
||||||
use App\Services\Invoice\ApplyPayment;
|
use App\Services\Invoice\ApplyPayment;
|
||||||
@ -30,10 +32,13 @@ use App\Services\Invoice\MarkInvoicePaid;
|
|||||||
use App\Services\Invoice\MarkSent;
|
use App\Services\Invoice\MarkSent;
|
||||||
use App\Services\Invoice\TriggeredActions;
|
use App\Services\Invoice\TriggeredActions;
|
||||||
use App\Services\Invoice\UpdateBalance;
|
use App\Services\Invoice\UpdateBalance;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
class InvoiceService
|
class InvoiceService
|
||||||
{
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
private $invoice;
|
private $invoice;
|
||||||
|
|
||||||
protected $client_service;
|
protected $client_service;
|
||||||
@ -328,6 +333,30 @@ class InvoiceService
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function linkEntities()
|
||||||
|
{
|
||||||
|
//set all task.invoice_ids = 0
|
||||||
|
$this->invoice->tasks()->update(['invoice_id' => null]);
|
||||||
|
|
||||||
|
//set all tasks.invoice_ids = x with the current line_items
|
||||||
|
$tasks = collect($this->invoice->line_items)->map(function ($item){
|
||||||
|
|
||||||
|
if(isset($item->task_id))
|
||||||
|
$item->task_id = $this->decodePrimaryKey($item->task_id);
|
||||||
|
|
||||||
|
if(isset($item->expense_id))
|
||||||
|
$item->expense_id = $this->decodePrimaryKey($item->expense_id);
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
Task::whereIn('id',$tasks->pluck('task_id'))->update(['invoice_id' => $this->invoice->id]);
|
||||||
|
Expense::whereIn('id',$tasks->pluck('expense_id'))->update(['invoice_id' => $this->invoice->id]);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the invoice.
|
* Saves the invoice.
|
||||||
* @return Invoice object
|
* @return Invoice object
|
||||||
|
@ -53,6 +53,10 @@ class MarkInvoiceDeleted extends AbstractService
|
|||||||
|
|
||||||
$this->invoice->number = $number;
|
$this->invoice->number = $number;
|
||||||
|
|
||||||
|
//wipe references to invoices from related entities.
|
||||||
|
$this->invoice->tasks()->update(['invoice_id' => null]);
|
||||||
|
$this->invoice->expenses()->update(['invoice_id' => null]);
|
||||||
|
|
||||||
return $this->invoice;
|
return $this->invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,11 +33,11 @@ class SendEmail
|
|||||||
*/
|
*/
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
$email_builder = (new PaymentEmail())->build($this->payment, $contact);
|
$email_builder = (new PaymentEmail())->build($this->payment, $this->contact);
|
||||||
|
|
||||||
$this->payment->client->contacts->each(function ($contact) use ($email_builder) {
|
$this->payment->client->contacts->each(function ($contact) use ($email_builder) {
|
||||||
if ($contact->send && $contact->email) {
|
if ($contact->send && $contact->email) {
|
||||||
EmailPayment::dispatchNow($this->payment, $email_builder, $contact);
|
EmailPayment::dispatchNow($this->payment, $email_builder, $contact, $this->payment->company);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -148,6 +148,7 @@ class CompanyTransformer extends EntityTransformer
|
|||||||
'enabled_item_tax_rates' => (int) $company->enabled_item_tax_rates,
|
'enabled_item_tax_rates' => (int) $company->enabled_item_tax_rates,
|
||||||
'client_can_register' => (bool) $company->client_can_register,
|
'client_can_register' => (bool) $company->client_can_register,
|
||||||
'is_large' => (bool) $company->is_large,
|
'is_large' => (bool) $company->is_large,
|
||||||
|
'is_disabled' => (bool) $company->is_disabled,
|
||||||
'enable_shop_api' => (bool) $company->enable_shop_api,
|
'enable_shop_api' => (bool) $company->enable_shop_api,
|
||||||
'mark_expenses_invoiceable'=> (bool) $company->mark_expenses_invoiceable,
|
'mark_expenses_invoiceable'=> (bool) $company->mark_expenses_invoiceable,
|
||||||
'mark_expenses_paid' => (bool) $company->mark_expenses_paid,
|
'mark_expenses_paid' => (bool) $company->mark_expenses_paid,
|
||||||
|
@ -54,7 +54,6 @@ class UserTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $user->created_at,
|
'created_at' => (int) $user->created_at,
|
||||||
'updated_at' => (int) $user->updated_at,
|
'updated_at' => (int) $user->updated_at,
|
||||||
'archived_at' => (int) $user->deleted_at,
|
'archived_at' => (int) $user->deleted_at,
|
||||||
'created_at' => (int) $user->created_at,
|
|
||||||
'is_deleted' => (bool) $user->is_deleted,
|
'is_deleted' => (bool) $user->is_deleted,
|
||||||
'phone' => $user->phone ?: '',
|
'phone' => $user->phone ?: '',
|
||||||
'email_verified_at' => $user->getEmailVerifiedAt(),
|
'email_verified_at' => $user->getEmailVerifiedAt(),
|
||||||
|
@ -57,7 +57,7 @@ class EmailStats
|
|||||||
* Iterates through a list of companies
|
* Iterates through a list of companies
|
||||||
* and flushes the email sent data.
|
* and flushes the email sent data.
|
||||||
*
|
*
|
||||||
* @param string $companies The company key
|
* @param Collection $companies The company key
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function clearCompanies($companies)
|
public static function clearCompanies($companies)
|
||||||
|
@ -251,8 +251,8 @@ class HtmlEngine
|
|||||||
$data['$contact.phone'] = ['value' => $this->contact->phone, 'label' => ctrans('texts.phone')];
|
$data['$contact.phone'] = ['value' => $this->contact->phone, 'label' => ctrans('texts.phone')];
|
||||||
|
|
||||||
$data['$contact.name'] = ['value' => isset($this->contact) ? $this->contact->present()->name() : 'no contact name on record', 'label' => ctrans('texts.contact_name')];
|
$data['$contact.name'] = ['value' => isset($this->contact) ? $this->contact->present()->name() : 'no contact name on record', 'label' => ctrans('texts.contact_name')];
|
||||||
$data['$contact.first_name'] = ['value' => isset($contact) ? $contact->first_name : '', 'label' => ctrans('texts.first_name')];
|
$data['$contact.first_name'] = ['value' => isset($this->contact) ? $this->contact->first_name : '', 'label' => ctrans('texts.first_name')];
|
||||||
$data['$contact.last_name'] = ['value' => isset($contact) ? $contact->last_name : '', 'label' => ctrans('texts.last_name')];
|
$data['$contact.last_name'] = ['value' => isset($this->contact) ? $this->contact->last_name : '', 'label' => ctrans('texts.last_name')];
|
||||||
$data['$contact.custom1'] = ['value' => isset($this->contact) ? $this->contact->custom_value1 : ' ', 'label' => $this->makeCustomField('contact1')];
|
$data['$contact.custom1'] = ['value' => isset($this->contact) ? $this->contact->custom_value1 : ' ', 'label' => $this->makeCustomField('contact1')];
|
||||||
$data['$contact.custom2'] = ['value' => isset($this->contact) ? $this->contact->custom_value2 : ' ', 'label' => $this->makeCustomField('contact1')];
|
$data['$contact.custom2'] = ['value' => isset($this->contact) ? $this->contact->custom_value2 : ' ', 'label' => $this->makeCustomField('contact1')];
|
||||||
$data['$contact.custom3'] = ['value' => isset($this->contact) ? $this->contact->custom_value3 : ' ', 'label' => $this->makeCustomField('contact1')];
|
$data['$contact.custom3'] = ['value' => isset($this->contact) ? $this->contact->custom_value3 : ' ', 'label' => $this->makeCustomField('contact1')];
|
||||||
|
@ -35,9 +35,8 @@ class Phantom
|
|||||||
* Phantom JS API.
|
* Phantom JS API.
|
||||||
*
|
*
|
||||||
* @param $invitation
|
* @param $invitation
|
||||||
* @return pdf HTML to PDF conversion
|
|
||||||
*/
|
*/
|
||||||
public function generate($invitation)
|
public function generate($invitation)
|
||||||
{
|
{
|
||||||
$entity = false;
|
$entity = false;
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ trait ClientGroupSettingsSaver
|
|||||||
* so that it can be saved cleanly
|
* so that it can be saved cleanly
|
||||||
*
|
*
|
||||||
* @param array $settings The settings request() array
|
* @param array $settings The settings request() array
|
||||||
* @return object stdClass object
|
* @return stdClass stdClass object
|
||||||
*/
|
*/
|
||||||
private function checkSettingType($settings) : stdClass
|
private function checkSettingType($settings) : stdClass
|
||||||
{
|
{
|
||||||
@ -214,8 +214,7 @@ trait ClientGroupSettingsSaver
|
|||||||
case 'array':
|
case 'array':
|
||||||
return is_array($value);
|
return is_array($value);
|
||||||
case 'json':
|
case 'json':
|
||||||
json_decode($string);
|
json_decode($value);
|
||||||
|
|
||||||
return json_last_error() == JSON_ERROR_NONE;
|
return json_last_error() == JSON_ERROR_NONE;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -71,7 +71,7 @@ trait CompanyGatewayFeesAndLimitsSaver
|
|||||||
case 'array':
|
case 'array':
|
||||||
return is_array($value);
|
return is_array($value);
|
||||||
case 'json':
|
case 'json':
|
||||||
json_decode($string);
|
json_decode($value);
|
||||||
|
|
||||||
return json_last_error() == JSON_ERROR_NONE;
|
return json_last_error() == JSON_ERROR_NONE;
|
||||||
default:
|
default:
|
||||||
|
@ -131,7 +131,7 @@ trait CompanySettingsSaver
|
|||||||
* so that it can be saved cleanly
|
* so that it can be saved cleanly
|
||||||
*
|
*
|
||||||
* @param array $settings The settings request() array
|
* @param array $settings The settings request() array
|
||||||
* @return object stdClass object
|
* @return stdClass stdClass object
|
||||||
*/
|
*/
|
||||||
private function checkSettingType($settings) : stdClass
|
private function checkSettingType($settings) : stdClass
|
||||||
{
|
{
|
||||||
@ -224,7 +224,7 @@ trait CompanySettingsSaver
|
|||||||
case 'array':
|
case 'array':
|
||||||
return is_array($value);
|
return is_array($value);
|
||||||
case 'json':
|
case 'json':
|
||||||
json_decode($string);
|
json_decode($value);
|
||||||
|
|
||||||
return json_last_error() == JSON_ERROR_NONE;
|
return json_last_error() == JSON_ERROR_NONE;
|
||||||
default:
|
default:
|
||||||
|
@ -442,7 +442,7 @@ trait GeneratesCounter
|
|||||||
* check if we need to reset here.
|
* check if we need to reset here.
|
||||||
*
|
*
|
||||||
* @param Client $client client entity
|
* @param Client $client client entity
|
||||||
* @return false
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function resetCounters(Client $client)
|
private function resetCounters(Client $client)
|
||||||
{
|
{
|
||||||
|
@ -44,13 +44,9 @@ trait Inviteable
|
|||||||
|
|
||||||
public function getLink() :string
|
public function getLink() :string
|
||||||
{
|
{
|
||||||
//$entity_type = strtolower(class_basename($this->entityType()));
|
|
||||||
|
|
||||||
$entity_type = Str::snake(class_basename($this->entityType()));
|
$entity_type = Str::snake(class_basename($this->entityType()));
|
||||||
|
|
||||||
//$this->with('company','contact',$this->entity_type);
|
|
||||||
//$this->with('company');
|
|
||||||
|
|
||||||
$domain = isset($this->company->portal_domain) ?: $this->company->domain();
|
$domain = isset($this->company->portal_domain) ?: $this->company->domain();
|
||||||
|
|
||||||
switch ($this->company->portal_mode) {
|
switch ($this->company->portal_mode) {
|
||||||
@ -65,6 +61,9 @@ trait Inviteable
|
|||||||
return $domain.'client/'.$entity_type.'/'.$this->key;
|
return $domain.'client/'.$entity_type.'/'.$this->key;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,15 +52,17 @@ trait MakesDates
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats a date.
|
* Formats a date.
|
||||||
* @param Carbon/String $date Carbon object or date string
|
* @param Carbon|string $date Carbon object or date string
|
||||||
* @param string $format The date display format
|
* @param string $format The date display format
|
||||||
* @return string The formatted date
|
* @return string The formatted date
|
||||||
*/
|
*/
|
||||||
public function formatDate($date, string $format) :string
|
public function formatDate($date, string $format) :string
|
||||||
{
|
{
|
||||||
if (! $date || strlen($date) < 1) {
|
if(!isset($date))
|
||||||
return '';
|
return '';
|
||||||
}
|
// if (!$date || strlen($date) < 1) {
|
||||||
|
// return '';
|
||||||
|
// }
|
||||||
|
|
||||||
if (is_string($date)) {
|
if (is_string($date)) {
|
||||||
$date = $this->convertToDateObject($date);
|
$date = $this->convertToDateObject($date);
|
||||||
|
@ -67,7 +67,7 @@ trait MakesHash
|
|||||||
$decoded_array = $hashids->decode($value);
|
$decoded_array = $hashids->decode($value);
|
||||||
|
|
||||||
if (! is_array($decoded_array)) {
|
if (! is_array($decoded_array)) {
|
||||||
throw new Exception("Invalid Primary Key");
|
throw new \Exception("Invalid Primary Key");
|
||||||
//response()->json(['error'=>'Invalid primary key'], 400);
|
//response()->json(['error'=>'Invalid primary key'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ trait UserNotifies
|
|||||||
{
|
{
|
||||||
public function findUserNotificationTypes($invitation, $company_user, $entity_name, $required_permissions) :array
|
public function findUserNotificationTypes($invitation, $company_user, $entity_name, $required_permissions) :array
|
||||||
{
|
{
|
||||||
if ($this->migrationRunning($company_user)) {
|
if ($company_user->company->is_disabled) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ trait UserNotifies
|
|||||||
|
|
||||||
public function findUserEntityNotificationType($entity, $company_user, $required_permissions) :array
|
public function findUserEntityNotificationType($entity, $company_user, $required_permissions) :array
|
||||||
{
|
{
|
||||||
if ($this->migrationRunning($company_user)) {
|
if ($company_user->company->is_disabled) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ trait UserNotifies
|
|||||||
|
|
||||||
public function findCompanyUserNotificationType($company_user, $required_permissions) :array
|
public function findCompanyUserNotificationType($company_user, $required_permissions) :array
|
||||||
{
|
{
|
||||||
if ($this->migrationRunning($company_user)) {
|
if ($company_user->company->is_disabled) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,8 +79,4 @@ trait UserNotifies
|
|||||||
return $notifiable_methods;
|
return $notifiable_methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function migrationRunning($company_user)
|
|
||||||
{
|
|
||||||
return $company_user->is_migrating;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
622
composer.lock
generated
622
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,7 @@ return [
|
|||||||
'require_https' => env('REQUIRE_HTTPS', true),
|
'require_https' => env('REQUIRE_HTTPS', true),
|
||||||
'app_url' => rtrim(env('APP_URL', ''), '/').'/',
|
'app_url' => rtrim(env('APP_URL', ''), '/').'/',
|
||||||
'app_domain' => env('APP_DOMAIN', ''),
|
'app_domain' => env('APP_DOMAIN', ''),
|
||||||
'app_version' => '5.0.22',
|
'app_version' => '5.0.23',
|
||||||
'minimum_client_version' => '5.0.16',
|
'minimum_client_version' => '5.0.16',
|
||||||
'terms_version' => '1.0.1',
|
'terms_version' => '1.0.1',
|
||||||
'api_secret' => env('API_SECRET', ''),
|
'api_secret' => env('API_SECRET', ''),
|
||||||
|
@ -42,6 +42,7 @@ class ExpenseFactory extends Factory
|
|||||||
'public_notes' => $this->faker->text(50),
|
'public_notes' => $this->faker->text(50),
|
||||||
'private_notes' => $this->faker->text(50),
|
'private_notes' => $this->faker->text(50),
|
||||||
'transaction_reference' => $this->faker->text(5),
|
'transaction_reference' => $this->faker->text(5),
|
||||||
|
'invoice_id' => null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ class TaskFactory extends Factory
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'description' => $this->faker->text(50),
|
'description' => $this->faker->text(50),
|
||||||
|
'invoice_id' => null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class DropMigratingColumn extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('company_user', function(Blueprint $table){
|
||||||
|
$table->dropColumn('is_migrating');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
11
psalm.xml
11
psalm.xml
@ -51,7 +51,18 @@
|
|||||||
<directory name="app" />
|
<directory name="app" />
|
||||||
</errorLevel>
|
</errorLevel>
|
||||||
</InvalidScalarArgument>
|
</InvalidScalarArgument>
|
||||||
|
<UndefinedMagicPropertyFetch>
|
||||||
|
<errorLevel type="suppress">
|
||||||
|
<directory name="app" />
|
||||||
|
</errorLevel>
|
||||||
|
</UndefinedMagicPropertyFetch>
|
||||||
|
<InvalidNullableReturnType>
|
||||||
|
<errorLevel type="suppress">
|
||||||
|
<directory name="app" />
|
||||||
|
</errorLevel>
|
||||||
|
</InvalidNullableReturnType>
|
||||||
|
|
||||||
|
|
||||||
</issueHandlers>
|
</issueHandlers>
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,10 +16,9 @@ Route::group(['middleware' => ['api_secret_check']], function () {
|
|||||||
Route::post('api/v1/oauth_login', 'Auth\LoginController@oauthApiLogin');
|
Route::post('api/v1/oauth_login', 'Auth\LoginController@oauthApiLogin');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::group(['api_secret_check', 'email_db'], function () {
|
Route::group(['middleware' => ['api_secret_check', 'email_db']], function () {
|
||||||
Route::post('api/v1/login', 'Auth\LoginController@apiLogin')->name('login.submit');
|
Route::post('api/v1/login', 'Auth\LoginController@apiLogin')->name('login.submit');
|
||||||
Route::post('api/v1/reset_password', 'Auth\ForgotPasswordController@sendResetLinkEmail');
|
Route::post('api/v1/reset_password', 'Auth\ForgotPasswordController@sendResetLinkEmail');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () {
|
Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () {
|
||||||
|
77
tests/Feature/InvoiceLinkTasksTest.php
Normal file
77
tests/Feature/InvoiceLinkTasksTest.php
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\DataMapper\ClientSettings;
|
||||||
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\Factory\InvoiceFactory;
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Task;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Foundation\Testing\WithFaker;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Tests\MockAccountData;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
class InvoiceLinkTasksTest extends TestCase
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
use DatabaseTransactions;
|
||||||
|
use MockAccountData;
|
||||||
|
|
||||||
|
public function setUp() :void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
Session::start();
|
||||||
|
|
||||||
|
$this->faker = \Faker\Factory::create();
|
||||||
|
|
||||||
|
Model::reguard();
|
||||||
|
|
||||||
|
$this->makeTestData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMapCreation()
|
||||||
|
{
|
||||||
|
$temp_invoice_id = $this->invoice->id;
|
||||||
|
|
||||||
|
$tasks = collect($this->invoice->line_items)->map(function ($item){
|
||||||
|
|
||||||
|
if(isset($item->task_id))
|
||||||
|
$item->task_id = $this->decodePrimaryKey($item->task_id);
|
||||||
|
|
||||||
|
if(isset($item->expense_id))
|
||||||
|
$item->expense_id = $this->decodePrimaryKey($item->expense_id);
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertEquals($tasks->first()->task_id, $this->task->id);
|
||||||
|
$this->assertEquals($tasks->first()->expense_id, $this->expense->id);
|
||||||
|
|
||||||
|
$this->invoice = $this->invoice->service()->linkEntities()->save();
|
||||||
|
|
||||||
|
$this->assertEquals($this->task->fresh()->invoice_id, $temp_invoice_id);
|
||||||
|
$this->assertEquals($this->expense->fresh()->invoice_id, $temp_invoice_id);
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ use Illuminate\Http\Request;
|
|||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
@ -141,6 +142,10 @@ class LoginTest extends TestCase
|
|||||||
|
|
||||||
public function testApiLogin()
|
public function testApiLogin()
|
||||||
{
|
{
|
||||||
|
Account::all()->each(function ($account){
|
||||||
|
$account->delete();
|
||||||
|
});
|
||||||
|
|
||||||
$account = Account::factory()->create();
|
$account = Account::factory()->create();
|
||||||
$user = User::factory()->create([
|
$user = User::factory()->create([
|
||||||
'account_id' => $account->id,
|
'account_id' => $account->id,
|
||||||
@ -177,15 +182,28 @@ class LoginTest extends TestCase
|
|||||||
$this->assertTrue($user->company_users->first() !== null);
|
$this->assertTrue($user->company_users->first() !== null);
|
||||||
$this->assertTrue($user->company_user->account !== null);
|
$this->assertTrue($user->company_user->account !== null);
|
||||||
|
|
||||||
|
$this->assertEquals($user->email, 'test@example.com');
|
||||||
|
$this->assertTrue(\Hash::check('123456', $user->password));
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'email' => 'test@example.com',
|
'email' => 'test@example.com',
|
||||||
'password' => '123456',
|
'password' => '123456',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
try{
|
||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
])->post('/api/v1/login', $data);
|
])->post('/api/v1/login', $data);
|
||||||
|
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||||
|
info(print_r($message,1));
|
||||||
|
}
|
||||||
|
|
||||||
|
$arr = $response->json();
|
||||||
|
|
||||||
|
info(print_r($arr,1));
|
||||||
|
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -570,6 +570,8 @@ trait MockAccountData
|
|||||||
$item = InvoiceItemFactory::create();
|
$item = InvoiceItemFactory::create();
|
||||||
$item->quantity = 1;
|
$item->quantity = 1;
|
||||||
$item->cost = 10;
|
$item->cost = 10;
|
||||||
|
$item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||||
|
$item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||||
|
|
||||||
$line_items[] = $item;
|
$line_items[] = $item;
|
||||||
|
|
||||||
|
@ -61,19 +61,19 @@ class ImportTest extends TestCase
|
|||||||
$this->assertTrue($status);
|
$this->assertTrue($status);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAllImport()
|
// public function testAllImport()
|
||||||
{
|
// {
|
||||||
|
|
||||||
$this->invoice->forceDelete();
|
// $this->invoice->forceDelete();
|
||||||
$this->quote->forceDelete();
|
// $this->quote->forceDelete();
|
||||||
|
|
||||||
$this->user->setCompany($this->company);
|
// $this->user->setCompany($this->company);
|
||||||
auth()->login($this->user, true);
|
// auth()->login($this->user, true);
|
||||||
|
|
||||||
Import::dispatchNow($this->migration_array, $this->company, $this->user);
|
// Import::dispatchNow($this->migration_array, $this->company, $this->user);
|
||||||
|
|
||||||
$this->assertTrue(true);
|
// $this->assertTrue(true);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// public function testExceptionOnUnavailableResource()
|
// public function testExceptionOnUnavailableResource()
|
||||||
// {
|
// {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user