mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-03 23:37:33 -05: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
 | 
			
		||||
COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}'
 | 
			
		||||
TRAVIS=true
 | 
			
		||||
API_SECRET=superdoopersecrethere
 | 
			
		||||
 | 
			
		||||
@ -55,10 +55,5 @@ NINJA_ENVIRONMENT=selfhost
 | 
			
		||||
PHANTOMJS_KEY='a-demo-key-with-low-quota-per-ip-address'
 | 
			
		||||
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 }}"}}'
 | 
			
		||||
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.
 | 
			
		||||
     * @return object
 | 
			
		||||
     * @return stdClass
 | 
			
		||||
     */
 | 
			
		||||
    public static function defaults(): stdClass
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -149,7 +149,7 @@ class FreeCompanySettings extends BaseSettings
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Provides class defaults on init.
 | 
			
		||||
     * @return object
 | 
			
		||||
     * @return stdClass
 | 
			
		||||
     */
 | 
			
		||||
    public static function defaults(): stdClass
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@
 | 
			
		||||
namespace App\Exceptions;
 | 
			
		||||
 | 
			
		||||
use App\Exceptions\GenericPaymentDriverFailure;
 | 
			
		||||
use App\Models\Account;
 | 
			
		||||
use Exception;
 | 
			
		||||
use Illuminate\Auth\Access\AuthorizationException;
 | 
			
		||||
use Illuminate\Auth\AuthenticationException;
 | 
			
		||||
@ -27,14 +28,14 @@ use Illuminate\Support\Arr;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
use Illuminate\Validation\ValidationException;
 | 
			
		||||
use PDOException;
 | 
			
		||||
use Sentry\State\Scope;
 | 
			
		||||
use Swift_TransportException;
 | 
			
		||||
use Symfony\Component\Console\Exception\CommandNotFoundException;
 | 
			
		||||
use function Sentry\configureScope;
 | 
			
		||||
use Sentry\State\Scope;
 | 
			
		||||
use Symfony\Component\Debug\Exception\FatalThrowableError;
 | 
			
		||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
 | 
			
		||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 | 
			
		||||
use Throwable;
 | 
			
		||||
use function Sentry\configureScope;
 | 
			
		||||
 | 
			
		||||
