From 2190aadf9e773fdfa50333607296bf40f34959e9 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 29 Jan 2021 07:44:56 +1100 Subject: [PATCH 1/7] minor fixes for texts --- resources/lang/en/texts.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index e0baaf184b5e..76909da18ce5 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -286,7 +286,7 @@ return [ 'password' => 'Password', 'pro_plan_product' => 'Pro Plan', 'pro_plan_success' => 'Thanks for choosing Invoice Ninja\'s Pro plan! 
- Next StepsA payable invoice has been sent to the email + Next Steps. A payable invoice has been sent to the email address associated with your account. To unlock all of the awesome Pro features, please follow the instructions on the invoice to pay for a year of Pro-level invoicing. @@ -1091,7 +1091,7 @@ return [ 'invoice_item_fields' => 'Invoice Item Fields', 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Recurring Number', - 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices.', + 'recurring_invoice_number_prefix_help' => 'Specify a prefix to be added to the invoice number for recurring invoices.', // Client Passwords 'enable_portal_password' => 'Password Protect Invoices', From e669718adb59d114840f67151773ac78bd219dca Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 29 Jan 2021 13:18:21 +1100 Subject: [PATCH 2/7] Fixes for client counter across entities --- app/Utils/Traits/GeneratesCounter.php | 48 ++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/app/Utils/Traits/GeneratesCounter.php b/app/Utils/Traits/GeneratesCounter.php index 45b31134b4e0..621d16fa3593 100644 --- a/app/Utils/Traits/GeneratesCounter.php +++ b/app/Utils/Traits/GeneratesCounter.php @@ -97,10 +97,23 @@ trait GeneratesCounter $pattern = $client->getSetting('credit_number_pattern'); //Determine if we are using client_counters if (strpos($pattern, 'clientCounter') || strpos($pattern, 'client_counter')) { - $counter = $client->settings->credit_number_counter; + + if (property_exists($client->settings, 'credit_number_counter')) { + $counter = $client->settings->credit_number_counter; + } else { + $counter = 1; + } + $counter_entity = $client; + } elseif (strpos($pattern, 'groupCounter') || strpos($pattern, 'group_counter')) { - $counter = $client->group_settings->credit_number_counter; + + if (property_exists($client->group_settings, 'credit_number_counter')) { + $counter = $client->group_settings->credit_number_counter; + } else { + $counter = 1; + } + $counter_entity = $client->group_settings; } else { $counter = $client->company->settings->credit_number_counter; @@ -133,11 +146,24 @@ trait GeneratesCounter $pattern = $client->getSetting('quote_number_pattern'); //Determine if we are using client_counters if (strpos($pattern, 'clientCounter') || strpos($pattern, 'client_counter')) { - $counter = $client->settings->{$used_counter}; + + if (property_exists($client->settings, $used_counter)) { + $counter = $client->settings->{$used_counter}; + } else { + $counter = 1; + } + $counter_entity = $client; } elseif (strpos($pattern, 'groupCounter') || strpos($pattern, 'group_counter')) { + + if (property_exists($client->group_settings, $used_counter)) { $counter = $client->group_settings->{$used_counter}; + } else { + $counter = 1; + } + $counter_entity = $client->group_settings; + } else { $counter = $client->company->settings->{$used_counter}; $counter_entity = $client->company; @@ -172,7 +198,13 @@ trait GeneratesCounter if (strpos($pattern, 'client_counter') === false) { $counter = $client->company->settings->recurring_invoice_number_counter; } else { - $counter = $client->settings->recurring_invoice_number_counter; + + if (property_exists($client->settings, 'recurring_invoice_number_counter')) { + $counter = $client->settings->recurring_invoice_number_counter; + } else { + $counter = 1; + } + $is_client_counter = true; } @@ -212,7 +244,13 @@ trait GeneratesCounter if (strpos($pattern, 'client_counter') === false) { $counter = $client->company->settings->payment_number_counter; } else { - $counter = $client->settings->payment_number_counter; + + if (property_exists($client->settings, 'payment_number_counter')) { + $counter = $client->settings->payment_number_counter; + } else { + $counter = 1; + } + $is_client_counter = true; } From dbfee7d5194eae19bf2a2d14b610404f0f63ee7e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 29 Jan 2021 16:41:19 +1100 Subject: [PATCH 3/7] Refactor for invoice number generator --- app/Utils/Traits/GeneratesCounter.php | 133 ++++++++++++++++++++------ 1 file changed, 105 insertions(+), 28 deletions(-) diff --git a/app/Utils/Traits/GeneratesCounter.php b/app/Utils/Traits/GeneratesCounter.php index 621d16fa3593..d209eddf8fa2 100644 --- a/app/Utils/Traits/GeneratesCounter.php +++ b/app/Utils/Traits/GeneratesCounter.php @@ -132,23 +132,30 @@ trait GeneratesCounter } public function getNextQuoteNumber(Client $client) + { + return $this->getNextEntityNumber(Quote::class, $client); + } + + private function getNextEntityNumber($entity, Client $client) { //Reset counters if enabled $this->resetCounters($client); - $used_counter = 'quote_number_counter'; + $is_client_counter = false; - if ($this->hasSharedCounter($client)) { - $used_counter = 'invoice_number_counter'; - } + $counter_pattern = $this->getNumberPattern($entity, $client); + $counter_string = $this->getEntityCounter($entity, $client); + + $pattern = $client->getSetting($counter_pattern); + + nlog($counter_pattern); + nlog($counter_string); + nlog($pattern); - //todo handle if we have specific client patterns in the future - $pattern = $client->getSetting('quote_number_pattern'); - //Determine if we are using client_counters if (strpos($pattern, 'clientCounter') || strpos($pattern, 'client_counter')) { - if (property_exists($client->settings, $used_counter)) { - $counter = $client->settings->{$used_counter}; + if (property_exists($client->settings, $counter_string)) { + $counter = $client->settings->{$counter_string}; } else { $counter = 1; } @@ -156,8 +163,8 @@ trait GeneratesCounter $counter_entity = $client; } elseif (strpos($pattern, 'groupCounter') || strpos($pattern, 'group_counter')) { - if (property_exists($client->group_settings, $used_counter)) { - $counter = $client->group_settings->{$used_counter}; + if (property_exists($client->group_settings, $counter_string)) { + $counter = $client->group_settings->{$counter_string}; } else { $counter = 1; } @@ -165,22 +172,82 @@ trait GeneratesCounter $counter_entity = $client->group_settings; } else { - $counter = $client->company->settings->{$used_counter}; + $counter = $client->company->settings->{$counter_string}; $counter_entity = $client->company; } - //Return a valid counter - $pattern = $client->getSetting('quote_number_pattern'); + + //If it is a quote - we need to + $pattern = $this->getNumberPattern($entity, $client); + $padding = $client->getSetting('counter_padding'); - $quote_number = $this->checkEntityNumber(Quote::class, $client, $counter, $padding, $pattern); + $entity_number = $this->checkEntityNumber($entity, $client, $counter, $padding, $pattern); - // if($this->recurring_id) - // $quote_number = $this->prefixCounter($quote_number, $client->getSetting('recurring_number_prefix')); + $this->incrementCounter($counter_entity, $counter_string); - $this->incrementCounter($counter_entity, $used_counter); + return $entity_number; - return $quote_number; + } + + private function getNumberPattern($entity, Client $client) + { + $pattern_string = ''; + + switch ($entity) { + case Invoice::class: + $pattern_string = 'invoice_number_pattern'; + break; + case Quote::class: + $pattern_string = 'quote_number_pattern'; + break; + case RecurringInvoice::class: + $pattern_string = 'recurring_invoice_number_pattern'; + break; + case Payment::class: + $pattern_string = 'payment_number_pattern'; + break; + case Credit::class: + $pattern_string = 'credit_number_pattern'; + break; + case Project::class: + $pattern_string = 'project_number_pattern'; + break; + } + + return $client->getSetting($pattern_string); + } + + private function getEntityCounter($entity, $client) + { + switch ($entity) { + case Invoice::class: + return 'invoice_number_counter'; + break; + case Quote::class: + + if ($this->hasSharedCounter($client)) + return 'invoice_number_counter'; + + return 'quote_number_counter'; + break; + case RecurringInvoice::class: + return 'recurring_invoice_number_counter'; + break; + case Payment::class: + return 'payment_number_counter'; + break; + case Credit::class: + return 'credit_number_counter'; + break; + case Project::class: + return 'project_number_counter'; + break; + + default: + return 'default_number_counter'; + break; + } } public function getNextRecurringInvoiceNumber(Client $client) @@ -194,10 +261,7 @@ trait GeneratesCounter //todo handle if we have specific client patterns in the future $pattern = $client->company->settings->recurring_invoice_number_pattern; - //Determine if we are using client_counters - if (strpos($pattern, 'client_counter') === false) { - $counter = $client->company->settings->recurring_invoice_number_counter; - } else { + if (strpos($pattern, 'clientCounter') || strpos($pattern, 'client_counter')) { if (property_exists($client->settings, 'recurring_invoice_number_counter')) { $counter = $client->settings->recurring_invoice_number_counter; @@ -205,14 +269,24 @@ trait GeneratesCounter $counter = 1; } - $is_client_counter = true; + $counter_entity = $client; + + } elseif (strpos($pattern, 'groupCounter') || strpos($pattern, 'group_counter')) { + + if (property_exists($client->group_settings, 'recurring_invoice_number_counter')) { + $counter = $client->group_settings->recurring_invoice_number_counter; + } else { + $counter = 1; + } + + $counter_entity = $client->group_settings; + } else { + $counter = $client->company->settings->recurring_invoice_number_counter; + $counter_entity = $client->company; } - //Return a valid counter - $pattern = ''; $padding = $client->getSetting('counter_padding'); $invoice_number = $this->checkEntityNumber(RecurringInvoice::class, $client, $counter, $padding, $pattern); - //$invoice_number = $this->prefixCounter($invoice_number, $client->getSetting('recurring_number_prefix')); //increment the correct invoice_number Counter (company vs client) if ($is_client_counter) { @@ -380,7 +454,7 @@ trait GeneratesCounter * * @return bool True if has shared counter, False otherwise. */ - public function hasSharedCounter(Client $client) : bool + public function hasSharedCounter(Client $client) : bool { return (bool) $client->getSetting('shared_invoice_quote_counter'); } @@ -442,6 +516,9 @@ trait GeneratesCounter $settings->invoice_number_counter = 0; } + if(!property_exists($settings, $counter_name)) + $settings->{$counter_name} = 1; + $settings->{$counter_name} = $settings->{$counter_name} + 1; $entity->settings = $settings; From e213203ed992d3a0f557d2bf1b0a0c8e6cb94d1d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 29 Jan 2021 18:36:22 +1100 Subject: [PATCH 4/7] Fixes for generates counteR" --- app/Utils/Traits/GeneratesCounter.php | 50 +++------------------------ 1 file changed, 5 insertions(+), 45 deletions(-) diff --git a/app/Utils/Traits/GeneratesCounter.php b/app/Utils/Traits/GeneratesCounter.php index d209eddf8fa2..c5b907bc843f 100644 --- a/app/Utils/Traits/GeneratesCounter.php +++ b/app/Utils/Traits/GeneratesCounter.php @@ -90,45 +90,7 @@ trait GeneratesCounter */ public function getNextCreditNumber(Client $client) :string { - //Reset counters if enabled - $this->resetCounters($client); - - //todo handle if we have specific client patterns in the future - $pattern = $client->getSetting('credit_number_pattern'); - //Determine if we are using client_counters - if (strpos($pattern, 'clientCounter') || strpos($pattern, 'client_counter')) { - - if (property_exists($client->settings, 'credit_number_counter')) { - $counter = $client->settings->credit_number_counter; - } else { - $counter = 1; - } - - $counter_entity = $client; - - } elseif (strpos($pattern, 'groupCounter') || strpos($pattern, 'group_counter')) { - - if (property_exists($client->group_settings, 'credit_number_counter')) { - $counter = $client->group_settings->credit_number_counter; - } else { - $counter = 1; - } - - $counter_entity = $client->group_settings; - } else { - $counter = $client->company->settings->credit_number_counter; - $counter_entity = $client->company; - } - - //Return a valid counter - $pattern = $client->getSetting('credit_number_pattern'); - $padding = $client->getSetting('counter_padding'); - - $credit_number = $this->checkEntityNumber(Credit::class, $client, $counter, $padding, $pattern); - - $this->incrementCounter($counter_entity, 'credit_number_counter'); - - return $credit_number; + return $this->getNextEntityNumber(Credit::class, $client); } public function getNextQuoteNumber(Client $client) @@ -143,14 +105,11 @@ trait GeneratesCounter $is_client_counter = false; - $counter_pattern = $this->getNumberPattern($entity, $client); $counter_string = $this->getEntityCounter($entity, $client); + $pattern = $this->getNumberPattern($entity, $client); - $pattern = $client->getSetting($counter_pattern); - - nlog($counter_pattern); - nlog($counter_string); - nlog($pattern); +nlog("counter string = {$counter_string}"); +nlog("pattern = {$pattern}"); if (strpos($pattern, 'clientCounter') || strpos($pattern, 'client_counter')) { @@ -176,6 +135,7 @@ trait GeneratesCounter $counter_entity = $client->company; } +nlog($counter_entity->toArray()); //If it is a quote - we need to $pattern = $this->getNumberPattern($entity, $client); From af472b21c12323d740014dfae4a9de001f41f1a9 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 29 Jan 2021 23:05:03 +1100 Subject: [PATCH 5/7] Working on filtering responses based on user permissions --- README.md | 19 ++- app/DataMapper/CompanySettings.php | 4 +- app/Http/Controllers/BaseController.php | 123 +++++++++++--- app/Models/User.php | 25 +-- app/Utils/Traits/GeneratesCounter.php | 205 ++++++------------------ 5 files changed, 178 insertions(+), 198 deletions(-) diff --git a/README.md b/README.md index 7c8727f8c0ab..77af4773cb0b 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,18 @@ ![v5-develop phpunit](https://github.com/invoiceninja/invoiceninja/workflows/phpunit/badge.svg?branch=v5-develop) ![v5-stable phpunit](https://github.com/invoiceninja/invoiceninja/workflows/phpunit/badge.svg?branch=v5-stable) -[![codecov](https://codecov.io/gh/invoiceninja/invoiceninja/branch/v2/graph/badge.svg)](https://codecov.io/gh/invoiceninja/invoiceninja) + [![Codacy Badge](https://api.codacy.com/project/badge/Grade/d39acb4bf0f74a0698dc77f382769ba5)](https://www.codacy.com/app/turbo124/invoiceninja?utm_source=github.com&utm_medium=referral&utm_content=invoiceninja/invoiceninja&utm_campaign=Badge_Grade) -# Invoice Ninja version 5 is in Beta! +# Invoice Ninja version 5.1 RC2! -We will be using the lessons learnt in Invoice Ninja 4.0 to build a bigger better platform to work from. If you would like to contribute to the project we will gladly accept contributions for code, user guides, bug tracking and feedback! Please consider the following guidelines prior to submitting a pull request: +Invoice Ninja version 5.1 has now reached Release Candidate 2! + +What does this mean exactly? We consider this version _almost_ stable. There may be some remaining small issues which we would love to get feedback on. We would really appreciate the community booting up this version and attempting the migration from their Invoice Ninja V4 application and inspect the migrated data. + +We'd also like feedback on any issues that you can see, and help us nail down the few remaining issues before Version 5 graduates to Stable Gold Release. + +Please note we do not consider this version ready for production use, please stick with your V4 installation for your production clients! ## Quick Start @@ -17,13 +23,10 @@ Currently the client portal and API are of alpha quality, to get started: ```bash git clone https://github.com/invoiceninja/invoiceninja.git -git checkout v2 +git checkout v5-stable cp .env.example .env -cp .env.dusk.example .env.dusk.local php artisan key:generate composer update -npm i -npm run production ``` Please Note: Your APP_KEY in the .env file is used to encrypt data, if you lose this you will not be able to run the application. @@ -33,7 +36,7 @@ Run if you want to load sample data, remember to configure .env php artisan migrate:fresh --seed && php artisan db:seed && php artisan ninja:create-test-data ``` -To Run the web server +To run the web server ``` php artisan serve ``` diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index 45f6ce34af0e..e1aa1975cc29 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -235,8 +235,8 @@ class CompanySettings extends BaseSettings public $font_size = 7; //@implemented public $primary_font = 'Roboto'; public $secondary_font = 'Roboto'; - public $primary_color = '#4caf50'; - public $secondary_color = '#2196f3'; + public $primary_color = '#142cb5'; + public $secondary_color = '#7081e0'; public $hide_paid_to_date = false; //@TODO where? public $embed_documents = false; //@TODO where? diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 68ac5202d06d..7ebcda5eba44 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -184,7 +184,9 @@ class BaseController extends Controller protected function refreshResponse($query) { - if (auth()->user()->getCompany()->is_large) + $user = auth()->user(); + + if ($user->getCompany()->is_large) $this->manager->parseIncludes($this->mini_load); else $this->manager->parseIncludes($this->first_load); @@ -200,74 +202,145 @@ class BaseController extends Controller $transformer = new $this->entity_transformer($this->serializer); $updated_at = request()->has('updated_at') ? request()->input('updated_at') : 0; - // if (auth()->user()->getCompany()->is_large && ! request()->has('updated_at')) { - // return response()->json(['message' => ctrans('texts.large_account_update_parameter'), 'errors' =>[]], 401); - // } - $updated_at = date('Y-m-d H:i:s', $updated_at); $query->with( [ - 'company' => function ($query) use ($updated_at) { + 'company' => function ($query) use ($updated_at, $user) { $query->whereNotNull('updated_at')->with('documents'); }, - 'company.clients' => function ($query) use ($updated_at) { + 'company.clients' => function ($query) use ($updated_at, $user) { $query->where('clients.updated_at', '>=', $updated_at)->with('contacts.company', 'gateway_tokens', 'documents'); + + if(!$user->hasPermission('view_client')) + $query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id); + }, - 'company.company_gateways' => function ($query) { + 'company.company_gateways' => function ($query) use ($user) { $query->whereNotNull('updated_at'); + + if(!$user->isAdmin()) + $query->where('company_gateways.user_id', $user->id); + }, - 'company.credits'=> function ($query) use ($updated_at) { + 'company.credits'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents'); + + if(!$user->hasPermission('view_credit')) + $query->where('credits.user_id', $user->id)->orWhere('credits.assigned_user_id', $user->id); + }, - 'company.designs'=> function ($query) use ($updated_at) { + 'company.designs'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('company'); + + if(!$user->isAdmin()) + $query->where('designs.user_id', $user->id); }, - 'company.documents'=> function ($query) use ($updated_at) { + 'company.documents'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at); }, - 'company.expenses'=> function ($query) use ($updated_at) { + 'company.expenses'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('documents'); + + if(!$user->hasPermission('view_expense')) + $query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id); }, - 'company.groups' => function ($query) use ($updated_at) { + 'company.groups' => function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at); + + if(!$user->isAdmin()) + $query->where('group_settings.user_id', $user->id); }, - 'company.invoices'=> function ($query) use ($updated_at) { + 'company.invoices'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents'); + + if(!$user->hasPermission('view_invoice')) + $query->where('invoices.user_id', $user->id)->orWhere('invoices.assigned_user_id', $user->id); + }, - 'company.payments'=> function ($query) use ($updated_at) { + 'company.payments'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('paymentables', 'documents'); + + if(!$user->hasPermission('view_payment')) + $query->where('payments.user_id', $user->id)->orWhere('payments.assigned_user_id', $user->id); + }, - 'company.payment_terms'=> function ($query) use ($updated_at) { + 'company.payment_terms'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at); + + if(!$user->isAdmin()) + $query->where('payment_terms.user_id', $user->id); + }, - 'company.products' => function ($query) use ($updated_at) { + 'company.products' => function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('documents'); + + if(!$user->hasPermission('view_product')) + $query->where('products.user_id', $user->id)->orWhere('products.assigned_user_id', $user->id); + }, - 'company.projects'=> function ($query) use ($updated_at) { + 'company.projects'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('documents'); + + if(!$user->hasPermission('view_project')) + $query->where('projects.user_id', $user->id)->orWhere('projects.assigned_user_id', $user->id); + }, - 'company.quotes'=> function ($query) use ($updated_at) { + 'company.quotes'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents'); + + if(!$user->hasPermission('view_quote')) + $query->where('quotes.user_id', $user->id)->orWhere('quotes.assigned_user_id', $user->id); + }, - 'company.recurring_invoices'=> function ($query) use ($updated_at) { + 'company.recurring_invoices'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents'); + + if(!$user->hasPermission('view_recurring_invoice')) + $query->where('recurring_invoices.user_id', $user->id)->orWhere('recurring_invoices.assigned_user_id', $user->id); + }, - 'company.tasks'=> function ($query) use ($updated_at) { + 'company.tasks'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('documents'); + + if(!$user->hasPermission('view_task')) + $query->where('tasks.user_id', $user->id)->orWhere('tasks.assigned_user_id', $user->id); + }, - 'company.tax_rates' => function ($query) use ($updated_at) { + 'company.tax_rates' => function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at); + + if(!$user->isAdmin()) + $query->where('tax_rates.user_id', $user->id); + }, - 'company.vendors'=> function ($query) use ($updated_at) { + 'company.vendors'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at)->with('contacts', 'documents'); + + if(!$user->hasPermission('view_vendor')) + $query->where('vendors.user_id', $user->id)->orWhere('vendors.assigned_user_id', $user->id); + }, - 'company.expense_categories'=> function ($query) use ($updated_at) { + 'company.expense_categories'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at); + + if(!$user->isAdmin()) + $query->where('expense_categories.user_id', $user->id); + }, - 'company.task_statuses'=> function ($query) use ($updated_at) { + 'company.task_statuses'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at); + + if(!$user->isAdmin()) + $query->where('task_statuses.user_id', $user->id); + }, + 'company.activities'=> function ($query) use($user) { + + if(!$user->isAdmin()) + $query->where('activities.user_id', $user->id); + + } ] ); diff --git a/app/Models/User.php b/app/Models/User.php index e77c9a611fa3..9e0133057188 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -202,15 +202,22 @@ class User extends Authenticatable implements MustVerifyEmail $this->id = auth()->user()->id; } - if (request()->header('X-API-TOKEN')) { - return $this->hasOneThrough(CompanyUser::class, CompanyToken::class, 'user_id', 'company_id', 'id', 'company_id') - ->where('company_tokens.token', request()->header('X-API-TOKEN')) - ->withTrashed(); - } else { - return $this->hasOneThrough(CompanyUser::class, CompanyToken::class, 'user_id', 'company_id', 'id', 'company_id') - ->where('company_user.user_id', $this->id) - ->withTrashed(); - } + return $this->hasOneThrough(CompanyUser::class, CompanyToken::class, 'user_id', 'user_id', 'id', 'user_id') + ->withTrashed(); + + // if (request()->header('X-API-TOKEN')) { + + // nlog("with an API token"); + // nlog(request()->header('X-API-TOKEN')); + + // return $this->hasOneThrough(CompanyUser::class, CompanyToken::class, 'user_id', 'company_id', 'id', 'company_id') + // ->where('company_tokens.token', request()->header('X-API-TOKEN')) + // ->withTrashed(); + // } else { + // return $this->hasOneThrough(CompanyUser::class, CompanyToken::class, 'user_id', 'company_id', 'id', 'company_id') + // ->where('company_user.user_id', $this->id) + // ->withTrashed(); + // } } /** diff --git a/app/Utils/Traits/GeneratesCounter.php b/app/Utils/Traits/GeneratesCounter.php index c5b907bc843f..0364ee0fbd3c 100644 --- a/app/Utils/Traits/GeneratesCounter.php +++ b/app/Utils/Traits/GeneratesCounter.php @@ -33,74 +33,12 @@ trait GeneratesCounter //todo in the form validation, we need to ensure that if a prefix and pattern is set we throw a validation error, //only one type is allow else this will cause confusion to the end user - /** - * Gets the next invoice number. - * - * @param Client $client The client - * - * @param Invoice|null $invoice - * @return string The next invoice number. - */ - public function getNextInvoiceNumber(Client $client, ?Invoice $invoice) :string - { - //Reset counters if enabled - $this->resetCounters($client); - //todo handle if we have specific client patterns in the future - $pattern = $client->getSetting('invoice_number_pattern'); - //Determine if we are using client_counters - if (strpos($pattern, 'clientCounter') || strpos($pattern, 'client_counter')) { - if (property_exists($client->settings, 'invoice_number_counter')) { - $counter = $client->settings->invoice_number_counter; - } else { - $counter = 1; - } - - $counter_entity = $client; - } elseif (strpos($pattern, 'groupCounter') || strpos($pattern, 'group_counter')) { - $counter = $client->group_settings->invoice_number_counter; - $counter_entity = $client->group_settings; - } else { - $counter = $client->company->settings->invoice_number_counter; - $counter_entity = $client->company; - } - - //Return a valid counter - $pattern = $client->getSetting('invoice_number_pattern'); - $padding = $client->getSetting('counter_padding'); - $prefix = ''; - - if ($invoice && $invoice->recurring_id) { - $prefix = $client->getSetting('recurring_number_prefix'); - } - - $invoice_number = $this->checkEntityNumber(Invoice::class, $client, $counter, $padding, $pattern, $prefix); - - $this->incrementCounter($counter_entity, 'invoice_number_counter'); - - return $invoice_number; - } - - /** - * Gets the next credit number. - * - * @param Client $client The client - * - * @return string The next credit number. - */ - public function getNextCreditNumber(Client $client) :string - { - return $this->getNextEntityNumber(Credit::class, $client); - } - - public function getNextQuoteNumber(Client $client) - { - return $this->getNextEntityNumber(Quote::class, $client); - } private function getNextEntityNumber($entity, Client $client) { - //Reset counters if enabled + $prefix = ''; + $this->resetCounters($client); $is_client_counter = false; @@ -108,9 +46,6 @@ trait GeneratesCounter $counter_string = $this->getEntityCounter($entity, $client); $pattern = $this->getNumberPattern($entity, $client); -nlog("counter string = {$counter_string}"); -nlog("pattern = {$pattern}"); - if (strpos($pattern, 'clientCounter') || strpos($pattern, 'client_counter')) { if (property_exists($client->settings, $counter_string)) { @@ -135,14 +70,15 @@ nlog("pattern = {$pattern}"); $counter_entity = $client->company; } -nlog($counter_entity->toArray()); - //If it is a quote - we need to $pattern = $this->getNumberPattern($entity, $client); $padding = $client->getSetting('counter_padding'); - $entity_number = $this->checkEntityNumber($entity, $client, $counter, $padding, $pattern); + if($entity instanceof Invoice && $entity && $entity->recurring_id) + $prefix = $client->getSetting('recurring_number_prefix'); + + $entity_number = $this->checkEntityNumber($entity, $client, $counter, $padding, $pattern, $prefix); $this->incrementCounter($counter_entity, $counter_string); @@ -210,97 +146,58 @@ nlog($counter_entity->toArray()); } } - public function getNextRecurringInvoiceNumber(Client $client) + /** + * Gets the next invoice number. + * + * @param Client $client The client + * + * @param Invoice|null $invoice + * @return string The next invoice number. + */ + public function getNextInvoiceNumber(Client $client, ?Invoice $invoice) :string { - - //Reset counters if enabled - $this->resetCounters($client); - - $is_client_counter = false; - - //todo handle if we have specific client patterns in the future - $pattern = $client->company->settings->recurring_invoice_number_pattern; - - if (strpos($pattern, 'clientCounter') || strpos($pattern, 'client_counter')) { - - if (property_exists($client->settings, 'recurring_invoice_number_counter')) { - $counter = $client->settings->recurring_invoice_number_counter; - } else { - $counter = 1; - } - - $counter_entity = $client; - - } elseif (strpos($pattern, 'groupCounter') || strpos($pattern, 'group_counter')) { - - if (property_exists($client->group_settings, 'recurring_invoice_number_counter')) { - $counter = $client->group_settings->recurring_invoice_number_counter; - } else { - $counter = 1; - } - - $counter_entity = $client->group_settings; - } else { - $counter = $client->company->settings->recurring_invoice_number_counter; - $counter_entity = $client->company; - } - - $padding = $client->getSetting('counter_padding'); - $invoice_number = $this->checkEntityNumber(RecurringInvoice::class, $client, $counter, $padding, $pattern); - - //increment the correct invoice_number Counter (company vs client) - if ($is_client_counter) { - $this->incrementCounter($client, 'recurring_invoice_number_counter'); - } else { - $this->incrementCounter($client->company, 'recurring_invoice_number_counter'); - } - - return $invoice_number; + return $this->getNextEntityNumber(Invoice::class, $client); } /** - * Payment Number Generator. - * @param Client $client - * @return string The payment number + * Gets the next credit number. + * + * @param Client $client The client + * + * @return string The next credit number. + */ + public function getNextCreditNumber(Client $client) :string + { + return $this->getNextEntityNumber(Credit::class, $client); + } + + /** + * Gets the next quote number. + * + * @param Client $client The client + * + * @return string The next credit number. + */ + public function getNextQuoteNumber(Client $client) + { + return $this->getNextEntityNumber(Quote::class, $client); + } + + public function getNextRecurringInvoiceNumber(Client $client) + { + return $this->getNextEntityNumber(RecurringInvoice::class, $client); + } + + /** + * Gets the next Payment number. + * + * @param Client $client The client + * + * @return string The next payment number. */ public function getNextPaymentNumber(Client $client) :string { - - //Reset counters if enabled - $this->resetCounters($client); - - $is_client_counter = false; - - //todo handle if we have specific client patterns in the future - $pattern = $client->company->settings->payment_number_pattern; - - //Determine if we are using client_counters - if (strpos($pattern, 'client_counter') === false) { - $counter = $client->company->settings->payment_number_counter; - } else { - - if (property_exists($client->settings, 'payment_number_counter')) { - $counter = $client->settings->payment_number_counter; - } else { - $counter = 1; - } - - $is_client_counter = true; - } - - //Return a valid counter - $pattern = ''; - $padding = $client->getSetting('counter_padding'); - $payment_number = $this->checkEntityNumber(Payment::class, $client, $counter, $padding, $pattern); - - //increment the correct invoice_number Counter (company vs client) - if ($is_client_counter) { - $this->incrementCounter($client, 'payment_number_counter'); - } else { - $this->incrementCounter($client->company, 'payment_number_counter'); - } - - return (string) $payment_number; + return $this->getNextEntityNumber(Payment::class, $client); } /** From 6d278a9c0543cd3638acfc5f9a9a06259b581747 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 29 Jan 2021 23:29:42 +1100 Subject: [PATCH 6/7] Add flag when permissions change --- app/Http/Controllers/UserController.php | 11 +++++++ app/Models/CompanyUser.php | 1 + app/Transformers/CompanyUserTransformer.php | 2 +- ...21502_add_permission_changed_timestamp.php | 30 +++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 database/migrations/2021_01_29_121502_add_permission_changed_timestamp.php diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 37f956b50abb..bc84f38f12e3 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -370,14 +370,25 @@ class UserController extends BaseController public function update(UpdateUserRequest $request, User $user) { $old_email = $user->email; + $old_company_user = $user->company_user; + $old_user = $user; + $new_email = $request->input('email'); $user = $this->user_repo->save($request->all(), $user); + $user = $user->fresh(); if ($old_email != $new_email) { UserEmailChanged::dispatch($new_email, $old_email, auth()->user()->company()); } + if( + strcasecmp($old_company_user->permissions, $user->company_user->permissions) != 0 || + $old_company_user->is_admin != $user->company_user->is_admin + ){ + $user->company_user()->update(["permissions_updated_at" => now()]); + } + event(new UserWasUpdated($user, auth()->user(), auth()->user()->company, Ninja::eventVars())); return $this->itemResponse($user); diff --git a/app/Models/CompanyUser.php b/app/Models/CompanyUser.php index e7fa44c44b9f..20089288b5d4 100644 --- a/app/Models/CompanyUser.php +++ b/app/Models/CompanyUser.php @@ -28,6 +28,7 @@ class CompanyUser extends Pivot * @var array */ protected $casts = [ + 'permissions_updated_at' => 'timestamp', 'updated_at' => 'timestamp', 'created_at' => 'timestamp', 'deleted_at' => 'timestamp', diff --git a/app/Transformers/CompanyUserTransformer.php b/app/Transformers/CompanyUserTransformer.php index a3b6f6785374..2ead828ebeb4 100644 --- a/app/Transformers/CompanyUserTransformer.php +++ b/app/Transformers/CompanyUserTransformer.php @@ -48,7 +48,7 @@ class CompanyUserTransformer extends EntityTransformer 'updated_at' => (int) $company_user->updated_at, 'archived_at' => (int) $company_user->deleted_at, 'created_at' => (int) $company_user->created_at, - + 'permissions_updated_at' => (int) $company_user->permissions_updated_at, ]; } diff --git a/database/migrations/2021_01_29_121502_add_permission_changed_timestamp.php b/database/migrations/2021_01_29_121502_add_permission_changed_timestamp.php new file mode 100644 index 000000000000..30ff2096d393 --- /dev/null +++ b/database/migrations/2021_01_29_121502_add_permission_changed_timestamp.php @@ -0,0 +1,30 @@ +timestamp('permissions_updated_at')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} From 958519d032af0760de42bb06372f6d547d50ff6d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 30 Jan 2021 00:02:04 +1100 Subject: [PATCH 7/7] Version bump --- VERSION.txt | 2 +- config/ninja.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 65c5e6f31326..aec0ea1d292f 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.0.55 \ No newline at end of file +5.0.56 \ No newline at end of file diff --git a/config/ninja.php b/config/ninja.php index 283c361c0a58..53b659058f8b 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -13,7 +13,7 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', ''), - 'app_version' => '5.0.55', + 'app_version' => '5.0.56', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false),