diff --git a/app/Console/Commands/CreateTestData.php b/app/Console/Commands/CreateTestData.php index 8d4ab8041e4a..ac7bcf8daa56 100644 --- a/app/Console/Commands/CreateTestData.php +++ b/app/Console/Commands/CreateTestData.php @@ -112,6 +112,8 @@ class CreateTestData extends Command $company_token->account_id = $account->id; $company_token->name = 'test token'; $company_token->token = Str::random(64); + $company_token->is_system = true; + $company_token->save(); $user->companies()->attach($company->id, [ @@ -207,6 +209,7 @@ class CreateTestData extends Command $company_token->account_id = $account->id; $company_token->name = 'test token'; $company_token->token = Str::random(64); + $company_token->is_system = true; $company_token->save(); $user->companies()->attach($company->id, [ @@ -304,6 +307,7 @@ class CreateTestData extends Command $company_token->account_id = $account->id; $company_token->name = 'test token'; $company_token->token = Str::random(64); + $company_token->is_system = true; $company_token->save(); $user->companies()->attach($company->id, [ diff --git a/app/Console/Commands/DemoMode.php b/app/Console/Commands/DemoMode.php index bc1875f5a787..a2cb0781c43a 100644 --- a/app/Console/Commands/DemoMode.php +++ b/app/Console/Commands/DemoMode.php @@ -100,7 +100,7 @@ class DemoMode extends Command $company = factory(\App\Models\Company::class)->create([ 'account_id' => $account->id, 'slack_webhook_url' => config('ninja.notification.slack'), - 'enabled_modules' => 8191, + 'enabled_modules' => 32767, ]); $settings = $company->settings; @@ -137,6 +137,8 @@ class DemoMode extends Command $company_token->account_id = $account->id; $company_token->name = 'test token'; $company_token->token = Str::random(64); + $company_token->is_system = true; + $company_token->save(); $user->companies()->attach($company->id, [ @@ -190,10 +192,8 @@ class DemoMode extends Command $z = $x+1; $this->info("Creating client # ".$z); - if(rand(0,1)) - $this->createClient($company, $user); - else - $this->createClient($company, $u2); + $this->createClient($company, $user, $u2->id); + } for($x=0; $x<$this->count; $x++) @@ -201,50 +201,50 @@ class DemoMode extends Command $client = $company->clients->random(); $this->info('creating entities for client #'.$client->id); - $this->createInvoice($client); + $this->createInvoice($client, $u2->id); // for($y=0; $y<($this->count); $y++){ // $this->info("creating invoice #{$y} for client #".$client->id); // } $client = $company->clients->random(); - $this->createCredit($client); + $this->createCredit($client, $u2->id); // for($y=0; $y<($this->count); $y++){ // $this->info("creating credit #{$y} for client #".$client->id); // } $client = $company->clients->random(); - $this->createQuote($client); + $this->createQuote($client, $u2->id); // for($y=0; $y<($this->count); $y++){ // $this->info("creating quote #{$y} for client #".$client->id); // } $client = $company->clients->random(); - $this->createExpense($client); + $this->createExpense($client, $u2->id); //$this->info("creating expense for client #".$client->id); $client = $company->clients->random(); - $this->createVendor($client); + $this->createVendor($client, $u2->id); // $this->info("creating vendor for client #".$client->id); $client = $company->clients->random(); - $this->createTask($client); + $this->createTask($client, $u2->id); // $this->info("creating task for client #".$client->id); $client = $company->clients->random(); - $this->createProject($client); + $this->createProject($client, $u2->id); // $this->info("creating project for client #".$client->id); } } - private function createClient($company, $user) + private function createClient($company, $user, $assigned_user_id = null) { // dispatch(function () use ($company, $user) { @@ -274,6 +274,9 @@ class DemoMode extends Command $settings->currency_id = (string)rand(1,3); $client->settings = $settings; + if(rand(0,1)) + $client->assigned_user_id = $assigned_user_id; + $client->country_id = array_rand([36,392,840,124,276,826]); $client->save(); @@ -288,7 +291,7 @@ class DemoMode extends Command ]); } - private function createVendor($client) + private function createVendor($client, $assigned_user_id = null) { $vendor = factory(\App\Models\Vendor::class)->create([ 'user_id' => $client->user_id, @@ -311,7 +314,7 @@ class DemoMode extends Command ]); } - private function createTask($client) + private function createTask($client, $assigned_user_id = null) { $vendor = factory(\App\Models\Task::class)->create([ 'user_id' => $client->user->id, @@ -319,7 +322,7 @@ class DemoMode extends Command ]); } - private function createProject($client) + private function createProject($client, $assigned_user_id = null) { $vendor = factory(\App\Models\Project::class)->create([ 'user_id' => $client->user->id, @@ -327,7 +330,7 @@ class DemoMode extends Command ]); } - private function createInvoice($client) + private function createInvoice($client, $assigned_user_id = null) { // for($x=0; $x<$this->count; $x++){ // dispatch(new CreateTestInvoiceJob($client)); @@ -373,6 +376,9 @@ class DemoMode extends Command $invoice = $invoice_calc->getInvoice(); + if(rand(0,1)) + $invoice->assigned_user_id = $assigned_user_id; + $invoice->save(); $invoice->service()->createInvitations()->markSent(); @@ -383,7 +389,7 @@ class DemoMode extends Command $invoice = $invoice->service()->markPaid()->save(); $invoice->payments->each(function ($payment){ - $payment->date = now()->addDays(rand(0,90)); + $payment->date = now()->addDays(rand(-30,30)); $payment->save(); }); } @@ -391,7 +397,7 @@ class DemoMode extends Command event(new InvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars())); } - private function createCredit($client) + private function createCredit($client, $assigned_user_id = null) { // for($x=0; $x<$this->count; $x++){ @@ -434,12 +440,15 @@ class DemoMode extends Command $credit = $invoice_calc->getCredit(); + if(rand(0,1)) + $credit->assigned_user_id = $assigned_user_id; + $credit->save(); $credit->service()->markSent()->save(); $credit->service()->createInvitations(); } - private function createQuote($client) + private function createQuote($client, $assigned_user_id = null) { $faker = \Faker\Factory::create(); @@ -487,6 +496,9 @@ class DemoMode extends Command $quote = $quote_calc->getQuote(); + if(rand(0,1)) + $quote->assigned_user_id = $assigned_user_id; + $quote->save(); $quote->service()->markSent()->save(); diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 58342ac5c3ed..0bd9b3c9611d 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -11,6 +11,7 @@ namespace App\Console; +use App\Console\Commands\CheckData; use App\Jobs\Cron\RecurringInvoicesCron; use App\Jobs\Ninja\AdjustEmailQuota; use App\Jobs\Ninja\CheckDbStatus; @@ -46,6 +47,8 @@ class Kernel extends ConsoleKernel //$schedule->job(new RecurringInvoicesCron)->hourly(); $schedule->job(new VersionCheck)->daily(); + $schedule->command('ninja:check-data')->daily(); + $schedule->job(new ReminderJob)->daily(); $schedule->job(new CompanySizeCheck)->daily(); diff --git a/app/DataMapper/FreeCompanySettings.php b/app/DataMapper/FreeCompanySettings.php index 9f18d759972c..9ddfaf34de9c 100644 --- a/app/DataMapper/FreeCompanySettings.php +++ b/app/DataMapper/FreeCompanySettings.php @@ -45,7 +45,7 @@ class FreeCompanySettings extends BaseSettings public $military_time = false; public $payment_number_pattern = ''; public $payment_number_counter = 1; - public $payment_terms = -1; + public $payment_terms = ""; public $payment_type_id = '0'; public $portal_design_id = '1'; public $quote_design_id = 'VolejRejNm'; @@ -112,7 +112,7 @@ class FreeCompanySettings extends BaseSettings 'custom_value4' => 'string', 'inclusive_taxes' => 'bool', 'name' => 'string', - 'payment_terms' => 'integer', + 'payment_terms' => 'string', 'payment_type_id' => 'string', 'phone' => 'string', 'postal_code' => 'string', diff --git a/app/Events/Credit/CreditWasDeleted.php b/app/Events/Credit/CreditWasDeleted.php new file mode 100644 index 000000000000..e081891a2c13 --- /dev/null +++ b/app/Events/Credit/CreditWasDeleted.php @@ -0,0 +1,41 @@ +credit = $credit; + $this->company = $company; + $this->event_vars = $event_vars; + } +} diff --git a/app/Events/Quote/QuoteWasViewed.php b/app/Events/Quote/QuoteWasViewed.php new file mode 100644 index 000000000000..10b68f756042 --- /dev/null +++ b/app/Events/Quote/QuoteWasViewed.php @@ -0,0 +1,37 @@ +invitation = $invitation; + $this->company = $company; + $this->event_vars = $event_vars; + } +} diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index aafe25931921..79e78569714b 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -36,7 +36,7 @@ class Handler extends ExceptionHandler * @var array */ protected $dontReport = [ - // + \PDOException::class, ]; /** @@ -81,6 +81,7 @@ class Handler extends ExceptionHandler } }); +// app('sentry')->setRelease(config('ninja.app_version')); app('sentry')->captureException($exception); } @@ -117,6 +118,7 @@ class Handler extends ExceptionHandler } elseif ($exception instanceof MethodNotAllowedHttpException && $request->expectsJson()) { return response()->json(['message'=>'Method not support for this route'], 404); } elseif ($exception instanceof ValidationException && $request->expectsJson()) { +// info(print_r($exception->validator->getMessageBag(),1)); return response()->json(['message' => 'The given data was invalid.', 'errors' => $exception->validator->getMessageBag()], 422); } elseif ($exception instanceof RelationNotFoundException && $request->expectsJson()) { return response()->json(['message' => $exception->getMessage()], 400); diff --git a/app/Factory/CompanyFactory.php b/app/Factory/CompanyFactory.php index da387a0efa54..56acba7f75ea 100644 --- a/app/Factory/CompanyFactory.php +++ b/app/Factory/CompanyFactory.php @@ -34,7 +34,7 @@ class CompanyFactory //$company->custom_fields = (object) ['invoice1' => '1', 'invoice2' => '2', 'client1'=>'3']; $company->custom_fields = (object) []; $company->subdomain = ''; - $company->enabled_modules = 8191; //4095 + $company->enabled_modules = 32767;//8191; //4095 return $company; } diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 24af5f7a9bfc..cef903d81f98 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -137,36 +137,39 @@ class BaseController extends Controller $transformer = new $this->entity_transformer(Input::get('serializer')); $includes = $transformer->getDefaultIncludes(); - $includes = $this->getRequestIncludes($includes); + //info(print_r($includes,1)); + $updated_at = request()->has('updated_at') ? request()->input('updated_at') : 0; $updated_at = date('Y-m-d H:i:s', $updated_at); + //info($updated_at); + $query->with( [ 'company' => function ($query) use($updated_at){$query->where('updated_at', '>=', 0);}, 'company.activities' => function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, - 'company.clients' =>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.tax_rates'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.groups'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.company_gateways'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.clients.contacts'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.products'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.invoices.invitations'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.invoices.invitations'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.invoices.documents'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.payments.paymentables'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.quotes.invitations'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.quotes.documents'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.credits.invitations'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.credits'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.payment_terms'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.vendors'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.expenses'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.tasks'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.projects'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, - 'company.designs'=>function ($query) use($updated_at){$query->where('updated_at', '>', $updated_at);}, + 'company.clients' =>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.tax_rates'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.groups'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.company_gateways'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.clients.contacts'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.products'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.invoices.invitations.contact'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.invoices.invitations'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.invoices.documents'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.payments.paymentables'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.quotes.invitations'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.quotes.documents'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.credits.invitations'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.credits'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.payment_terms'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.vendors'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.expenses'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.tasks'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.projects'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.designs'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, ] ); @@ -311,6 +314,7 @@ class BaseController extends Controller 'company.quotes.invitations.contact', 'company.quotes.invitations.company', 'company.quotes.documents', + 'company.credits.invitations.contact', 'company.credits.invitations.company', 'company.credits.documents', 'company.payment_terms.company', @@ -340,7 +344,7 @@ class BaseController extends Controller * Thresholds for displaying large account on first load */ if (request()->has('first_load') && request()->input('first_load') == 'true') { - if (auth()->user()->getCompany()->is_large) { + if (auth()->user()->getCompany()->is_large && request()->missing('updated_at')) { $data = $mini_load; } else { $data = $first_load; diff --git a/app/Http/Controllers/MigrationController.php b/app/Http/Controllers/MigrationController.php index 59c7db415a5a..b2369aa84a8f 100644 --- a/app/Http/Controllers/MigrationController.php +++ b/app/Http/Controllers/MigrationController.php @@ -228,6 +228,7 @@ class MigrationController extends BaseController $company_token->account_id = $account->id; $company_token->name = $request->token_name ?? Str::random(12); $company_token->token = $request->token ?? \Illuminate\Support\Str::random(64); + $company_token->is_system = true; $company_token->save(); $user->companies()->attach($company->id, [ @@ -287,6 +288,8 @@ class MigrationController extends BaseController $company_token->account_id = $account->id; $company_token->name = $request->token_name ?? Str::random(12); $company_token->token = $request->token ?? \Illuminate\Support\Str::random(64); + $company_token->is_system = true; + $company_token->save(); $user->companies()->attach($company->id, [ @@ -320,6 +323,8 @@ class MigrationController extends BaseController $company_token->account_id = $account->id; $company_token->name = $request->token_name ?? Str::random(12); $company_token->token = $request->token ?? \Illuminate\Support\Str::random(64); + $company_token->is_system = true; + $company_token->save(); $user->companies()->attach($company->id, [ @@ -346,6 +351,8 @@ class MigrationController extends BaseController $company_token->account_id = $account->id; $company_token->name = $request->token_name ?? Str::random(12); $company_token->token = $request->token ?? \Illuminate\Support\Str::random(64); + $company_token->is_system = true; + $company_token->save(); $user->companies()->attach($company->id, [ diff --git a/app/Http/Controllers/SelfUpdateController.php b/app/Http/Controllers/SelfUpdateController.php index 968db83dcfaf..bfa265cdd261 100644 --- a/app/Http/Controllers/SelfUpdateController.php +++ b/app/Http/Controllers/SelfUpdateController.php @@ -15,6 +15,7 @@ use App\Utils\Ninja; use Composer\Factory; use Composer\IO\NullIO; use Composer\Installer; +use Cz\Git\GitException; use Cz\Git\GitRepository; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Support\Facades\Artisan; @@ -73,8 +74,12 @@ class SelfUpdateController extends BaseController info("Are there changes to pull? " . $repo->hasChanges()); + try{ $res = $repo->pull(); - + } + catch(GitException $e) { + info($e->getMessage()); + } info("Are there any changes to pull? " . $repo->hasChanges()); Artisan::call('ninja:post-update'); diff --git a/app/Http/Controllers/SetupController.php b/app/Http/Controllers/SetupController.php index 84f3fdd6325d..a174e7e07b28 100644 --- a/app/Http/Controllers/SetupController.php +++ b/app/Http/Controllers/SetupController.php @@ -205,4 +205,6 @@ class SetupController extends Controller return response([], 500); } } + + } diff --git a/app/Http/Middleware/QueryLogging.php b/app/Http/Middleware/QueryLogging.php index 659612e4d831..0c29045eeeef 100644 --- a/app/Http/Middleware/QueryLogging.php +++ b/app/Http/Middleware/QueryLogging.php @@ -48,7 +48,7 @@ class QueryLogging $timeEnd = microtime(true); $time = $timeEnd - $timeStart; - // Log::info($request->method() . ' - ' . $request->url() . ": $count queries - " . $time); + Log::info($request->method() . ' - ' . $request->url() . ": $count queries - " . $time); //if($count > 10) // Log::info($queries); diff --git a/app/Http/Requests/Payment/StorePaymentRequest.php b/app/Http/Requests/Payment/StorePaymentRequest.php index f53da29920ed..0fa435f4fa49 100644 --- a/app/Http/Requests/Payment/StorePaymentRequest.php +++ b/app/Http/Requests/Payment/StorePaymentRequest.php @@ -39,6 +39,8 @@ class StorePaymentRequest extends Request { $input = $this->all(); + //info(print_r($input,1)); + $invoices_total = 0; $credits_total = 0; diff --git a/app/Http/ValidationRules/Credit/ValidCreditsRules.php b/app/Http/ValidationRules/Credit/ValidCreditsRules.php index 1cdaf11eca44..527b5a2f310b 100644 --- a/app/Http/ValidationRules/Credit/ValidCreditsRules.php +++ b/app/Http/ValidationRules/Credit/ValidCreditsRules.php @@ -78,6 +78,11 @@ class ValidCreditsRules implements Rule } + if(count($this->input['credits']) >=1 && count($this->input['invoices']) == 0){ + $this->error_msg = "You must have an invoice set when using a credit in a payment"; + return false; + } + return true; } diff --git a/app/Http/ValidationRules/Ninja/CanAddUserRule.php b/app/Http/ValidationRules/Ninja/CanAddUserRule.php index 75bf15f5e552..3665a3757f97 100644 --- a/app/Http/ValidationRules/Ninja/CanAddUserRule.php +++ b/app/Http/ValidationRules/Ninja/CanAddUserRule.php @@ -35,7 +35,7 @@ class CanAddUserRule implements Rule */ public function passes($attribute, $value) { - return $this->account->num_users < $this->account->pending_num_users; + return $this->account->users->count() < $this->account->num_users; } /** @@ -43,7 +43,7 @@ class CanAddUserRule implements Rule */ public function message() { - return ctrans('texts.limit_users', ['limit' => $this->account->pending_num_users]); + return ctrans('texts.limit_users', ['limit' => $this->account->num_users]); } } diff --git a/app/Jobs/Company/CreateCompanyToken.php b/app/Jobs/Company/CreateCompanyToken.php index 26bdf1601140..da8a07d3e2c2 100644 --- a/app/Jobs/Company/CreateCompanyToken.php +++ b/app/Jobs/Company/CreateCompanyToken.php @@ -59,6 +59,8 @@ class CreateCompanyToken implements ShouldQueue $company_token->account_id = $this->user->account->id; $company_token->name = $this->custom_token_name ?: $this->user->first_name. ' '. $this->user->last_name; $company_token->token = Str::random(64); + $company_token->is_system = true; + $company_token->save(); diff --git a/app/Listeners/Activity/CreatedQuoteActivity.php b/app/Listeners/Activity/CreatedQuoteActivity.php new file mode 100644 index 000000000000..5b6bd86d76ee --- /dev/null +++ b/app/Listeners/Activity/CreatedQuoteActivity.php @@ -0,0 +1,53 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new \stdClass; + + $fields->quote_id = $event->quote->id; + $fields->user_id = $event->quote->user_id; + $fields->company_id = $event->quote->company_id; + $fields->activity_type_id = Activity::CREATE_QUOTE; + + $this->activity_repo->save($fields, $event->quote, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/DeleteCreditActivity.php b/app/Listeners/Activity/DeleteCreditActivity.php new file mode 100644 index 000000000000..c24033921f5a --- /dev/null +++ b/app/Listeners/Activity/DeleteCreditActivity.php @@ -0,0 +1,54 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new \stdClass; + + $fields->client_id = $event->credit->client_id; + $fields->credit_id = $event->credit->id; + $fields->user_id = $event->credit->user_id; + $fields->company_id = $event->credit->company_id; + $fields->activity_type_id = Activity::DELETE_CREDIT; + + $this->activity_repo->save($fields, $event->credit, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/QuoteUpdatedActivity.php b/app/Listeners/Activity/QuoteUpdatedActivity.php new file mode 100644 index 000000000000..9a8da1507137 --- /dev/null +++ b/app/Listeners/Activity/QuoteUpdatedActivity.php @@ -0,0 +1,70 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $quote = $event->quote; + + $invoices = $payment->invoices; + + $fields = new \stdClass; + + $fields->payment_id = $quote->id; + $fields->user_id = $quote->user_id; + $fields->company_id = $quote->company_id; + $fields->activity_type_id = Activity::UPDATE_QUOTE; + + $this->activity_repo->save($fields, $quote, $event->event_vars); + + // foreach ($invoices as $invoice) { + // //todo we may need to add additional logic if in the future we apply payments to other entity Types, not just invoices + // $fields->invoice_id = $invoice->id; + + // $this->activity_repo->save($fields, $invoice, $event->event_vars); + // } + + // if (count($invoices) == 0) { + // $this->activity_repo->save($fields, $payment, $event->event_vars); + // } + } +} diff --git a/app/Listeners/Quote/QuoteEmailActivity.php b/app/Listeners/Quote/QuoteEmailActivity.php new file mode 100644 index 000000000000..dffcb72ce767 --- /dev/null +++ b/app/Listeners/Quote/QuoteEmailActivity.php @@ -0,0 +1,57 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new \stdClass; + + $fields->quote_id = $event->invitation->quote->id; + $fields->user_id = $event->invitation->quote->user_id; + $fields->company_id = $event->invitation->quote->company_id; + $fields->client_contact_id = $event->invitation->quote->client_contact_id; + $fields->activity_type_id = Activity::EMAIL_QUOTE; + + $this->activity_repo->save($fields, $event->invitation->quote, $event->event_vars); + } +} diff --git a/app/Listeners/Quote/QuoteViewedActivity.php b/app/Listeners/Quote/QuoteViewedActivity.php new file mode 100644 index 000000000000..a10c8e78fd24 --- /dev/null +++ b/app/Listeners/Quote/QuoteViewedActivity.php @@ -0,0 +1,59 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new \stdClass; + + $fields->user_id = $event->quote->user_id; + $fields->company_id = $event->quote->company_id; + $fields->activity_type_id = Activity::VIEW_QUOTE; + $fields->client_id = $event->invitation->client_id; + $fields->client_contact_id = $event->invitation->client_contact_id; + $fields->invitation_id = $event->invitation->id; + $fields->quote_id = $event->invitation->quote_id; + + $this->activity_repo->save($fields, $event->quote, $event->event_vars); + } +} diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 25b259d8724b..79432dabbc3a 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -30,12 +30,12 @@ class Activity extends StaticModel const DELETE_PAYMENT=13; // const CREATE_CREDIT=14; // const UPDATE_CREDIT=15; // - const ARCHIVE_CREDIT=16; - const DELETE_CREDIT=17; - const CREATE_QUOTE=18; - const UPDATE_QUOTE=19; - const EMAIL_QUOTE=20; - const VIEW_QUOTE=21; + const ARCHIVE_CREDIT=16; // + const DELETE_CREDIT=17; // + const CREATE_QUOTE=18; // + const UPDATE_QUOTE=19; // + const EMAIL_QUOTE=20; // + const VIEW_QUOTE=21; // const ARCHIVE_QUOTE=22; const DELETE_QUOTE=23; const RESTORE_QUOTE=24; diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 8019d9409a7d..d493ca9e84cf 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -23,6 +23,7 @@ use App\Events\Company\CompanyDocumentsDeleted; use App\Events\Contact\ContactLoggedIn; use App\Events\Credit\CreditWasArchived; use App\Events\Credit\CreditWasCreated; +use App\Events\Credit\CreditWasDeleted; use App\Events\Credit\CreditWasEmailedAndFailed; use App\Events\Credit\CreditWasMarkedSent; use App\Events\Credit\CreditWasUpdated; @@ -45,19 +46,26 @@ use App\Events\Payment\PaymentWasRefunded; use App\Events\Payment\PaymentWasUpdated; use App\Events\Payment\PaymentWasVoided; use App\Events\Quote\QuoteWasApproved; +use App\Events\Quote\QuoteWasCreated; +use App\Events\Quote\QuoteWasEmailed; +use App\Events\Quote\QuoteWasUpdated; +use App\Events\Quote\QuoteWasViewed; use App\Events\User\UserLoggedIn; use App\Events\User\UserWasCreated; use App\Events\User\UserWasDeleted; use App\Listeners\Activity\ArchivedClientActivity; use App\Listeners\Activity\CreatedClientActivity; use App\Listeners\Activity\CreatedCreditActivity; +use App\Listeners\Activity\CreatedQuoteActivity; use App\Listeners\Activity\CreditArchivedActivity; use App\Listeners\Activity\DeleteClientActivity; +use App\Listeners\Activity\DeleteCreditActivity; use App\Listeners\Activity\PaymentCreatedActivity; use App\Listeners\Activity\PaymentDeletedActivity; use App\Listeners\Activity\PaymentRefundedActivity; use App\Listeners\Activity\PaymentUpdatedActivity; use App\Listeners\Activity\PaymentVoidedActivity; +use App\Listeners\Activity\QuoteUpdatedActivity; use App\Listeners\Activity\RestoreClientActivity; use App\Listeners\Activity\UpdatedCreditActivity; use App\Listeners\Contact\UpdateContactLastLogin; @@ -76,6 +84,8 @@ use App\Listeners\Invoice\UpdateInvoiceActivity; use App\Listeners\Invoice\UpdateInvoiceInvitations; use App\Listeners\Misc\InvitationViewedListener; use App\Listeners\Payment\PaymentNotification; +use App\Listeners\Quote\QuoteEmailActivity; +use App\Listeners\Quote\QuoteViewedActivity; use App\Listeners\Quote\ReachWorkflowSettings; use App\Listeners\SendVerificationNotification; use App\Listeners\SetDBListener; @@ -151,6 +161,9 @@ class EventServiceProvider extends ServiceProvider CreditWasCreated::class => [ CreatedCreditActivity::class, ], + CreditWasDeleted::class => [ + DeleteCreditActivity::class, + ], CreditWasUpdated::class => [ UpdatedCreditActivity::class, ], @@ -216,6 +229,19 @@ class EventServiceProvider extends ServiceProvider QuoteWasApproved::class => [ ReachWorkflowSettings::class, ], + QuoteWasCreated::class => [ + CreatedQuoteActivity::class, + ], + QuoteWasUpdated::class => [ + QuoteUpdatedActivity::class, + ], + QuoteWasEmailed::class => [ + QuoteEmailActivity::class, + ], + QuoteWasViewed::class => [ + QuoteViewedActivity::class, + ], + ]; /** diff --git a/app/Repositories/BaseRepository.php b/app/Repositories/BaseRepository.php index c96cdf52577f..05858f8c83b2 100644 --- a/app/Repositories/BaseRepository.php +++ b/app/Repositories/BaseRepository.php @@ -178,7 +178,7 @@ class BaseRepository public function getInvitation($invitation, $resource) { - if (!array_key_exists('key', $invitation)) { + if (is_array($invitation) && !array_key_exists('key', $invitation)) { return false; } @@ -253,7 +253,15 @@ class BaseRepository /* Get array of Keys which have been removed from the invitations array and soft delete each invitation */ $model->invitations->pluck('key')->diff($invitations->pluck('key'))->each(function ($invitation) use($resource){ - $this->getInvitation($invitation, $resource)->delete(); + // $this->getInvitation($invitation, $resource)->delete(); + + $invitation_class = sprintf("App\\Models\\%sInvitation", $resource); + + $invitation = $invitation_class::whereRaw("BINARY `key`= ?", [$invitation])->first(); + + if($invitation) + $invitation->delete(); + }); foreach ($data['invitations'] as $invitation) { diff --git a/app/Repositories/TokenRepository.php b/app/Repositories/TokenRepository.php index d63cb6f54ae0..18aca4b3b7ac 100644 --- a/app/Repositories/TokenRepository.php +++ b/app/Repositories/TokenRepository.php @@ -37,7 +37,7 @@ class TokenRepository extends BaseRepository public function save(array $data, CompanyToken $company_token) { $company_token->fill($data); - $company_token->is_system = true; + $company_token->is_system = false; $company_token->save(); diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 10b6ba0a8438..714b2727ea05 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -161,11 +161,9 @@ class InvoiceService /* One liners */ public function setDueDate() { - if($this->invoice->due_date != '') + if($this->invoice->due_date != '' || $this->invoice->client->getSetting('payment_terms') == '') return $this; - //$this->invoice->due_date = Carbon::now()->addDays($this->invoice->client->getSetting('payment_terms')); - $this->invoice->due_date = Carbon::parse($this->invoice->date)->addDays($this->invoice->client->getSetting('payment_terms')); return $this; diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index 0c2a11abc149..58e3242a7eda 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -68,19 +68,12 @@ class AccountTransformer extends EntityTransformer 'payment_id' => (string) $account->payment_id, 'trial_started' => (string) $account->trial_started, 'trial_plan' => (string) $account->trial_plan, - 'pending_plan' => (string) $account->pending_plan, - 'pending_term' => (string) $account->pending_term, 'plan_price' => (float) $account->plan_price, - 'pending_plan_price' => (string) $account->pending_plan_price, 'num_users' => (int) $account->num_users, - 'pending_num_users' => (int) $account->pending_num_users, 'utm_source' => (string) $account->utm_source, 'utm_medium' => (string) $account->utm_medium, 'utm_content' => (string) $account->utm_content, 'utm_term' => (string) $account->utm_term, - 'discount' => (float) $account->discount, - 'discount_expires' => (string) $account->discount_expires, - 'bluevine_status' => (string) $account->bluevine_status, 'referral_code' => (string) $account->referral_code, 'latest_version' => (string)$account->latest_version, 'current_version' => (string)config('ninja.app_version'), diff --git a/app/Utils/SystemHealth.php b/app/Utils/SystemHealth.php index 09ae9451aa68..9d0f031202e5 100644 --- a/app/Utils/SystemHealth.php +++ b/app/Utils/SystemHealth.php @@ -71,9 +71,43 @@ class SystemHealth 'env_writable' => self::checkEnvWritable(), //'mail' => self::testMailServer(), 'simple_db_check' => (bool) self::simpleDbCheck(), + 'npm_status' => self::checkNpm(), + 'node_status' => self::checkNode(), ]; } + public static function checkNode() + { + try { + exec('node -v', $foo, $exitCode); + + if ($exitCode === 0) { + return $foo[0]; + } + + } catch (\Exception $e) { + + return false; + } + + } + + public static function checkNpm() + { + try { + exec('npm -v', $foo, $exitCode); + + if ($exitCode === 0) { + return $foo[0]; + } + + }catch (\Exception $e) { + + return false; + } + + } + private static function simpleDbCheck() :bool { $result = true; diff --git a/config/ninja.php b/config/ninja.php index 0fd26a26c041..38d93fc5842c 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -8,7 +8,7 @@ return [ 'license' => env('NINJA_LICENSE', ''), 'version_url' => 'https://raw.githubusercontent.com/invoiceninja/invoiceninja/v2/VERSION.txt', 'app_name' => env('APP_NAME'), - 'app_env' => env('APP_ENV', 'local'), + 'app_env' => env('APP_ENV', 'selfhosted'), 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => env('APP_URL', ''), 'app_domain' => env('APP_DOMAIN', ''), @@ -56,7 +56,7 @@ return [ 'datetime_format_id' => env('DEFAULT_DATETIME_FORMAT_ID', '1'), 'locale' => env('DEFAULT_LOCALE', 'en'), 'map_zoom' => env('DEFAULT_MAP_ZOOM', 10), - 'payment_terms' => env('DEFAULT_PAYMENT_TERMS', "-1"), + 'payment_terms' => env('DEFAULT_PAYMENT_TERMS', ""), 'military_time' => env('MILITARY_TIME', 0), 'first_day_of_week' => env('FIRST_DATE_OF_WEEK', 0), 'first_month_of_year' => env('FIRST_MONTH_OF_YEAR', '2000-01-01') diff --git a/config/sentry.php b/config/sentry.php new file mode 100644 index 000000000000..e428cbbce513 --- /dev/null +++ b/config/sentry.php @@ -0,0 +1,30 @@ + env('SENTRY_LARAVEL_DSN', env('SENTRY_DSN')), + + // capture release as git sha + // 'release' => trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')), + + 'breadcrumbs' => [ + // Capture Laravel logs in breadcrumbs + 'logs' => true, + + // Capture SQL queries in breadcrumbs + 'sql_queries' => true, + + // Capture bindings on SQL queries logged in breadcrumbs + 'sql_bindings' => true, + + // Capture queue job information in breadcrumbs + 'queue_info' => true, + + // Capture command information in breadcrumbs + 'command_info' => true, + ], + + // @see: https://docs.sentry.io/error-reporting/configuration/?platform=php#send-default-pii + 'send_default_pii' => false, + 'release' => config('ninja.app_version'), +]; diff --git a/database/migrations/2014_10_13_000000_create_users_table.php b/database/migrations/2014_10_13_000000_create_users_table.php index cee12a11992f..1141ee17b48d 100644 --- a/database/migrations/2014_10_13_000000_create_users_table.php +++ b/database/migrations/2014_10_13_000000_create_users_table.php @@ -112,13 +112,8 @@ class CreateUsersTable extends Migration $table->date('trial_started')->nullable(); $table->enum('trial_plan', ['pro', 'enterprise'])->nullable(); - $table->enum('pending_plan', ['pro', 'enterprise', 'free'])->nullable(); - $table->enum('pending_term', ['month', 'year'])->nullable(); - $table->decimal('plan_price', 7, 2)->nullable(); - $table->decimal('pending_plan_price', 7, 2)->nullable(); $table->smallInteger('num_users')->default(1); - $table->smallInteger('pending_num_users')->default(1); $table->string('utm_source')->nullable(); $table->string('utm_medium')->nullable(); @@ -128,10 +123,6 @@ class CreateUsersTable extends Migration $table->string('latest_version')->default('0.0.0'); $table->boolean('report_errors')->default(false); - $table->float('discount')->default(0); - $table->date('discount_expires')->nullable(); - - $table->enum('bluevine_status', ['ignored', 'signed_up'])->nullable(); $table->string('referral_code')->nullable(); $table->timestamps(6); diff --git a/database/migrations/2020_07_21_112424_update_enabled_modules_value.php b/database/migrations/2020_07_21_112424_update_enabled_modules_value.php new file mode 100644 index 000000000000..8acb3e848777 --- /dev/null +++ b/database/migrations/2020_07_21_112424_update_enabled_modules_value.php @@ -0,0 +1,32 @@ +each(function ($company){ + $company->enabled_modules = 32767; + $company->save(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 1edee92a325d..ab526a5efcc9 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3238,5 +3238,7 @@ return [ 'checkout_authorize_label' => 'Checkout.com can be can saved as payment method for future use, once you complete your first transaction. Don\'t forget to check "Save card" during payment process.', + 'node_status_not_found' => 'I could not find Node anywhere. Is it installed?', + 'npm_status_not_found' => 'I could not find NPM anywhere. Is it installed?', ]; diff --git a/resources/views/setup/_issues.blade.php b/resources/views/setup/_issues.blade.php index 7baf3165456e..896648389ca5 100644 --- a/resources/views/setup/_issues.blade.php +++ b/resources/views/setup/_issues.blade.php @@ -61,6 +61,42 @@ @endif +
NPM Version => {{$check['npm_status']}}
+Node Version => {{$check['node_status']}}
+