class Handler extends ExceptionHandler
 | 
			
		||||
{
 | 
			
		||||
@ -71,9 +72,12 @@ class Handler extends ExceptionHandler
 | 
			
		||||
    {
 | 
			
		||||
        if (! Schema::hasTable('accounts')) {
 | 
			
		||||
            info('account table not found');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // if(Account::count() == 0){
 | 
			
		||||
        //     info("handler - account table not found");
 | 
			
		||||
        //     return;
 | 
			
		||||
        // }
 | 
			
		||||
 | 
			
		||||
        if (app()->bound('sentry') && $this->shouldReport($exception)) {
 | 
			
		||||
            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_PASSWORD'] = $request->input('mail_password');
 | 
			
		||||
        $_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';
 | 
			
		||||
 | 
			
		||||
        $config = '';
 | 
			
		||||
 | 
			
		||||
@ -34,12 +34,14 @@ class SetEmailDb
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        if ($request->input('email') && config('ninja.db.multi_db_enabled')) {
 | 
			
		||||
            info("trying to find db");
 | 
			
		||||
            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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -112,7 +112,7 @@ class UpdateClientRequest extends Request
 | 
			
		||||
     * are saveable
 | 
			
		||||
     *
 | 
			
		||||
     * @param  object $settings
 | 
			
		||||
     * @return object $settings
 | 
			
		||||
     * @return stdClass $settings
 | 
			
		||||
     */
 | 
			
		||||
    private function filterSaveableSettings($settings)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -76,7 +76,7 @@ class UpdateCompanyRequest extends Request
 | 
			
		||||
     * are saveable
 | 
			
		||||
     *
 | 
			
		||||
     * @param  object $settings
 | 
			
		||||
     * @return object $settings
 | 
			
		||||
     * @return stdClass $settings
 | 
			
		||||
     */
 | 
			
		||||
    private function filterSaveableSettings($settings)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -58,7 +58,7 @@ class UpdateGroupSettingRequest extends Request
 | 
			
		||||
     * are saveable
 | 
			
		||||
     *
 | 
			
		||||
     * @param  object $settings
 | 
			
		||||
     * @return object $settings
 | 
			
		||||
     * @return stdClass $settings
 | 
			
		||||
     */
 | 
			
		||||
    private function filterSaveableSettings($settings)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -38,8 +38,8 @@ class StoreTaskRequest extends Request
 | 
			
		||||
    {
 | 
			
		||||
        $rules = [];
 | 
			
		||||
        
 | 
			
		||||
        $rules['number'] = Rule::unique('tasks')
 | 
			
		||||
                                ->where('company_id', auth()->user()->company()->id);
 | 
			
		||||
        if(isset($this->number))
 | 
			
		||||
            $rules['number'] = Rule::unique('tasks')->where('company_id', auth()->user()->company()->id);
 | 
			
		||||
    
 | 
			
		||||
       return $this->globalRules($rules);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -38,9 +38,8 @@ class UpdateTaskRequest extends Request
 | 
			
		||||
    {
 | 
			
		||||
        $rules = [];
 | 
			
		||||
 | 
			
		||||
        $rules['number'] = Rule::unique('tasks')
 | 
			
		||||
                                ->where('company_id', auth()->user()->company()->id)
 | 
			
		||||
                                ->ignore($this->task->id);
 | 
			
		||||
        if(isset($this->number))
 | 
			
		||||
            $rules['number'] = Rule::unique('tasks')->where('company_id', auth()->user()->company()->id)->ignore($this->task->id);
 | 
			
		||||
 | 
			
		||||
        return $this->globalRules($rules);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ namespace App\Jobs\Cron;
 | 
			
		||||
use App\Jobs\RecurringInvoice\SendRecurring;
 | 
			
		||||
use App\Libraries\MultiDB;
 | 
			
		||||
use App\Models\RecurringInvoice;
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Illuminate\Foundation\Bus\Dispatchable;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Support\Carbon;
 | 
			
		||||
@ -46,6 +47,9 @@ class RecurringInvoicesCron
 | 
			
		||||
 | 
			
		||||
                $recurring_invoices = RecurringInvoice::whereDate('next_send_date', '=', now())
 | 
			
		||||
                                                        ->where('status_id', RecurringInvoice::STATUS_ACTIVE)
 | 
			
		||||
                                                        ->whereHas('company', function(Builder $query){
 | 
			
		||||
                                                            $query->where('is_disabled', false);
 | 
			
		||||
                                                        })
 | 
			
		||||
                                                        ->cursor();
 | 
			
		||||
 | 
			
		||||
                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())
 | 
			
		||||
                                                        ->where('status_id', RecurringInvoice::STATUS_ACTIVE)
 | 
			
		||||
                                                        ->whereHas('company', function(Builder $query){
 | 
			
		||||
                                                            $query->where('is_disabled', false);
 | 
			
		||||
                                                        })
 | 
			
		||||
                                                        ->cursor();
 | 
			
		||||
 | 
			
		||||
                Log::info(now()->format('Y-m-d') . ' Sending Recurring Invoices. Count = '.$recurring_invoices->count().' On Database # '.$db);
 | 
			
		||||
 | 
			
		||||
@ -94,6 +94,8 @@ class EmailEntity extends BaseMailerJob implements ShouldQueue
 | 
			
		||||
     */
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
        if($this->company->is_disabled)
 | 
			
		||||
            return true;
 | 
			
		||||
        
 | 
			
		||||
        MultiDB::setDB($this->company->db);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
         *  just for this request.
 | 
			
		||||
        */
 | 
			
		||||
 | 
			
		||||
@ -71,14 +71,13 @@ class EntityPaidMailer extends BaseMailerJob implements ShouldQueue
 | 
			
		||||
     */
 | 
			
		||||
    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
 | 
			
		||||
        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
 | 
			
		||||
        $this->setMailDriver();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -75,6 +75,10 @@ class EntitySentMailer extends BaseMailerJob implements ShouldQueue
 | 
			
		||||
     */
 | 
			
		||||
    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
 | 
			
		||||
        MultiDB::setDb($this->company->db);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -75,6 +75,9 @@ class EntityViewedMailer extends BaseMailerJob implements ShouldQueue
 | 
			
		||||
     */
 | 
			
		||||
    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
 | 
			
		||||
        MultiDB::setDb($this->company->db);
 | 
			
		||||
 | 
			
		||||
@ -67,6 +67,10 @@ class MailRouter extends BaseMailerJob implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
        //if we need to set an email driver do it now
 | 
			
		||||
 | 
			
		||||
@ -76,6 +76,10 @@ class PaymentFailureMailer extends BaseMailerJob implements ShouldQueue
 | 
			
		||||
     */
 | 
			
		||||
    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
 | 
			
		||||
        MultiDB::setDb($this->company->db);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -32,18 +32,21 @@ class EmailPayment extends BaseMailerJob implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    private $contact;
 | 
			
		||||
 | 
			
		||||
    private $company;
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new job instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param Payment $payment
 | 
			
		||||
     * @param $email_builder
 | 
			
		||||
     * @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->email_builder = $email_builder;
 | 
			
		||||
        $this->contact = $contact;
 | 
			
		||||
        $this->company = $company;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -54,6 +57,9 @@ class EmailPayment extends BaseMailerJob implements ShouldQueue
 | 
			
		||||
     */
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
        if($this->company->is_disabled)
 | 
			
		||||
            return true;
 | 
			
		||||
        
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
@ -54,6 +54,9 @@ class UserEmailChanged extends BaseMailerJob implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
        if($this->company->is_disabled)
 | 
			
		||||
            return true;
 | 
			
		||||
        
 | 
			
		||||
        //Set DB
 | 
			
		||||
        MultiDB::setDb($this->company->db);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -79,7 +79,8 @@ class StartMigration implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
        auth()->user()->setCompany($this->company);
 | 
			
		||||
 | 
			
		||||
        $this->company->setMigration(true);
 | 
			
		||||
        $this->company->is_disabled = true;
 | 
			
		||||
        $this->company->save();
 | 
			
		||||
 | 
			
		||||
        $zip = new ZipArchive();
 | 
			
		||||
        $archive = $zip->open($this->filepath);
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ class WebhookHandler implements ShouldQueue
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -49,12 +49,13 @@ class PaymentNotification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
        $payment = $event->payment;
 | 
			
		||||
        
 | 
			
		||||
        /*User notifications*/
 | 
			
		||||
        foreach ($payment->company->company_users as $company_user) {
 | 
			
		||||
            if ($company_user->is_migrating) {
 | 
			
		||||
        if ($event->company->is_disabled) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*User notifications*/
 | 
			
		||||
        foreach ($payment->company->company_users as $company_user) {
 | 
			
		||||
 | 
			
		||||
            $user = $company_user->user;
 | 
			
		||||
 | 
			
		||||
            $methods = $this->findUserEntityNotificationType($payment, $company_user, ['all_notifications']);
 | 
			
		||||
 | 
			
		||||
@ -285,7 +285,7 @@ class Client extends BaseModel implements HasLocalePreference
 | 
			
		||||
     * of settings which have been merged from
 | 
			
		||||
     * Client > Group > Company levels.
 | 
			
		||||
     *
 | 
			
		||||
     * @return object stdClass object of settings
 | 
			
		||||
     * @return stdClass stdClass object of settings
 | 
			
		||||
     */
 | 
			
		||||
    public function getMergedSettings() :object
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -107,6 +107,7 @@ class Company extends BaseModel
 | 
			
		||||
        'enable_shop_api',
 | 
			
		||||
        'invoice_task_timelog',
 | 
			
		||||
        'auto_start_tasks',
 | 
			
		||||
        'is_disabled',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    protected $hidden = [
 | 
			
		||||
@ -443,13 +444,5 @@ class Company extends BaseModel
 | 
			
		||||
        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
 | 
			
		||||
     * @return stdClass
 | 
			
		||||
     */
 | 
			
		||||
    public function calcGatewayFeeObject($amount, $invoice_count)
 | 
			
		||||
    {
 | 
			
		||||
        $total_gateway_fee = $this->calcGatewayFee($amount);
 | 
			
		||||
    // public function calcGatewayFeeObject($amount, $invoice_count)
 | 
			
		||||
    // {
 | 
			
		||||
    //     $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) {
 | 
			
		||||
            return $fee_object;
 | 
			
		||||
        }
 | 
			
		||||
    //     if (! $fees_and_limits) {
 | 
			
		||||
    //         return $fee_object;
 | 
			
		||||
    //     }
 | 
			
		||||
 | 
			
		||||
        $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_amount = $fees_and_limits->fee_amount ?: 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_rate1 = $fees_and_limits->fee_tax_rate1 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate1 / 100) : 0;
 | 
			
		||||
    //     $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_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_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_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_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;
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    public function resolveRouteBinding($value, $field = NULL)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -185,7 +185,7 @@ class Credit extends BaseModel
 | 
			
		||||
    /**
 | 
			
		||||
     * Access the invoice calculator object.
 | 
			
		||||
     *
 | 
			
		||||
     * @return object The invoice calculator object getters
 | 
			
		||||
     * @return stdClass The invoice calculator object getters
 | 
			
		||||
     */
 | 
			
		||||
    public function calc()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -209,6 +209,15 @@ class Invoice extends BaseModel
 | 
			
		||||
        return $this->hasMany(Credit::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function tasks()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->hasMany(Task::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function expenses()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->hasMany(Expense::class);
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Service entry points.
 | 
			
		||||
     */
 | 
			
		||||
@ -356,7 +365,7 @@ class Invoice extends BaseModel
 | 
			
		||||
    /**
 | 
			
		||||
     * Access the invoice calculator object.
 | 
			
		||||
     *
 | 
			
		||||
     * @return object The invoice calculator object getters
 | 
			
		||||
     * @return stdClass The invoice calculator object getters
 | 
			
		||||
     */
 | 
			
		||||
    public function calc()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -159,7 +159,7 @@ class Quote extends BaseModel
 | 
			
		||||
    /**
 | 
			
		||||
     * Access the quote calculator object.
 | 
			
		||||
     *
 | 
			
		||||
     * @return object The quote calculator object getters
 | 
			
		||||
     * @return stdClass The quote calculator object getters
 | 
			
		||||
     */
 | 
			
		||||
    public function calc()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -72,7 +72,7 @@ class BasePaymentDriver
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the Omnipay driver.
 | 
			
		||||
     * @return object Omnipay initialized object
 | 
			
		||||
     * @return stdClass Omnipay initialized object
 | 
			
		||||
     */
 | 
			
		||||
    protected function gateway()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -314,6 +314,7 @@ class BaseRepository
 | 
			
		||||
            if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) {
 | 
			
		||||
                $model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount']));
 | 
			
		||||
                $model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save();
 | 
			
		||||
                $model->service()->linkEntities()->save();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (! $model->design_id) {
 | 
			
		||||
 | 
			
		||||
@ -41,6 +41,10 @@ class PaymentRepository extends BaseRepository
 | 
			
		||||
        $this->credit_repo = $credit_repo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** 
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    public function getClassName()
 | 
			
		||||
    {
 | 
			
		||||
        return Payment::class;
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,7 @@ class RecurringInvoiceRepository extends BaseRepository
 | 
			
		||||
 | 
			
		||||
        $invoice->save();
 | 
			
		||||
 | 
			
		||||
        $invoice_calc = new InvoiceSum($invoice, $invoice->settings);
 | 
			
		||||
        $invoice_calc = new InvoiceSum($invoice);
 | 
			
		||||
 | 
			
		||||
        $invoice->service()
 | 
			
		||||
                ->applyNumber()
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ class TaskRepository extends BaseRepository
 | 
			
		||||
     * Saves the task and its contacts.
 | 
			
		||||
     *
 | 
			
		||||
     * @param      array                         $data    The data
 | 
			
		||||
     * @param      \App\Models\task              $task  The task
 | 
			
		||||
     * @param      \App\Models\Task              $task  The task
 | 
			
		||||
     *
 | 
			
		||||
     * @return     task|null  task Object
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
@ -43,11 +43,10 @@ class UserRepository extends BaseRepository
 | 
			
		||||
     * @param array $data The data
 | 
			
		||||
     * @param \App\Models\user $user The user
 | 
			
		||||
     *
 | 
			
		||||
     * @param bool $is_migrating
 | 
			
		||||
     * @param bool $unset_company_user
 | 
			
		||||
     * @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;
 | 
			
		||||
 | 
			
		||||
@ -85,13 +84,11 @@ class UserRepository extends BaseRepository
 | 
			
		||||
            if (! $cu) {
 | 
			
		||||
                $data['company_user']['account_id'] = $account->id;
 | 
			
		||||
                $data['company_user']['notifications'] = CompanySettings::notificationDefaults();
 | 
			
		||||
                $data['company_user']['is_migrating'] = $is_migrating;
 | 
			
		||||
                $user->companies()->attach($company->id, $data['company_user']);
 | 
			
		||||
            } else {
 | 
			
		||||
                $cu->fill($data['company_user']);
 | 
			
		||||
                $cu->restore();
 | 
			
		||||
                $cu->tokens()->restore();
 | 
			
		||||
                $cu->is_migrating = true;
 | 
			
		||||
                $cu->save();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -108,8 +105,6 @@ class UserRepository extends BaseRepository
 | 
			
		||||
    public function destroy(array $data, User $user)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
info("destroy user");
 | 
			
		||||
 | 
			
		||||
        if (array_key_exists('company_user', $data)) {
 | 
			
		||||
            $this->forced_includes = 'company_users';
 | 
			
		||||
 | 
			
		||||
@ -136,8 +131,6 @@ info("destroy user");
 | 
			
		||||
    public function delete($user)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
info("delete user");
 | 
			
		||||
 | 
			
		||||
        $company = auth()->user()->company();
 | 
			
		||||
 | 
			
		||||
        $cu = CompanyUser::whereUserId($user->id)
 | 
			
		||||
 | 
			
		||||
@ -14,8 +14,10 @@ namespace App\Services\Invoice;
 | 
			
		||||
use App\Jobs\Entity\CreateEntityPdf;
 | 
			
		||||
use App\Jobs\Util\UnlinkFile;
 | 
			
		||||
use App\Models\CompanyGateway;
 | 
			
		||||
use App\Models\Expense;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Models\Payment;
 | 
			
		||||
use App\Models\Task;
 | 
			
		||||
use App\Services\Client\ClientService;
 | 
			
		||||
use App\Services\Invoice\ApplyNumber;
 | 
			
		||||
use App\Services\Invoice\ApplyPayment;
 | 
			
		||||
@ -30,10 +32,13 @@ use App\Services\Invoice\MarkInvoicePaid;
 | 
			
		||||
use App\Services\Invoice\MarkSent;
 | 
			
		||||
use App\Services\Invoice\TriggeredActions;
 | 
			
		||||
use App\Services\Invoice\UpdateBalance;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Support\Carbon;
 | 
			
		||||
 | 
			
		||||
class InvoiceService
 | 
			
		||||
{
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
 | 
			
		||||
    private $invoice;
 | 
			
		||||
 | 
			
		||||
    protected $client_service;
 | 
			
		||||
@ -328,6 +333,30 @@ class InvoiceService
 | 
			
		||||
        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.
 | 
			
		||||
     * @return Invoice object
 | 
			
		||||
 | 
			
		||||
@ -53,6 +53,10 @@ class MarkInvoiceDeleted extends AbstractService
 | 
			
		||||
 | 
			
		||||
        $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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -33,11 +33,11 @@ class SendEmail
 | 
			
		||||
     */
 | 
			
		||||
    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) {
 | 
			
		||||
            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,
 | 
			
		||||
            'client_can_register' => (bool) $company->client_can_register,
 | 
			
		||||
            'is_large' => (bool) $company->is_large,
 | 
			
		||||
            'is_disabled' => (bool) $company->is_disabled,
 | 
			
		||||
            'enable_shop_api' => (bool) $company->enable_shop_api,
 | 
			
		||||
            'mark_expenses_invoiceable'=> (bool) $company->mark_expenses_invoiceable,
 | 
			
		||||
            'mark_expenses_paid' => (bool) $company->mark_expenses_paid,
 | 
			
		||||
 | 
			
		||||
@ -54,7 +54,6 @@ class UserTransformer extends EntityTransformer
 | 
			
		||||
            'created_at' => (int) $user->created_at,
 | 
			
		||||
            'updated_at' => (int) $user->updated_at,
 | 
			
		||||
            'archived_at' => (int) $user->deleted_at,
 | 
			
		||||
            'created_at' => (int) $user->created_at,
 | 
			
		||||
            'is_deleted' => (bool) $user->is_deleted,
 | 
			
		||||
            'phone' => $user->phone ?: '',
 | 
			
		||||
            'email_verified_at' => $user->getEmailVerifiedAt(),
 | 
			
		||||
 | 
			
		||||
@ -57,7 +57,7 @@ class EmailStats
 | 
			
		||||
     * Iterates through a list of companies
 | 
			
		||||
     * and flushes the email sent data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  string $companies The company key
 | 
			
		||||
     * @param  Collection $companies The company key
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public static function clearCompanies($companies)
 | 
			
		||||
 | 
			
		||||
@ -251,8 +251,8 @@ class HtmlEngine
 | 
			
		||||
        $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.first_name'] = ['value' => isset($contact) ? $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.first_name'] = ['value' => isset($this->contact) ? $this->contact->first_name : '', 'label' => ctrans('texts.first_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.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')];
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,6 @@ class Phantom
 | 
			
		||||
     * Phantom JS API.
 | 
			
		||||
     *
 | 
			
		||||
     * @param $invitation
 | 
			
		||||
     * @return pdf HTML to PDF conversion
 | 
			
		||||
     */
 | 
			
		||||
    public function generate($invitation) 
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -139,7 +139,7 @@ trait ClientGroupSettingsSaver
 | 
			
		||||
     * so that it can be saved cleanly
 | 
			
		||||
     *
 | 
			
		||||
     * @param  array $settings The settings request() array
 | 
			
		||||
     * @return object          stdClass object
 | 
			
		||||
     * @return stdClass          stdClass object
 | 
			
		||||
     */
 | 
			
		||||
    private function checkSettingType($settings) : stdClass
 | 
			
		||||
    {
 | 
			
		||||
@ -214,8 +214,7 @@ trait ClientGroupSettingsSaver
 | 
			
		||||
            case 'array':
 | 
			
		||||
                return is_array($value);
 | 
			
		||||
            case 'json':
 | 
			
		||||
                json_decode($string);
 | 
			
		||||
 | 
			
		||||
                json_decode($value);
 | 
			
		||||
                    return json_last_error() == JSON_ERROR_NONE;
 | 
			
		||||
            default:
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
@ -71,7 +71,7 @@ trait CompanyGatewayFeesAndLimitsSaver
 | 
			
		||||
            case 'array':
 | 
			
		||||
                return is_array($value);
 | 
			
		||||
            case 'json':
 | 
			
		||||
                json_decode($string);
 | 
			
		||||
                json_decode($value);
 | 
			
		||||
 | 
			
		||||
                    return json_last_error() == JSON_ERROR_NONE;
 | 
			
		||||
            default:
 | 
			
		||||
 | 
			
		||||
@ -131,7 +131,7 @@ trait CompanySettingsSaver
 | 
			
		||||
     * so that it can be saved cleanly
 | 
			
		||||
     *
 | 
			
		||||
     * @param  array $settings The settings request() array
 | 
			
		||||
     * @return object          stdClass object
 | 
			
		||||
     * @return stdClass       stdClass object
 | 
			
		||||
     */
 | 
			
		||||
    private function checkSettingType($settings) : stdClass
 | 
			
		||||
    {
 | 
			
		||||
@ -224,7 +224,7 @@ trait CompanySettingsSaver
 | 
			
		||||
            case 'array':
 | 
			
		||||
                return is_array($value);
 | 
			
		||||
            case 'json':
 | 
			
		||||
                json_decode($string);
 | 
			
		||||
                json_decode($value);
 | 
			
		||||
 | 
			
		||||
                    return json_last_error() == JSON_ERROR_NONE;
 | 
			
		||||
            default:
 | 
			
		||||
 | 
			
		||||
@ -442,7 +442,7 @@ trait GeneratesCounter
 | 
			
		||||
     * check if we need to reset here.
 | 
			
		||||
     *
 | 
			
		||||
     * @param Client $client client entity
 | 
			
		||||
     * @return false
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    private function resetCounters(Client $client)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -44,13 +44,9 @@ trait Inviteable
 | 
			
		||||
 | 
			
		||||
    public function getLink() :string
 | 
			
		||||
    {
 | 
			
		||||
        //$entity_type = strtolower(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();
 | 
			
		||||
 | 
			
		||||
        switch ($this->company->portal_mode) {
 | 
			
		||||
@ -65,6 +61,9 @@ trait Inviteable
 | 
			
		||||
                return $domain.'client/'.$entity_type.'/'.$this->key;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                return '';
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -52,15 +52,17 @@ trait MakesDates
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
     * @return string         The formatted date
 | 
			
		||||
     */
 | 
			
		||||
    public function formatDate($date, string $format) :string
 | 
			
		||||
    {
 | 
			
		||||
        if (! $date || strlen($date) < 1) {
 | 
			
		||||
        if(!isset($date))
 | 
			
		||||
            return '';
 | 
			
		||||
        }
 | 
			
		||||
        // if (!$date || strlen($date) < 1) {
 | 
			
		||||
        //     return '';
 | 
			
		||||
        // }
 | 
			
		||||
 | 
			
		||||
        if (is_string($date)) {
 | 
			
		||||
            $date = $this->convertToDateObject($date);
 | 
			
		||||
 | 
			
		||||
@ -67,7 +67,7 @@ trait MakesHash
 | 
			
		||||
            $decoded_array = $hashids->decode($value);
 | 
			
		||||
 | 
			
		||||
            if (! is_array($decoded_array)) {
 | 
			
		||||
                throw new Exception("Invalid Primary Key");
 | 
			
		||||
                throw new \Exception("Invalid Primary Key");
 | 
			
		||||
                //response()->json(['error'=>'Invalid primary key'], 400);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@ trait UserNotifies
 | 
			
		||||
{
 | 
			
		||||
    public function findUserNotificationTypes($invitation, $company_user, $entity_name, $required_permissions) :array
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->migrationRunning($company_user)) {
 | 
			
		||||
        if ($company_user->company->is_disabled) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ trait UserNotifies
 | 
			
		||||
 | 
			
		||||
    public function findUserEntityNotificationType($entity, $company_user, $required_permissions) :array
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->migrationRunning($company_user)) {
 | 
			
		||||
        if ($company_user->company->is_disabled) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -65,7 +65,7 @@ trait UserNotifies
 | 
			
		||||
 | 
			
		||||
    public function findCompanyUserNotificationType($company_user, $required_permissions) :array
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->migrationRunning($company_user)) {
 | 
			
		||||
        if ($company_user->company->is_disabled) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -79,8 +79,4 @@ trait UserNotifies
 | 
			
		||||
        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),
 | 
			
		||||
    'app_url' => rtrim(env('APP_URL', ''), '/').'/',
 | 
			
		||||
    'app_domain' => env('APP_DOMAIN', ''),
 | 
			
		||||
    'app_version' => '5.0.22',
 | 
			
		||||
    'app_version' => '5.0.23',
 | 
			
		||||
    'minimum_client_version' => '5.0.16',
 | 
			
		||||
    'terms_version' => '1.0.1',
 | 
			
		||||
    'api_secret' => env('API_SECRET', ''),
 | 
			
		||||
 | 
			
		||||
@ -42,6 +42,7 @@ class ExpenseFactory extends Factory
 | 
			
		||||
            'public_notes' => $this->faker->text(50),
 | 
			
		||||
            'private_notes' => $this->faker->text(50),
 | 
			
		||||
            'transaction_reference' => $this->faker->text(5),
 | 
			
		||||
            'invoice_id' => null,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,7 @@ class TaskFactory extends Factory
 | 
			
		||||
	    {
 | 
			
		||||
	    return [
 | 
			
		||||
	        '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,6 +51,17 @@
 | 
			
		||||
      <directory name="app" /> 
 | 
			
		||||
    </errorLevel>
 | 
			
		||||
  </InvalidScalarArgument> 
 | 
			
		||||
  <UndefinedMagicPropertyFetch>
 | 
			
		||||
    <errorLevel type="suppress">
 | 
			
		||||
      <directory name="app" /> 
 | 
			
		||||
    </errorLevel>
 | 
			
		||||
  </UndefinedMagicPropertyFetch> 
 | 
			
		||||
  <InvalidNullableReturnType>
 | 
			
		||||
    <errorLevel type="suppress">
 | 
			
		||||
      <directory name="app" /> 
 | 
			
		||||
    </errorLevel>
 | 
			
		||||
  </InvalidNullableReturnType> 
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
</issueHandlers>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,9 @@ Route::group(['middleware' => ['api_secret_check']], function () {
 | 
			
		||||
    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/reset_password', 'Auth\ForgotPasswordController@sendResetLinkEmail');
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
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\Session;
 | 
			
		||||
use Tests\TestCase;
 | 
			
		||||
use Illuminate\Validation\ValidationException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @test
 | 
			
		||||
@ -141,6 +142,10 @@ class LoginTest extends TestCase
 | 
			
		||||
 | 
			
		||||
    public function testApiLogin()
 | 
			
		||||
    {
 | 
			
		||||
        Account::all()->each(function ($account){
 | 
			
		||||
            $account->delete();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $account = Account::factory()->create();
 | 
			
		||||
        $user = User::factory()->create([
 | 
			
		||||
            'account_id' => $account->id,
 | 
			
		||||
@ -177,15 +182,28 @@ class LoginTest extends TestCase
 | 
			
		||||
        $this->assertTrue($user->company_users->first() !== null);
 | 
			
		||||
        $this->assertTrue($user->company_user->account !== null);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals($user->email, 'test@example.com');
 | 
			
		||||
        $this->assertTrue(\Hash::check('123456', $user->password));
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'email' => 'test@example.com',
 | 
			
		||||
            'password' => '123456',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        try{
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            ])->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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -570,6 +570,8 @@ trait MockAccountData
 | 
			
		||||
        $item = InvoiceItemFactory::create();
 | 
			
		||||
        $item->quantity = 1;
 | 
			
		||||
        $item->cost = 10;
 | 
			
		||||
        $item->task_id = $this->encodePrimaryKey($this->task->id);
 | 
			
		||||
        $item->expense_id = $this->encodePrimaryKey($this->expense->id);
 | 
			
		||||
 | 
			
		||||
        $line_items[] = $item;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -61,19 +61,19 @@ class ImportTest extends TestCase
 | 
			
		||||
        $this->assertTrue($status);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testAllImport()
 | 
			
		||||
    {
 | 
			
		||||
    // public function testAllImport()
 | 
			
		||||
    // {
 | 
			
		||||
 | 
			
		||||
        $this->invoice->forceDelete();
 | 
			
		||||
        $this->quote->forceDelete();
 | 
			
		||||
    //     $this->invoice->forceDelete();
 | 
			
		||||
    //     $this->quote->forceDelete();
 | 
			
		||||
 | 
			
		||||
        $this->user->setCompany($this->company);
 | 
			
		||||
        auth()->login($this->user, true);
 | 
			
		||||
    //     $this->user->setCompany($this->company);
 | 
			
		||||
    //     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()
 | 
			
		||||
//     {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user