mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 14:17:34 -04:00 
			
		
		
		
	Merge pull request #8173 from turbo124/v5-develop
Add company logo size to company settings object
This commit is contained in:
		
						commit
						2aea9eade3
					
				
							
								
								
									
										68
									
								
								.github/workflows/phpunit.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										68
									
								
								.github/workflows/phpunit.yml
									
									
									
									
										vendored
									
									
								
							| @ -13,8 +13,12 @@ jobs: | |||||||
|     strategy: |     strategy: | ||||||
|       matrix: |       matrix: | ||||||
|         operating-system: ['ubuntu-20.04', 'ubuntu-22.04'] |         operating-system: ['ubuntu-20.04', 'ubuntu-22.04'] | ||||||
|         php-versions: ['8.1'] |         php-versions: ['8.1','8.2'] | ||||||
|         phpunit-versions: ['latest'] |         phpunit-versions: ['latest'] | ||||||
|  |         ci_node_total: [ 8 ] | ||||||
|  |         ci_node_index: [ 0, 1, 2, 3, 4, 5, 6, 7] | ||||||
|  |         laravel: [9.*] | ||||||
|  |         dependency-version: [prefer-stable] | ||||||
| 
 | 
 | ||||||
|     env: |     env: | ||||||
|       DB_DATABASE1: ninja |       DB_DATABASE1: ninja | ||||||
| @ -25,13 +29,14 @@ jobs: | |||||||
|       DB_USERNAME: root |       DB_USERNAME: root | ||||||
|       DB_PASSWORD: ninja |       DB_PASSWORD: ninja | ||||||
|       DB_HOST: '127.0.0.1' |       DB_HOST: '127.0.0.1' | ||||||
|  |       REDIS_PORT: 6379 | ||||||
|       BROADCAST_DRIVER: log |       BROADCAST_DRIVER: log | ||||||
|       CACHE_DRIVER: file |       CACHE_DRIVER: redis | ||||||
|       QUEUE_CONNECTION: sync |       QUEUE_CONNECTION: redis | ||||||
|       SESSION_DRIVER: file |       SESSION_DRIVER: redis | ||||||
|       NINJA_ENVIRONMENT: hosted |       NINJA_ENVIRONMENT: hosted | ||||||
|       MULTI_DB_ENABLED: false |       MULTI_DB_ENABLED: false | ||||||
|       NINJA_LICENSE: 123456 |       NINJA_LICENSE: ${{ secrets.ninja_license }} | ||||||
|       TRAVIS: true |       TRAVIS: true | ||||||
|       MAIL_MAILER: log |       MAIL_MAILER: log | ||||||
| 
 | 
 | ||||||
| @ -47,13 +52,18 @@ jobs: | |||||||
|           MYSQL_DATABASE: ninja |           MYSQL_DATABASE: ninja | ||||||
|           MYSQL_ROOT_PASSWORD: ninja |           MYSQL_ROOT_PASSWORD: ninja | ||||||
|         options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 |         options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 | ||||||
|  |       redis: | ||||||
|  |         image: redis | ||||||
|  |         ports: | ||||||
|  |           - 6379/tcp | ||||||
|  |         options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 | ||||||
| 
 | 
 | ||||||
|     steps: |     steps: | ||||||
|     - name: Add hosts to /etc/hosts |     - name: Add hosts to /etc/hosts | ||||||
|       run: | |       run: | | ||||||
|         sudo echo "127.0.0.1 ninja.test" | sudo tee -a /etc/hosts |         sudo echo "127.0.0.1 ninja.test" | sudo tee -a /etc/hosts | ||||||
| 
 | 
 | ||||||
|     - name: Start mysql service |     - name: Start MariaDB service | ||||||
|       run: | |       run: | | ||||||
|         sudo systemctl start mysql.service |         sudo systemctl start mysql.service | ||||||
|     - name: Verify MariaDB connection |     - name: Verify MariaDB connection | ||||||
| @ -65,11 +75,11 @@ jobs: | |||||||
|         while ! mysqladmin ping -h"127.0.0.1" -P"$DB_PORT" --silent; do |         while ! mysqladmin ping -h"127.0.0.1" -P"$DB_PORT" --silent; do | ||||||
|           sleep 1 |           sleep 1 | ||||||
|         done |         done | ||||||
|     - name: Setup PHP |     - name: Setup PHP shivammathur/setup-php@v2 | ||||||
|       uses: shivammathur/setup-php@v2 |       uses: shivammathur/setup-php@v2 | ||||||
|       with: |       with: | ||||||
|         php-version: ${{ matrix.php-versions }} |         php-version: ${{ matrix.php-versions }} | ||||||
|         extensions: mysql, mysqlnd, sqlite3, bcmath, gmp, gd, curl, zip, openssl, mbstring, xml |         extensions: mysql, mysqlnd, sqlite3, bcmath, gmp, gd, curl, zip, openssl, mbstring, xml, redis | ||||||
| 
 | 
 | ||||||
|     - uses: actions/checkout@v1 |     - uses: actions/checkout@v1 | ||||||
|       with: |       with: | ||||||
| @ -79,32 +89,56 @@ jobs: | |||||||
|     - name: Copy .env |     - name: Copy .env | ||||||
|       run: | |       run: | | ||||||
|         cp .env.ci .env |         cp .env.ci .env | ||||||
|  | 
 | ||||||
|  |     # - name: Get Composer Cache Directory | ||||||
|  |     #   id: composer-cache | ||||||
|  |     #   run: | | ||||||
|  |     #     echo "::set-output name=dir::$(composer config cache-files-dir)" | ||||||
|  |     # - uses: actions/cache@v2 | ||||||
|  |     #   with: | ||||||
|  |     #     path: ${{ steps.composer-cache.outputs.dir }} | ||||||
|  |     #     key: ${{ runner.os }}-${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} | ||||||
|  |     #     restore-keys: | | ||||||
|  |     #       ${{ runner.os }}-${{ matrix.php }}-composer- | ||||||
|  | 
 | ||||||
|  |     - name: Cache dependencies actions/cache@v3 | ||||||
|  |       uses: actions/cache@v3 | ||||||
|  |       with: | ||||||
|  |         path: ~/.composer/cache/files | ||||||
|  |         key: dependencies-${{ matrix.dependency-version }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php-versions }}-composer-${{ hashFiles('composer.json') }} | ||||||
|  | 
 | ||||||
|     - name: Install composer dependencies |     - name: Install composer dependencies | ||||||
|       run: | |       run: | | ||||||
|         composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }} |         composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }} | ||||||
|         composer install |         composer install | ||||||
|  | 
 | ||||||
|     - name: Prepare Laravel Application |     - name: Prepare Laravel Application | ||||||
|  |       env: | ||||||
|  |         REDIS_PORT: ${{ job.services.redis.ports['6379'] }} | ||||||
|       run: | |       run: | | ||||||
|         php artisan key:generate |         php artisan key:generate | ||||||
|         php artisan optimize |         php artisan optimize | ||||||
|         php artisan cache:clear |         php artisan cache:clear | ||||||
|         php artisan config:cache |         php artisan config:cache | ||||||
|     - name: Create DB and schemas |         php artisan ninja:post-update | ||||||
|       run: | | 
 | ||||||
|         mkdir -p database |  | ||||||
|         touch database/database.sqlite |  | ||||||
|     - name: Migrate Database |     - name: Migrate Database | ||||||
|       run: | |       run: | | ||||||
|         php artisan migrate:fresh --seed --force && php artisan db:seed --force |         php artisan migrate:fresh --seed --force && php artisan db:seed --force | ||||||
|     - name: Prepare JS/CSS assets | 
 | ||||||
|       run: | |     # - name: Prepare JS/CSS assets | ||||||
|         npm i |     #   run: | | ||||||
|         npm run production |     #     npm i | ||||||
|  |     #     npm run production | ||||||
|  |          | ||||||
|     - name: Run Testsuite |     - name: Run Testsuite | ||||||
|       run: | |       run: | | ||||||
|         cat .env |         cat .env | ||||||
|         vendor/bin/snappdf download |         vendor/bin/snappdf download | ||||||
|         vendor/bin/phpunit --testdox |         tests/ci | ||||||
|       env: |       env: | ||||||
|         DB_PORT: ${{ job.services.mysql.ports[3306] }} |         DB_PORT: ${{ job.services.mysql.ports[3306] }} | ||||||
|         PHP_CS_FIXER_IGNORE_ENV: true |         PHP_CS_FIXER_IGNORE_ENV: true | ||||||
|  |         CI_NODE_TOTAL: ${{ matrix.ci_node_total }} | ||||||
|  |         # Use the index from matrix as an environment variable | ||||||
|  |         CI_NODE_INDEX: ${{ matrix.ci_node_index }} | ||||||
| @ -1 +1 @@ | |||||||
| 5.5.56 | 5.5.57 | ||||||
| @ -80,10 +80,7 @@ class CreateSingleAccount extends Command | |||||||
|     public function handle() |     public function handle() | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|         if(config('ninja.is_docker')) |         if (Ninja::isHosted() || config('ninja.is_docker') || !$this->confirm('Are you sure you want to inject dummy data?')) | ||||||
|             return; |  | ||||||
|          |  | ||||||
|         if (!$this->confirm('Are you sure you want to inject dummy data?')) |  | ||||||
|             return; |             return; | ||||||
| 
 | 
 | ||||||
|         $this->invoice_repo = new InvoiceRepository(); |         $this->invoice_repo = new InvoiceRepository(); | ||||||
| @ -105,6 +102,11 @@ class CreateSingleAccount extends Command | |||||||
|     { |     { | ||||||
|         $this->info('Creating Small Account and Company'); |         $this->info('Creating Small Account and Company'); | ||||||
| 
 | 
 | ||||||
|  |         if($user = User::where('email','small@example.com')->first()) | ||||||
|  |         { | ||||||
|  |             $user->account->delete(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         $account = Account::factory()->create(); |         $account = Account::factory()->create(); | ||||||
|         $company = Company::factory()->create([ |         $company = Company::factory()->create([ | ||||||
|             'account_id' => $account->id, |             'account_id' => $account->id, | ||||||
|  | |||||||
| @ -13,11 +13,14 @@ namespace App\Console\Commands; | |||||||
| 
 | 
 | ||||||
| use App\Jobs\Util\VersionCheck; | use App\Jobs\Util\VersionCheck; | ||||||
| use App\Utils\Ninja; | use App\Utils\Ninja; | ||||||
|  | use App\Utils\Traits\AppSetup; | ||||||
| use Illuminate\Console\Command; | use Illuminate\Console\Command; | ||||||
| use Illuminate\Support\Facades\Artisan; | use Illuminate\Support\Facades\Artisan; | ||||||
| 
 | 
 | ||||||
| class PostUpdate extends Command | class PostUpdate extends Command | ||||||
| { | { | ||||||
|  |     use AppSetup; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * The name and signature of the console command. |      * The name and signature of the console command. | ||||||
|      * |      * | ||||||
| @ -83,6 +86,8 @@ class PostUpdate extends Command | |||||||
| 
 | 
 | ||||||
|         info('queue restarted'); |         info('queue restarted'); | ||||||
| 
 | 
 | ||||||
|  |         $this->buildCache(true); | ||||||
|  | 
 | ||||||
|         VersionCheck::dispatch(); |         VersionCheck::dispatch(); | ||||||
| 
 | 
 | ||||||
|         info('Sent for version check'); |         info('Sent for version check'); | ||||||
|  | |||||||
| @ -94,8 +94,6 @@ class Kernel extends ConsoleKernel | |||||||
|         /* Performs system maintenance such as pruning the backup table */ |         /* Performs system maintenance such as pruning the backup table */ | ||||||
|         $schedule->job(new SystemMaintenance)->sundays()->at('02:30')->withoutOverlapping()->name('system-maintenance-job')->onOneServer(); |         $schedule->job(new SystemMaintenance)->sundays()->at('02:30')->withoutOverlapping()->name('system-maintenance-job')->onOneServer(); | ||||||
| 
 | 
 | ||||||
|         /* Pulls in bank transactions from third party services */ |  | ||||||
|         $schedule->job(new BankTransactionSync)->dailyAt('04:10')->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer(); |  | ||||||
| 
 | 
 | ||||||
|         if (Ninja::isSelfHost()) { |         if (Ninja::isSelfHost()) { | ||||||
| 
 | 
 | ||||||
| @ -110,6 +108,9 @@ class Kernel extends ConsoleKernel | |||||||
| 
 | 
 | ||||||
|             $schedule->job(new AdjustEmailQuota)->dailyAt('23:30')->withoutOverlapping(); |             $schedule->job(new AdjustEmailQuota)->dailyAt('23:30')->withoutOverlapping(); | ||||||
| 
 | 
 | ||||||
|  |             /* Pulls in bank transactions from third party services */ | ||||||
|  |             $schedule->job(new BankTransactionSync)->dailyAt('04:10')->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer(); | ||||||
|  | 
 | ||||||
|             //not used @deprecate
 |             //not used @deprecate
 | ||||||
|             // $schedule->job(new SendFailedEmails)->daily()->withoutOverlapping();
 |             // $schedule->job(new SendFailedEmails)->daily()->withoutOverlapping();
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -453,8 +453,10 @@ class CompanySettings extends BaseSettings | |||||||
| 
 | 
 | ||||||
|     public $show_email_footer = true; |     public $show_email_footer = true; | ||||||
| 
 | 
 | ||||||
|  |     public $company_logo_size = '65%'; | ||||||
| 
 | 
 | ||||||
|     public static $casts = [ |     public static $casts = [ | ||||||
|  |         'company_logo_size'                  => 'string', | ||||||
|         'show_email_footer'                  => 'bool', |         'show_email_footer'                  => 'bool', | ||||||
|         'email_alignment'                    => 'string', |         'email_alignment'                    => 'string', | ||||||
|         'auto_bill_standard_invoices'        => 'bool', |         'auto_bill_standard_invoices'        => 'bool', | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ | |||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| namespace App\DataMapper; | namespace App\DataMapper\Schedule; | ||||||
| 
 | 
 | ||||||
| use App\Models\Client; | use App\Models\Client; | ||||||
| use stdClass; | use stdClass; | ||||||
|  | |||||||
| @ -11,11 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\BankIntegration; |  | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * BankIntegrationFilters. |  * BankIntegrationFilters. | ||||||
|  | |||||||
| @ -12,10 +12,7 @@ | |||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\BankTransaction; | use App\Models\BankTransaction; | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * BankTransactionFilters. |  * BankTransactionFilters. | ||||||
| @ -77,87 +74,49 @@ class BankTransactionFilters extends QueryFilters | |||||||
| 
 | 
 | ||||||
|         $status_parameters = explode(',', $value); |         $status_parameters = explode(',', $value); | ||||||
| 
 | 
 | ||||||
|         $status_array = []; |  | ||||||
|          |  | ||||||
|         $debit_or_withdrawal_array = []; |  | ||||||
| 
 |  | ||||||
|         if (in_array('all', $status_parameters)) { |         if (in_array('all', $status_parameters)) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('unmatched', $status_parameters)) { |         $this->builder->where(function ($query) use ($status_parameters){ | ||||||
|             $status_array[] = BankTransaction::STATUS_UNMATCHED; |  | ||||||
|             // $this->builder->orWhere('status_id', BankTransaction::STATUS_UNMATCHED);
 |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (in_array('matched', $status_parameters)) { |             $status_array = []; | ||||||
|             $status_array[] = BankTransaction::STATUS_MATCHED; |              | ||||||
|             // $this->builder->where('status_id', BankTransaction::STATUS_MATCHED);
 |             $debit_or_withdrawal_array = []; | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (in_array('converted', $status_parameters)) { |             if (in_array('unmatched', $status_parameters)) { | ||||||
|             $status_array[] = BankTransaction::STATUS_CONVERTED; |                 $status_array[] = BankTransaction::STATUS_UNMATCHED; | ||||||
|             // $this->builder->where('status_id', BankTransaction::STATUS_CONVERTED);
 |             } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (in_array('deposits', $status_parameters)) { |             if (in_array('matched', $status_parameters)) { | ||||||
|             $debit_or_withdrawal_array[] = 'CREDIT'; |                 $status_array[] = BankTransaction::STATUS_MATCHED; | ||||||
|             // $this->builder->where('base_type', 'CREDIT');
 |             } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (in_array('withdrawals', $status_parameters)) { |             if (in_array('converted', $status_parameters)) { | ||||||
|             $debit_or_withdrawal_array[] = 'DEBIT'; |                 $status_array[] = BankTransaction::STATUS_CONVERTED; | ||||||
|             // $this->builder->where('base_type', 'DEBIT');
 |             } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if(count($status_array) >=1) { |             if (in_array('deposits', $status_parameters)) { | ||||||
|             $this->builder->whereIn('status_id', $status_array); |                 $debit_or_withdrawal_array[] = 'CREDIT'; | ||||||
|         } |             } | ||||||
| 
 | 
 | ||||||
|         if(count($debit_or_withdrawal_array) >=1) { |             if (in_array('withdrawals', $status_parameters)) { | ||||||
|             $this->builder->orWhereIn('base_type', $debit_or_withdrawal_array); |                 $debit_or_withdrawal_array[] = 'DEBIT'; | ||||||
|         } |             } | ||||||
|  | 
 | ||||||
|  |             if(count($status_array) >=1) { | ||||||
|  |                 $query->whereIn('status_id', $status_array); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(count($debit_or_withdrawal_array) >=1) { | ||||||
|  |                 $query->orWhereIn('base_type', $debit_or_withdrawal_array); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         }); | ||||||
| 
 | 
 | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Filters the list based on the status |  | ||||||
|      * archived, active, deleted. |  | ||||||
|      * |  | ||||||
|      * @param string filter |  | ||||||
|      * @return Builder |  | ||||||
|      */ |  | ||||||
|     public function status(string $filter = '') : Builder |  | ||||||
|     { |  | ||||||
|         if (strlen($filter) == 0) { |  | ||||||
|             return $this->builder; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $filters = explode(',', $filter); |  | ||||||
| 
 |  | ||||||
|         return $this->builder->where(function ($query) use ($filters) { |  | ||||||
| 
 |  | ||||||
|             if (in_array(parent::STATUS_ACTIVE, $filters)) { |  | ||||||
|                 $query->orWhereNull('deleted_at'); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (in_array(parent::STATUS_ARCHIVED, $filters)) { |  | ||||||
|                 $query->orWhere(function ($query) use ($table) { |  | ||||||
|                     $query->whereNotNull($table.'.deleted_at'); |  | ||||||
| 
 |  | ||||||
|                     if (! in_array($table, ['users'])) { |  | ||||||
|                         $query->where($table.'.is_deleted', '=', 0); |  | ||||||
|                     } |  | ||||||
|                 }); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (in_array(parent::STATUS_DELETED, $filters)) { |  | ||||||
|                 $query->orWhere($table.'.is_deleted', '=', 1); |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Sorts the list based on $sort. |      * Sorts the list based on $sort. | ||||||
|      * |      * | ||||||
| @ -186,19 +145,6 @@ class BankTransactionFilters extends QueryFilters | |||||||
|         return $this->builder->orderBy($sort_col[0], $sort_col[1]); |         return $this->builder->orderBy($sort_col[0], $sort_col[1]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Returns the base query. |  | ||||||
|      * |  | ||||||
|      * @param int company_id |  | ||||||
|      * @param User $user |  | ||||||
|      * @return Builder |  | ||||||
|      * @deprecated |  | ||||||
|      */ |  | ||||||
|     public function baseQuery(int $company_id, User $user) : Builder |  | ||||||
|     { |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
| @ -206,7 +152,6 @@ class BankTransactionFilters extends QueryFilters | |||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter() | ||||||
|     { |     { | ||||||
|         //return $this->builder->whereCompanyId(auth()->user()->company()->id);
 |  | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -108,17 +108,17 @@ class ClientFilters extends QueryFilters | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return  $this->builder->where(function ($query) use ($filter) { |         return  $this->builder->where(function ($query) use ($filter) { | ||||||
|             $query->where('clients.name', 'like', '%'.$filter.'%') |             $query->where('name', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('clients.id_number', 'like', '%'.$filter.'%') |                           ->orWhere('id_number', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhereHas('contacts', function ($query) use ($filter) { |                           ->orWhereHas('contacts', function ($query) use ($filter) { | ||||||
|                               $query->where('first_name', 'like', '%'.$filter.'%'); |                               $query->where('first_name', 'like', '%'.$filter.'%'); | ||||||
|                               $query->orWhere('last_name', 'like', '%'.$filter.'%'); |                               $query->orWhere('last_name', 'like', '%'.$filter.'%'); | ||||||
|                               $query->orWhere('email', 'like', '%'.$filter.'%'); |                               $query->orWhere('email', 'like', '%'.$filter.'%'); | ||||||
|                           }) |                           }) | ||||||
|                           ->orWhere('clients.custom_value1', 'like', '%'.$filter.'%') |                           ->orWhere('custom_value1', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('clients.custom_value2', 'like', '%'.$filter.'%') |                           ->orWhere('custom_value2', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('clients.custom_value3', 'like', '%'.$filter.'%') |                           ->orWhere('custom_value3', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('clients.custom_value4', 'like', '%'.$filter.'%'); |                           ->orWhere('custom_value4', 'like', '%'.$filter.'%'); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -147,4 +147,14 @@ class ClientFilters extends QueryFilters | |||||||
|     { |     { | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     public function filter_details(string $filter = '') | ||||||
|  |     { | ||||||
|  |          | ||||||
|  |         if($filter == 'true') | ||||||
|  |             return $this->builder->select('id', 'name', 'number', 'id_number'); | ||||||
|  | 
 | ||||||
|  |         return $this->builder; | ||||||
|  | 
 | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,9 +13,7 @@ | |||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\Credit; | use App\Models\Credit; | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Carbon; |  | ||||||
| 
 | 
 | ||||||
| class CreditFilters extends QueryFilters | class CreditFilters extends QueryFilters | ||||||
| { | { | ||||||
| @ -44,20 +42,20 @@ class CreditFilters extends QueryFilters | |||||||
|             return $this->builder; |             return $this->builder; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (in_array('draft', $status_parameters)) { |  | ||||||
|             $this->builder->where('status_id', Credit::STATUS_DRAFT); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (in_array('partial', $status_parameters)) { |         $credit_filters = []; | ||||||
|             $this->builder->where('status_id', Credit::STATUS_PARTIAL); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (in_array('applied', $status_parameters)) { |         if (in_array('draft', $status_parameters))  | ||||||
|             $this->builder->where('status_id', Credit::STATUS_APPLIED); |             $credit_filters[] = Credit::STATUS_DRAFT; | ||||||
|         } |          | ||||||
|  |         if (in_array('partial', $status_parameters))  | ||||||
|  |             $credit_filters[] = Credit::STATUS_PARTIAL; | ||||||
| 
 | 
 | ||||||
|         //->where('due_date', '>', Carbon::now())
 |         if (in_array('applied', $status_parameters))  | ||||||
|         //->orWhere('partial_due_date', '>', Carbon::now());
 |             $credit_filters[] = Credit::STATUS_APPLIED; | ||||||
|  | 
 | ||||||
|  |         if(count($credit_filters) >=1) | ||||||
|  |             $this->builder->whereIn('status_id', $credit_filters); | ||||||
| 
 | 
 | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,11 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\Design; |  | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * DesignFilters. |  * DesignFilters. | ||||||
| @ -27,9 +23,10 @@ class DesignFilters extends QueryFilters | |||||||
|      * |      * | ||||||
|      * @param string query filter |      * @param string query filter | ||||||
|      * @return Builder |      * @return Builder | ||||||
|  |      *  | ||||||
|      * @deprecated |      * @deprecated | ||||||
|      */ |      */ | ||||||
|     public function filter(string $filter = '') : Builder |     public function filter(string $filter = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($filter) == 0) { |         if (strlen($filter) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
| @ -44,48 +41,17 @@ class DesignFilters extends QueryFilters | |||||||
|      * Sorts the list based on $sort. |      * Sorts the list based on $sort. | ||||||
|      * |      * | ||||||
|      * @param string sort formatted as column|asc |      * @param string sort formatted as column|asc | ||||||
|  |      *  | ||||||
|      * @return Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function sort(string $sort) : Builder |     public function sort(string $sort): Builder | ||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
|         return $this->builder->orderBy($sort_col[0], $sort_col[1]); |         if(is_array($sort_col)) | ||||||
|     } |             return $this->builder->orderBy($sort_col[0], $sort_col[1]); | ||||||
| 
 | 
 | ||||||
|     /** |         return $this->builder; | ||||||
|      * Returns the base query. |  | ||||||
|      * |  | ||||||
|      * @param int company_id |  | ||||||
|      * @param User $user |  | ||||||
|      * @return Builder |  | ||||||
|      * @deprecated |  | ||||||
|      */ |  | ||||||
|     public function baseQuery(int $company_id, User $user) : Builder |  | ||||||
|     { |  | ||||||
|         $query = DB::table('designs') |  | ||||||
|             ->join('companies', 'companies.id', '=', 'designs.company_id') |  | ||||||
|             ->where('designs.company_id', '=', $company_id) |  | ||||||
|             ->select( |  | ||||||
|                 'designs.id', |  | ||||||
|                 'designs.name', |  | ||||||
|                 'designs.design', |  | ||||||
|                 'designs.created_at', |  | ||||||
|                 'designs.created_at as design_created_at', |  | ||||||
|                 'designs.deleted_at', |  | ||||||
|                 'designs.is_deleted', |  | ||||||
|                 'designs.user_id', |  | ||||||
|             ); |  | ||||||
| 
 |  | ||||||
|         /* |  | ||||||
|          * If the user does not have permissions to view all invoices |  | ||||||
|          * limit the user to only the invoices they have created |  | ||||||
|          */ |  | ||||||
|         if (Gate::denies('view-list', Design::class)) { |  | ||||||
|             $query->where('designs.user_id', '=', $user->id); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return $query; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -93,7 +59,7 @@ class DesignFilters extends QueryFilters | |||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Illuminate\Database\Query\Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
|         //return $this->builder->whereCompanyId(auth()->user()->company()->id);
 |         //return $this->builder->whereCompanyId(auth()->user()->company()->id);
 | ||||||
|         return $this->builder->where('company_id', auth()->user()->company()->id)->orWhere('company_id', null)->orderBy('id','asc'); |         return $this->builder->where('company_id', auth()->user()->company()->id)->orWhere('company_id', null)->orderBy('id','asc'); | ||||||
|  | |||||||
| @ -12,7 +12,6 @@ | |||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\Company; | use App\Models\Company; | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -27,7 +26,7 @@ class DocumentFilters extends QueryFilters | |||||||
|      * @return Builder |      * @return Builder | ||||||
|      * @deprecated |      * @deprecated | ||||||
|      */ |      */ | ||||||
|     public function filter(string $filter = '') : Builder |     public function filter(string $filter = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($filter) == 0) { |         if (strlen($filter) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
| @ -36,8 +35,15 @@ class DocumentFilters extends QueryFilters | |||||||
|         return $this->builder; |         return $this->builder; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* If client ID passed to this entity, simply return */ |     /** | ||||||
|     public function client_id(string $client_id = '') :Builder |      * Overriding method as client_id does | ||||||
|  |      * not exist on this model, just pass | ||||||
|  |      * back the builder | ||||||
|  |      * @param  string $client_id The client hashed id. | ||||||
|  |      *  | ||||||
|  |      * @return Builder            | ||||||
|  |      */ | ||||||
|  |     public function client_id(string $client_id = ''): Builder | ||||||
|     { |     { | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|     } |     } | ||||||
| @ -48,11 +54,14 @@ class DocumentFilters extends QueryFilters | |||||||
|      * @param string sort formatted as column|asc |      * @param string sort formatted as column|asc | ||||||
|      * @return Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function sort(string $sort) : Builder |     public function sort(string $sort = '') : Builder | ||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
|         return $this->builder->orderBy($sort_col[0], $sort_col[1]); |         if(is_array($sort_col)) | ||||||
|  |             return $this->builder->orderBy($sort_col[0], $sort_col[1]); | ||||||
|  | 
 | ||||||
|  |         return $this->builder; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,11 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\Expense; |  | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * ExpenseCategoryFilters. |  * ExpenseCategoryFilters. | ||||||
| @ -49,9 +45,9 @@ class ExpenseCategoryFilters extends QueryFilters | |||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
|         if (is_array($sort_col) && in_array($sort_col[1], ['asc', 'desc']) && in_array($sort_col[0], ['name'])) { |         if (is_array($sort_col) && in_array($sort_col[1], ['asc', 'desc']) && in_array($sort_col[0], ['name'])) | ||||||
|             return $this->builder->orderBy($sort_col[0], $sort_col[1]); |             return $this->builder->orderBy($sort_col[0], $sort_col[1]); | ||||||
|         } |          | ||||||
| 
 | 
 | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|     } |     } | ||||||
| @ -63,8 +59,6 @@ class ExpenseCategoryFilters extends QueryFilters | |||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter() | ||||||
|     { |     { | ||||||
| 
 |  | ||||||
|         //return $this->builder->whereCompanyId(auth()->user()->company()->id);
 |  | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,11 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\Expense; |  | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * ExpenseFilters. |  * ExpenseFilters. | ||||||
| @ -36,11 +32,11 @@ class ExpenseFilters extends QueryFilters | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return  $this->builder->where(function ($query) use ($filter) { |         return  $this->builder->where(function ($query) use ($filter) { | ||||||
|             $query->where('expenses.public_notes', 'like', '%'.$filter.'%') |             $query->where('public_notes', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('expenses.custom_value1', 'like', '%'.$filter.'%') |                           ->orWhere('custom_value1', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('expenses.custom_value2', 'like', '%'.$filter.'%') |                           ->orWhere('custom_value2', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('expenses.custom_value3', 'like', '%'.$filter.'%') |                           ->orWhere('custom_value3', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('expenses.custom_value4', 'like', '%'.$filter.'%'); |                           ->orWhere('custom_value4', 'like', '%'.$filter.'%'); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,7 +12,6 @@ | |||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\Invoice; | use App\Models\Invoice; | ||||||
| use App\Models\User; |  | ||||||
| use App\Utils\Traits\MakesHash; | use App\Utils\Traits\MakesHash; | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Carbon; | use Illuminate\Support\Carbon; | ||||||
| @ -80,6 +79,9 @@ class InvoiceFilters extends QueryFilters | |||||||
| 
 | 
 | ||||||
|     public function number(string $number = '') :Builder |     public function number(string $number = '') :Builder | ||||||
|     { |     { | ||||||
|  |         if(strlen($number) == 0) | ||||||
|  |             return $this->builder; | ||||||
|  |          | ||||||
|         return $this->builder->where('number', $number); |         return $this->builder->where('number', $number); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,7 +11,6 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -49,6 +48,7 @@ class PaymentFilters extends QueryFilters | |||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|         if($value == 'true'){ |         if($value == 'true'){ | ||||||
|  | 
 | ||||||
|             return $this->builder |             return $this->builder | ||||||
|                         ->where('is_deleted',0) |                         ->where('is_deleted',0) | ||||||
|                         ->where(function ($query){ |                         ->where(function ($query){ | ||||||
| @ -72,7 +72,10 @@ class PaymentFilters extends QueryFilters | |||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
|         return $this->builder->orderBy($sort_col[0], $sort_col[1]); |         if(is_array($sort_col)) | ||||||
|  |             return $this->builder->orderBy($sort_col[0], $sort_col[1]); | ||||||
|  | 
 | ||||||
|  |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function number(string $number) : Builder |     public function number(string $number) : Builder | ||||||
|  | |||||||
| @ -11,11 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\Design; |  | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * PaymentTermFilters. |  * PaymentTermFilters. | ||||||
| @ -29,7 +25,7 @@ class PaymentTermFilters extends QueryFilters | |||||||
|      * @return Builder |      * @return Builder | ||||||
|      * @deprecated |      * @deprecated | ||||||
|      */ |      */ | ||||||
|     public function filter(string $filter = '') : Builder |     public function filter(string $filter = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($filter) == 0) { |         if (strlen($filter) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
| @ -46,7 +42,7 @@ class PaymentTermFilters extends QueryFilters | |||||||
|      * @param string sort formatted as column|asc |      * @param string sort formatted as column|asc | ||||||
|      * @return Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function sort(string $sort) : Builder |     public function sort(string $sort): Builder | ||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
| @ -56,12 +52,10 @@ class PaymentTermFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|         //return $this->builder->whereCompanyId(auth()->user()->company()->id);
 |  | ||||||
|         // return $this->builder->whereCompanyId(auth()->user()->company()->id)->orWhere('company_id', null);
 |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,7 +11,6 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -11,11 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\Project; |  | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * ProjectFilters. |  * ProjectFilters. | ||||||
| @ -52,7 +48,8 @@ class ProjectFilters extends QueryFilters | |||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
|         return $this->builder->orderBy($sort_col[0], $sort_col[1]); |         if(is_array($sort_col)) | ||||||
|  |             return $this->builder->orderBy($sort_col[0], $sort_col[1]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -12,7 +12,6 @@ | |||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\PurchaseOrder; | use App\Models\PurchaseOrder; | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| class PurchaseOrderFilters extends QueryFilters | class PurchaseOrderFilters extends QueryFilters | ||||||
| @ -70,7 +69,7 @@ class PurchaseOrderFilters extends QueryFilters | |||||||
|             if(count($status_parameters) >=1) { |             if(count($status_parameters) >=1) { | ||||||
|                 $query->whereIn('status_id', $status_parameters); |                 $query->whereIn('status_id', $status_parameters); | ||||||
|             } |             } | ||||||
|         }) |         }); | ||||||
| 
 | 
 | ||||||
|         return $this->builder; |         return $this->builder; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -12,7 +12,6 @@ | |||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\Quote; | use App\Models\Quote; | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -11,11 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\RecurringExpense; |  | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * RecurringExpenseFilters. |  * RecurringExpenseFilters. | ||||||
| @ -29,19 +25,18 @@ class RecurringExpenseFilters extends QueryFilters | |||||||
|      * @return Builder |      * @return Builder | ||||||
|      * @deprecated |      * @deprecated | ||||||
|      */ |      */ | ||||||
|     public function filter(string $filter = '') : Builder |     public function filter(string $filter = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($filter) == 0) { |         if (strlen($filter) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return  $this->builder->where(function ($query) use ($filter) { |         return $this->builder->where(function ($query) use ($filter) { | ||||||
|             $query->where('recurring_expenses.name', 'like', '%'.$filter.'%') |             $query->where('public_notes', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('recurring_expenses.id_number', 'like', '%'.$filter.'%') |                           ->orWhere('custom_value1', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('recurring_expenses.custom_value1', 'like', '%'.$filter.'%') |                           ->orWhere('custom_value2', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('recurring_expenses.custom_value2', 'like', '%'.$filter.'%') |                           ->orWhere('custom_value3', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('recurring_expenses.custom_value3', 'like', '%'.$filter.'%') |                           ->orWhere('custom_value4', 'like', '%'.$filter.'%'); | ||||||
|                           ->orWhere('recurring_expenses.custom_value4', 'like', '%'.$filter.'%'); |  | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -51,7 +46,7 @@ class RecurringExpenseFilters extends QueryFilters | |||||||
|      * @param string sort formatted as column|asc |      * @param string sort formatted as column|asc | ||||||
|      * @return Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function sort(string $sort) : Builder |     public function sort(string $sort): Builder | ||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,7 +12,6 @@ | |||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\RecurringInvoice; | use App\Models\RecurringInvoice; | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -77,7 +76,10 @@ class RecurringInvoiceFilters extends QueryFilters | |||||||
|         if (in_array('completed', $status_parameters))  |         if (in_array('completed', $status_parameters))  | ||||||
|             $recurring_filters[] = RecurringInvoice::STATUS_COMPLETED; |             $recurring_filters[] = RecurringInvoice::STATUS_COMPLETED; | ||||||
| 
 | 
 | ||||||
|         return $this->builder->whereIn('status_id', $recurring_filters); |         if(count($recurring_filters) >= 1) | ||||||
|  |             return $this->builder->whereIn('status_id', $recurring_filters); | ||||||
|  | 
 | ||||||
|  |         return $this->builder; | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,7 +11,6 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -26,7 +25,7 @@ class RecurringQuoteFilters extends QueryFilters | |||||||
|      * @return Builder |      * @return Builder | ||||||
|      * @deprecated |      * @deprecated | ||||||
|      */ |      */ | ||||||
|     public function filter(string $filter = '') : Builder |     public function filter(string $filter = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($filter) == 0) { |         if (strlen($filter) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
| @ -46,7 +45,7 @@ class RecurringQuoteFilters extends QueryFilters | |||||||
|      * @param string sort formatted as column|asc |      * @param string sort formatted as column|asc | ||||||
|      * @return Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function sort(string $sort) : Builder |     public function sort(string $sort): Builder | ||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
| @ -56,9 +55,9 @@ class RecurringQuoteFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,11 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use App\Models\Webhook; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * SubscriptionFilters. |  * SubscriptionFilters. | ||||||
| @ -29,7 +25,7 @@ class SubscriptionFilters extends QueryFilters | |||||||
|      * @return Builder |      * @return Builder | ||||||
|      * @deprecated |      * @deprecated | ||||||
|      */ |      */ | ||||||
|     public function filter(string $filter = '') : Builder |     public function filter(string $filter = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($filter) == 0) { |         if (strlen($filter) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
| @ -46,7 +42,7 @@ class SubscriptionFilters extends QueryFilters | |||||||
|      * @param string sort formatted as column|asc |      * @param string sort formatted as column|asc | ||||||
|      * @return Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function sort(string $sort) : Builder |     public function sort(string $sort): Builder | ||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
| @ -56,9 +52,9 @@ class SubscriptionFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,7 +11,6 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -66,9 +65,9 @@ class SystemLogFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,7 +11,6 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use App\Utils\Traits\MakesHash; | use App\Utils\Traits\MakesHash; | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| @ -29,7 +28,7 @@ class TaskFilters extends QueryFilters | |||||||
|      * @return Builder |      * @return Builder | ||||||
|      * @deprecated |      * @deprecated | ||||||
|      */ |      */ | ||||||
|     public function filter(string $filter = '') : Builder |     public function filter(string $filter = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($filter) == 0) { |         if (strlen($filter) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
| @ -55,7 +54,7 @@ class TaskFilters extends QueryFilters | |||||||
|      * @param string client_status The invoice status as seen by the client |      * @param string client_status The invoice status as seen by the client | ||||||
|      * @return Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function client_status(string $value = '') :Builder |     public function client_status(string $value = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($value) == 0) { |         if (strlen($value) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
| @ -90,7 +89,7 @@ class TaskFilters extends QueryFilters | |||||||
|      * @param string sort formatted as column|asc |      * @param string sort formatted as column|asc | ||||||
|      * @return Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function sort(string $sort) : Builder |     public function sort(string $sort): Builder | ||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
| @ -100,9 +99,9 @@ class TaskFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,7 +11,6 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -26,7 +25,7 @@ class TaskStatusFilters extends QueryFilters | |||||||
|      * @return Builder |      * @return Builder | ||||||
|      * @deprecated |      * @deprecated | ||||||
|      */ |      */ | ||||||
|     public function filter(string $filter = '') : Builder |     public function filter(string $filter = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($filter) == 0) { |         if (strlen($filter) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
| @ -53,9 +52,9 @@ class TaskStatusFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,7 +11,6 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -53,9 +52,9 @@ class TaxRateFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,10 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * TokenFilters. |  * TokenFilters. | ||||||
| @ -55,9 +52,9 @@ class TokenFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,7 +11,6 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -61,10 +60,29 @@ class UserFilters extends QueryFilters | |||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter() | ||||||
|     { |     { | ||||||
|         //return $this->builder->user_companies()->whereCompanyId(auth()->user()->company()->id);
 |  | ||||||
|         //return $this->builder->whereCompanyId(auth()->user()->company()->id);
 |  | ||||||
|         return $this->builder->whereHas('company_users', function ($q) { |         return $this->builder->whereHas('company_users', function ($q) { | ||||||
|             $q->where('company_id', '=', auth()->user()->company()->id); |             $q->where('company_id', '=', auth()->user()->company()->id); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Overrides the base with() function as no company ID  | ||||||
|  |      * exists on the user table | ||||||
|  |      *  | ||||||
|  |      * @param  string $value Hashed ID of the user to return back in the dataset | ||||||
|  |      *  | ||||||
|  |      * @return Builder | ||||||
|  |      */ | ||||||
|  |     public function with(string $value = ''): Builder | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         if(strlen($value) == 0) | ||||||
|  |             return $this->builder; | ||||||
|  | 
 | ||||||
|  |         return $this->builder | ||||||
|  |             ->orWhere($this->with_property, $value) | ||||||
|  |             ->orderByRaw("{$this->with_property} = ? DESC", [$value]) | ||||||
|  |             ->where('account_id', auth()->user()->account_id); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,11 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use App\Models\Vendor; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * VendorFilters. |  * VendorFilters. | ||||||
| @ -29,7 +25,7 @@ class VendorFilters extends QueryFilters | |||||||
|      * @return Builder |      * @return Builder | ||||||
|      * @deprecated |      * @deprecated | ||||||
|      */ |      */ | ||||||
|     public function filter(string $filter = '') : Builder |     public function filter(string $filter = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($filter) == 0) { |         if (strlen($filter) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
| @ -56,7 +52,7 @@ class VendorFilters extends QueryFilters | |||||||
|      * @param string sort formatted as column|asc |      * @param string sort formatted as column|asc | ||||||
|      * @return Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function sort(string $sort) : Builder |     public function sort(string $sort): Builder | ||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
| @ -66,12 +62,10 @@ class VendorFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
| 
 |  | ||||||
|         //return $this->builder->whereCompanyId(auth()->user()->company()->id);
 |  | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,11 +11,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Filters; | namespace App\Filters; | ||||||
| 
 | 
 | ||||||
| use App\Models\User; |  | ||||||
| use App\Models\Webhook; |  | ||||||
| use Illuminate\Database\Eloquent\Builder; | use Illuminate\Database\Eloquent\Builder; | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Gate; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * TokenFilters. |  * TokenFilters. | ||||||
| @ -29,14 +25,14 @@ class WebhookFilters extends QueryFilters | |||||||
|      * @return Builder |      * @return Builder | ||||||
|      * @deprecated |      * @deprecated | ||||||
|      */ |      */ | ||||||
|     public function filter(string $filter = '') : Builder |     public function filter(string $filter = ''): Builder | ||||||
|     { |     { | ||||||
|         if (strlen($filter) == 0) { |         if (strlen($filter) == 0) { | ||||||
|             return $this->builder; |             return $this->builder; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return  $this->builder->where(function ($query) use ($filter) { |         return  $this->builder->where(function ($query) use ($filter) { | ||||||
|             $query->where('webhooks.target_url', 'like', '%'.$filter.'%'); |             $query->where('target_url', 'like', '%'.$filter.'%'); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -46,7 +42,7 @@ class WebhookFilters extends QueryFilters | |||||||
|      * @param string sort formatted as column|asc |      * @param string sort formatted as column|asc | ||||||
|      * @return Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function sort(string $sort) : Builder |     public function sort(string $sort): Builder | ||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
| @ -56,9 +52,9 @@ class WebhookFilters extends QueryFilters | |||||||
|     /** |     /** | ||||||
|      * Filters the query by the users company ID. |      * Filters the query by the users company ID. | ||||||
|      * |      * | ||||||
|      * @return Illuminate\Database\Query\Builder |      * @return Builder | ||||||
|      */ |      */ | ||||||
|     public function entityFilter() |     public function entityFilter(): Builder | ||||||
|     { |     { | ||||||
|         return $this->builder->company(); |         return $this->builder->company(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -24,6 +24,9 @@ use Illuminate\View\View; | |||||||
| function isActive($page, bool $boolean = false) | function isActive($page, bool $boolean = false) | ||||||
| { | { | ||||||
|     $current_page = Route::currentRouteName(); |     $current_page = Route::currentRouteName(); | ||||||
|  |     $action = Route::currentRouteAction(); // string
 | ||||||
|  | 
 | ||||||
|  |     $show = str_replace(['.show','payment_methodss','documentss','subscriptionss','paymentss'],['s.index','payment_methods','documents','subscriptions','payments'], $current_page); | ||||||
| 
 | 
 | ||||||
|     if ($page == $current_page && $boolean) { |     if ($page == $current_page && $boolean) { | ||||||
|         return true; |         return true; | ||||||
| @ -33,6 +36,12 @@ function isActive($page, bool $boolean = false) | |||||||
|         return 'bg-gray-200'; |         return 'bg-gray-200'; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if(($page == $show) && $boolean){ | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -56,7 +56,7 @@ class LoginController extends BaseController | |||||||
|      *     description="Authentication", |      *     description="Authentication", | ||||||
|      *     @OA\ExternalDocumentation( |      *     @OA\ExternalDocumentation( | ||||||
|      *         description="Find out more", |      *         description="Find out more", | ||||||
|      *         url="http://docs.invoiceninja.com" |      *         url="https://invoiceninja.github.io" | ||||||
|      *     ) |      *     ) | ||||||
|      * ) |      * ) | ||||||
|      */ |      */ | ||||||
|  | |||||||
| @ -335,7 +335,7 @@ class BankTransactionRuleController extends BaseController | |||||||
|      * |      * | ||||||
|      * @OA\Post( |      * @OA\Post( | ||||||
|      *      path="/api/v1/bank_transaction_rules", |      *      path="/api/v1/bank_transaction_rules", | ||||||
|      *      operationId="storeBankTransaction", |      *      operationId="storeBankTransactionRule", | ||||||
|      *      tags={"bank_transaction_rules"}, |      *      tags={"bank_transaction_rules"}, | ||||||
|      *      summary="Adds a bank_transaction rule", |      *      summary="Adds a bank_transaction rule", | ||||||
|      *      description="Adds an bank_transaction to a company", |      *      description="Adds an bank_transaction to a company", | ||||||
|  | |||||||
| @ -160,7 +160,7 @@ class PaymentController extends Controller | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (property_exists($payment_hash->data, 'billing_context')) { |         if (property_exists($payment_hash->data, 'billing_context')) { | ||||||
|             $billing_subscription = \App\Models\Subscription::find($payment_hash->data->billing_context->subscription_id); |             $billing_subscription = \App\Models\Subscription::find($this->decodePrimaryKey($payment_hash->data->billing_context->subscription_id)); | ||||||
| 
 | 
 | ||||||
|             return (new SubscriptionService($billing_subscription))->completePurchase($payment_hash); |             return (new SubscriptionService($billing_subscription))->completePurchase($payment_hash); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -19,8 +19,8 @@ | |||||||
|  *         url="https://ninja.test", |  *         url="https://ninja.test", | ||||||
|  *     ), |  *     ), | ||||||
|  *     @OA\ExternalDocumentation( |  *     @OA\ExternalDocumentation( | ||||||
|  *         description="http://docs.invoiceninja.com", |  *         description="https://invoiceninja.github.io", | ||||||
|  *         url="http://docs.invoiceninja.com" |  *         url="https://invoiceninja.github.io" | ||||||
|  *     ), |  *     ), | ||||||
|  * ), |  * ), | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -108,6 +108,8 @@ class SelfUpdateController extends BaseController | |||||||
|         $zipFile->openFile($file); |         $zipFile->openFile($file); | ||||||
| 
 | 
 | ||||||
|         $zipFile->deleteFromName(".htaccess"); |         $zipFile->deleteFromName(".htaccess"); | ||||||
|  |          | ||||||
|  |         $zipFile->rewrite(); | ||||||
| 
 | 
 | ||||||
|         $zipFile->extractTo(base_path()); |         $zipFile->extractTo(base_path()); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -323,7 +323,7 @@ class TaskSchedulerController extends BaseController | |||||||
|      *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"), |      *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"), | ||||||
|      *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), |      *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), | ||||||
|      *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), |      *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), | ||||||
|      *          @OA\JsonContent(ref="#/components/schemas/TaskScheduleSchema"), |      *          @OA\JsonContent(ref="#/components/schemas/TaskSchedulerSchema"), | ||||||
|      *       ), |      *       ), | ||||||
|      *       @OA\Response( |      *       @OA\Response( | ||||||
|      *          response=422, |      *          response=422, | ||||||
|  | |||||||
| @ -403,10 +403,10 @@ class BillingPortalPurchase extends Component | |||||||
|             ->save(); |             ->save(); | ||||||
| 
 | 
 | ||||||
|         Cache::put($this->hash, [ |         Cache::put($this->hash, [ | ||||||
|             'subscription_id' => $this->subscription->id, |             'subscription_id' => $this->subscription->hashed_id, | ||||||
|             'email' => $this->email ?? $this->contact->email, |             'email' => $this->email ?? $this->contact->email, | ||||||
|             'client_id' => $this->contact->client->id, |             'client_id' => $this->contact->client->hashed_id, | ||||||
|             'invoice_id' => $this->invoice->id, |             'invoice_id' => $this->invoice->hashed_id, | ||||||
|             'context' => 'purchase', |             'context' => 'purchase', | ||||||
|             'campaign' => $this->campaign, |             'campaign' => $this->campaign, | ||||||
|         ], now()->addMinutes(60)); |         ], now()->addMinutes(60)); | ||||||
|  | |||||||
| @ -483,7 +483,12 @@ class BillingPortalPurchasev2 extends Component | |||||||
|      */ |      */ | ||||||
|     protected function getPaymentMethods() :self |     protected function getPaymentMethods() :self | ||||||
|     { |     { | ||||||
|         if($this->contact) |         nlog("total amount = {$this->float_amount_total}"); | ||||||
|  | 
 | ||||||
|  |         if($this->float_amount_total == 0) | ||||||
|  |             $this->methods = []; | ||||||
|  | 
 | ||||||
|  |         if($this->contact && $this->float_amount_total >= 1) | ||||||
|             $this->methods = $this->contact->client->service()->getPaymentMethods($this->float_amount_total); |             $this->methods = $this->contact->client->service()->getPaymentMethods($this->float_amount_total); | ||||||
| 
 | 
 | ||||||
|         return $this; |         return $this; | ||||||
| @ -526,7 +531,7 @@ class BillingPortalPurchasev2 extends Component | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $data = [ |         $data = [ | ||||||
|             'client_id' => $this->contact->client->id, |             'client_id' => $this->contact->client->hashed_id, | ||||||
|             'date' => now()->format('Y-m-d'), |             'date' => now()->format('Y-m-d'), | ||||||
|             'invitations' => [[ |             'invitations' => [[ | ||||||
|                 'key' => '', |                 'key' => '', | ||||||
| @ -547,10 +552,10 @@ class BillingPortalPurchasev2 extends Component | |||||||
|             ->save(); |             ->save(); | ||||||
| 
 | 
 | ||||||
|         Cache::put($this->hash, [ |         Cache::put($this->hash, [ | ||||||
|             'subscription_id' => $this->subscription->id, |             'subscription_id' => $this->subscription->hashed_id, | ||||||
|             'email' => $this->email ?? $this->contact->email, |             'email' => $this->email ?? $this->contact->email, | ||||||
|             'client_id' => $this->contact->client->id, |             'client_id' => $this->contact->client->hashed_id, | ||||||
|             'invoice_id' => $this->invoice->id, |             'invoice_id' => $this->invoice->hashed_id, | ||||||
|             'context' => 'purchase', |             'context' => 'purchase', | ||||||
|             'campaign' => $this->campaign, |             'campaign' => $this->campaign, | ||||||
|             'bundle' => $this->bundle, |             'bundle' => $this->bundle, | ||||||
| @ -562,17 +567,62 @@ class BillingPortalPurchasev2 extends Component | |||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Starts the trial | ||||||
|  |      *  | ||||||
|  |      * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse | ||||||
|  |      */ | ||||||
|     public function handleTrial() |     public function handleTrial() | ||||||
|     { |     { | ||||||
|         return $this->subscription->service()->startTrial([ |         return $this->subscription->service()->startTrial([ | ||||||
|             'email' => $this->email ?? $this->contact->email, |             'email' => $this->email ?? $this->contact->email, | ||||||
|             'quantity' => $this->quantity, |             'quantity' => $this->quantity, | ||||||
|             'contact_id' => $this->contact->id, |             'contact_id' => $this->contact->hashed_id, | ||||||
|             'client_id' => $this->contact->client->id, |             'client_id' => $this->contact->client->hashed_id, | ||||||
|             'bundle' => $this->bundle, |             'bundle' => $this->bundle, | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * When the subscription total comes to $0 we  | ||||||
|  |      * pass back a $0 Invoice. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse | ||||||
|  |      */ | ||||||
|  |     public function handlePaymentNotRequired() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         $eligibility_check = $this->subscription->service()->isEligible($this->contact); | ||||||
|  | 
 | ||||||
|  |         if(is_array($eligibility_check) && $eligibility_check['message'] != 'Success'){ | ||||||
|  |              | ||||||
|  |             $this->is_eligible = false; | ||||||
|  |             $this->not_eligible_message = $eligibility_check['message']; | ||||||
|  |             return $this; | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $invoice = $this->subscription | ||||||
|  |             ->service() | ||||||
|  |             ->createInvoiceV2($this->bundle, $this->contact->client_id, $this->valid_coupon) | ||||||
|  |             ->service() | ||||||
|  |             ->fillDefaults() | ||||||
|  |             ->adjustInventory() | ||||||
|  |             ->save(); | ||||||
|  | 
 | ||||||
|  |             $invoice->number = null; | ||||||
|  | 
 | ||||||
|  |             $invoice->service() | ||||||
|  |                     ->markPaid() | ||||||
|  |                     ->save(); | ||||||
|  | 
 | ||||||
|  |             return $this->subscription | ||||||
|  |                         ->service() | ||||||
|  |                         ->handleNoPaymentFlow($invoice, $this->bundle, $this->contact); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -607,43 +657,6 @@ class BillingPortalPurchasev2 extends Component | |||||||
|      |      | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // /**
 |  | ||||||
|     //  * Handle user authentication
 |  | ||||||
|     //  *
 |  | ||||||
|     //  * @return $this|bool|void
 |  | ||||||
|     //  */
 |  | ||||||
|     // public function authenticate()
 |  | ||||||
|     // {
 |  | ||||||
|     //     $this->validate();
 |  | ||||||
| 
 |  | ||||||
|     //     $contact = ClientContact::where('email', $this->email)
 |  | ||||||
|     //         ->where('company_id', $this->subscription->company_id)
 |  | ||||||
|     //         ->first();
 |  | ||||||
| 
 |  | ||||||
|     //     if ($contact && $this->steps['existing_user'] === false) {
 |  | ||||||
|     //         return $this->steps['existing_user'] = true;
 |  | ||||||
|     //     }
 |  | ||||||
| 
 |  | ||||||
|     //     if ($contact && $this->steps['existing_user']) {
 |  | ||||||
|     //         $attempt = Auth::guard('contact')->attempt(['email' => $this->email, 'password' => $this->password, 'company_id' => $this->subscription->company_id]);
 |  | ||||||
| 
 |  | ||||||
|     //         return $attempt
 |  | ||||||
|     //             ? $this->getPaymentMethods($contact)
 |  | ||||||
|     //             : session()->flash('message', 'These credentials do not match our records.');
 |  | ||||||
|     //     }
 |  | ||||||
| 
 |  | ||||||
|     //     $this->steps['existing_user'] = false;
 |  | ||||||
| 
 |  | ||||||
|     //     $contact = $this->createBlankClient();
 |  | ||||||
| 
 |  | ||||||
|     //     if ($contact && $contact instanceof ClientContact) {
 |  | ||||||
|     //         $this->getPaymentMethods($contact);
 |  | ||||||
|     //     }
 |  | ||||||
|     // }
 |  | ||||||
| 
 |  | ||||||
|     |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Create a blank client. Used for new customers purchasing. |      * Create a blank client. Used for new customers purchasing. | ||||||
|      * |      * | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ class PaymentsTable extends Component | |||||||
|     public function render() |     public function render() | ||||||
|     { |     { | ||||||
|         $query = Payment::query() |         $query = Payment::query() | ||||||
|             ->with('type', 'client') |             ->with('type', 'client', 'invoices') | ||||||
|             ->where('company_id', $this->company->id) |             ->where('company_id', $this->company->id) | ||||||
|             ->where('client_id', auth()->guard('contact')->user()->client_id) |             ->where('client_id', auth()->guard('contact')->user()->client_id) | ||||||
|             ->whereIn('status_id', [Payment::STATUS_FAILED, Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_REFUNDED, Payment::STATUS_PARTIALLY_REFUNDED]) |             ->whereIn('status_id', [Payment::STATUS_FAILED, Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_REFUNDED, Payment::STATUS_PARTIALLY_REFUNDED]) | ||||||
|  | |||||||
| @ -106,11 +106,11 @@ class SubscriptionPlanSwitch extends Component | |||||||
|             ]); |             ]); | ||||||
| 
 | 
 | ||||||
|             Cache::put($this->hash, [ |             Cache::put($this->hash, [ | ||||||
|                 'subscription_id' => $this->target->id, |                 'subscription_id' => $this->target->hashed_id, | ||||||
|                 'target_id' => $this->target->id, |                 'target_id' => $this->target->hashed_id, | ||||||
|                 'recurring_invoice' => $this->recurring_invoice->id, |                 'recurring_invoice' => $this->recurring_invoice->hashed_id, | ||||||
|                 'client_id' => $this->recurring_invoice->client->id, |                 'client_id' => $this->recurring_invoice->client->hashed_id, | ||||||
|                 'invoice_id' => $this->state['invoice']->id, |                 'invoice_id' => $this->state['invoice']->hashed_id, | ||||||
|                 'context' => 'change_plan', |                 'context' => 'change_plan', | ||||||
|                 now()->addMinutes(60), ] |                 now()->addMinutes(60), ] | ||||||
|                 ); |                 ); | ||||||
|  | |||||||
| @ -78,8 +78,6 @@ class StoreShopClientRequest extends Request | |||||||
| 
 | 
 | ||||||
|         $input = $this->all(); |         $input = $this->all(); | ||||||
| 
 | 
 | ||||||
|         //@todo implement feature permissions for > 100 clients
 |  | ||||||
|         //
 |  | ||||||
|         $settings = ClientSettings::defaults(); |         $settings = ClientSettings::defaults(); | ||||||
| 
 | 
 | ||||||
|         if (array_key_exists('settings', $input) && ! empty($input['settings'])) { |         if (array_key_exists('settings', $input) && ! empty($input['settings'])) { | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ | |||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| namespace App\Http\Requests\Task; | namespace App\Http\Requests\TaskScheduler; | ||||||
| 
 | 
 | ||||||
| use App\Http\Requests\Request; | use App\Http\Requests\Request; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -63,8 +63,6 @@ class StoreUserRequest extends Request | |||||||
|     { |     { | ||||||
|         $input = $this->all(); |         $input = $this->all(); | ||||||
| 
 | 
 | ||||||
|         //unique user rule - check company_user table for user_id / company_id  / account_id if none exist we can add the user. ELSE return false
 |  | ||||||
| 
 |  | ||||||
|         if (array_key_exists('email', $input)) { |         if (array_key_exists('email', $input)) { | ||||||
|             $input['email'] = trim($input['email']); |             $input['email'] = trim($input['email']); | ||||||
|         } |         } | ||||||
| @ -79,12 +77,10 @@ class StoreUserRequest extends Request | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (! isset($input['company_user']['settings'])) { |             if (! isset($input['company_user']['settings'])) { | ||||||
|                 //$input['company_user']['settings'] = DefaultSettings::userSettings();
 |  | ||||||
|                 $input['company_user']['settings'] = null; |                 $input['company_user']['settings'] = null; | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             $input['company_user'] = [ |             $input['company_user'] = [ | ||||||
|                 //'settings' => DefaultSettings::userSettings(),
 |  | ||||||
|                 'settings' => null, |                 'settings' => null, | ||||||
|                 'permissions' => '', |                 'permissions' => '', | ||||||
|             ]; |             ]; | ||||||
|  | |||||||
| @ -319,7 +319,7 @@ class MatchBankTransactions implements ShouldQueue | |||||||
| 
 | 
 | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         }, 1); |         }, 2); | ||||||
| 
 | 
 | ||||||
|         if(!$this->invoice) |         if(!$this->invoice) | ||||||
|             return; |             return; | ||||||
|  | |||||||
| @ -45,6 +45,7 @@ class SubscriptionCron | |||||||
|             $invoices = Invoice::where('is_deleted', 0) |             $invoices = Invoice::where('is_deleted', 0) | ||||||
|                               ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) |                               ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) | ||||||
|                               ->where('balance', '>', 0) |                               ->where('balance', '>', 0) | ||||||
|  |                               ->where('is_proforma',0) | ||||||
|                               ->whereDate('due_date', '<=', now()->addDay()->startOfDay()) |                               ->whereDate('due_date', '<=', now()->addDay()->startOfDay()) | ||||||
|                               ->whereNull('deleted_at') |                               ->whereNull('deleted_at') | ||||||
|                               ->whereNotNull('subscription_id') |                               ->whereNotNull('subscription_id') | ||||||
| @ -74,6 +75,7 @@ class SubscriptionCron | |||||||
|                 $invoices = Invoice::where('is_deleted', 0) |                 $invoices = Invoice::where('is_deleted', 0) | ||||||
|                                   ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) |                                   ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) | ||||||
|                                   ->where('balance', '>', 0) |                                   ->where('balance', '>', 0) | ||||||
|  |                                   ->where('is_proforma',0) | ||||||
|                                   ->whereDate('due_date', '<=', now()->addDay()->startOfDay()) |                                   ->whereDate('due_date', '<=', now()->addDay()->startOfDay()) | ||||||
|                                   ->whereNull('deleted_at') |                                   ->whereNull('deleted_at') | ||||||
|                                   ->whereNotNull('subscription_id') |                                   ->whereNotNull('subscription_id') | ||||||
|  | |||||||
| @ -56,12 +56,5 @@ class InvoiceWorkflowSettings implements ShouldQueue | |||||||
|             /* Throws: Payment amount xxx does not match invoice totals. */ |             /* Throws: Payment amount xxx does not match invoice totals. */ | ||||||
|             $this->base_repository->archive($this->invoice); |             $this->base_repository->archive($this->invoice); | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         //@TODO this setting should only fire for recurring invoices
 |  | ||||||
|         // if ($this->client->getSetting('auto_email_invoice')) {
 |  | ||||||
|         //    $this->invoice->invitations->each(function ($invitation, $key) {
 |  | ||||||
|         //         $this->invoice->service()->sendEmail($invitation->contact);
 |  | ||||||
|         //    });
 |  | ||||||
|         // }
 |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -44,6 +44,7 @@ class BankTransactionSync implements ShouldQueue | |||||||
|      */ |      */ | ||||||
|     public function handle() |     public function handle() | ||||||
|     { |     { | ||||||
|  | 
 | ||||||
|         //multiDB environment, need to
 |         //multiDB environment, need to
 | ||||||
|         foreach (MultiDB::$dbs as $db)  |         foreach (MultiDB::$dbs as $db)  | ||||||
|         { |         { | ||||||
|  | |||||||
| @ -29,6 +29,8 @@ class UpdateOrCreateProduct implements ShouldQueue | |||||||
| 
 | 
 | ||||||
|     public $company; |     public $company; | ||||||
| 
 | 
 | ||||||
|  |     public $deleteWhenMissingModels = true; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Create a new job instance. |      * Create a new job instance. | ||||||
|      * |      * | ||||||
|  | |||||||
| @ -212,6 +212,11 @@ class Payment extends BaseModel | |||||||
|         return Number::formatMoney($this->amount, $this->client); |         return Number::formatMoney($this->amount, $this->client); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function formatAmount(float $amount): string | ||||||
|  |     { | ||||||
|  |         return Number::formatMoney($amount, $this->client); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function clientPaymentDate() |     public function clientPaymentDate() | ||||||
|     { |     { | ||||||
|         if (! $this->date) { |         if (! $this->date) { | ||||||
|  | |||||||
| @ -43,4 +43,5 @@ class Paymentable extends Pivot | |||||||
|     { |     { | ||||||
|         return $this->belongsTo(Payment::class); |         return $this->belongsTo(Payment::class); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -27,7 +27,6 @@ class ClientPresenter extends EntityPresenter | |||||||
|             return $this->entity->name; |             return $this->entity->name; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         //$contact = $this->entity->primary_contact->first();
 |  | ||||||
|         $contact = $this->entity->contacts->whereNotNull('email')->first(); |         $contact = $this->entity->contacts->whereNotNull('email')->first(); | ||||||
| 
 | 
 | ||||||
|         $contact_name = 'No Contact Set'; |         $contact_name = 'No Contact Set'; | ||||||
|  | |||||||
| @ -370,11 +370,6 @@ class User extends Authenticatable implements MustVerifyEmail | |||||||
|                 (is_int(stripos($this->token()->cu->permissions, $all_permission))) || |                 (is_int(stripos($this->token()->cu->permissions, $all_permission))) || | ||||||
|                 (is_int(stripos($this->token()->cu->permissions, $permission))); |                 (is_int(stripos($this->token()->cu->permissions, $permission))); | ||||||
| 
 | 
 | ||||||
|         //23-03-2021 - stripos return an int if true and bool false, but 0 is also interpreted as false, so we simply use is_int() to verify state
 |  | ||||||
|         // return  $this->isOwner() ||
 |  | ||||||
|         //         $this->isAdmin() ||
 |  | ||||||
|         //         (stripos($this->company_user->permissions, $all_permission) !== false) ||
 |  | ||||||
|         //         (stripos($this->company_user->permissions, $permission) !== false);
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function documents() |     public function documents() | ||||||
|  | |||||||
| @ -289,7 +289,7 @@ class BaseDriver extends AbstractPaymentDriver | |||||||
|         event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars())); |         event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars())); | ||||||
| 
 | 
 | ||||||
|         if (property_exists($this->payment_hash->data, 'billing_context') && $status == Payment::STATUS_COMPLETED) { |         if (property_exists($this->payment_hash->data, 'billing_context') && $status == Payment::STATUS_COMPLETED) { | ||||||
|             $billing_subscription = \App\Models\Subscription::find($this->payment_hash->data->billing_context->subscription_id); |             $billing_subscription = \App\Models\Subscription::find($this->decodePrimaryKey($this->payment_hash->data->billing_context->subscription_id)); | ||||||
| 
 | 
 | ||||||
|             // To access campaign hash => $this->payment_hash->data->billing_context->campaign;
 |             // To access campaign hash => $this->payment_hash->data->billing_context->campaign;
 | ||||||
|             // To access campaign data => Cache::get(CAMPAIGN_HASH)
 |             // To access campaign data => Cache::get(CAMPAIGN_HASH)
 | ||||||
|  | |||||||
| @ -18,18 +18,16 @@ use App\Models\Invoice; | |||||||
| use App\Models\Proposal; | use App\Models\Proposal; | ||||||
| use App\Utils\Ninja; | use App\Utils\Ninja; | ||||||
| use App\Utils\TruthSource; | use App\Utils\TruthSource; | ||||||
| use Illuminate\Cache\RateLimiting\Limit; |  | ||||||
| use Illuminate\Database\Eloquent\Model; |  | ||||||
| use Illuminate\Database\Eloquent\Relations\Relation; | use Illuminate\Database\Eloquent\Relations\Relation; | ||||||
| use Illuminate\Mail\Mailer; | use Illuminate\Mail\Mailer; | ||||||
| use Illuminate\Queue\Events\JobProcessing; | use Illuminate\Queue\Events\JobProcessing; | ||||||
| use Illuminate\Support\Facades\App; | use Illuminate\Support\Facades\App; | ||||||
| use Illuminate\Support\Facades\Artisan; | use Illuminate\Support\Facades\Artisan; | ||||||
| use Illuminate\Support\Facades\Blade; | use Illuminate\Support\Facades\Blade; | ||||||
|  | use Illuminate\Support\Facades\DB; | ||||||
| use Illuminate\Support\Facades\Mail; | use Illuminate\Support\Facades\Mail; | ||||||
| use Illuminate\Support\Facades\ParallelTesting; | use Illuminate\Support\Facades\ParallelTesting; | ||||||
| use Illuminate\Support\Facades\Queue; | use Illuminate\Support\Facades\Queue; | ||||||
| use Illuminate\Support\Facades\RateLimiter; |  | ||||||
| use Illuminate\Support\Facades\Schema; | use Illuminate\Support\Facades\Schema; | ||||||
| use Illuminate\Support\ServiceProvider; | use Illuminate\Support\ServiceProvider; | ||||||
| use Livewire\Livewire; | use Livewire\Livewire; | ||||||
| @ -111,13 +109,4 @@ class AppServiceProvider extends ServiceProvider | |||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Register any application services. |  | ||||||
|      * |  | ||||||
|      * @return void |  | ||||||
|      */ |  | ||||||
|     public function register() |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -52,7 +52,6 @@ class ClientRepository extends BaseRepository | |||||||
|      * @return     Client|Client|null  Client Object |      * @return     Client|Client|null  Client Object | ||||||
|      * |      * | ||||||
|      * @throws \Laracasts\Presenter\Exceptions\PresenterException |      * @throws \Laracasts\Presenter\Exceptions\PresenterException | ||||||
|      * @todo       Write tests to make sure that custom client numbers work as expected. |  | ||||||
|      */ |      */ | ||||||
|     public function save(array $data, Client $client) : ?Client |     public function save(array $data, Client $client) : ?Client | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ class ClientService | |||||||
|                 $this->client->balance += $amount; |                 $this->client->balance += $amount; | ||||||
|                 $this->client->save(); |                 $this->client->save(); | ||||||
| 
 | 
 | ||||||
|             }, 1); |             }, 2); | ||||||
|         } |         } | ||||||
|         catch (\Throwable $throwable) { |         catch (\Throwable $throwable) { | ||||||
|             nlog("DB ERROR " . $throwable->getMessage()); |             nlog("DB ERROR " . $throwable->getMessage()); | ||||||
| @ -63,7 +63,7 @@ class ClientService | |||||||
|                 $this->client->paid_to_date += $paid_to_date; |                 $this->client->paid_to_date += $paid_to_date; | ||||||
|                 $this->client->save(); |                 $this->client->save(); | ||||||
| 
 | 
 | ||||||
|             }, 1); |             }, 2); | ||||||
|         } |         } | ||||||
|         catch (\Throwable $throwable) { |         catch (\Throwable $throwable) { | ||||||
|             nlog("DB ERROR " . $throwable->getMessage()); |             nlog("DB ERROR " . $throwable->getMessage()); | ||||||
| @ -82,7 +82,7 @@ class ClientService | |||||||
|             $this->client->paid_to_date += $amount; |             $this->client->paid_to_date += $amount; | ||||||
|             $this->client->save(); |             $this->client->save(); | ||||||
| 
 | 
 | ||||||
|         }, 1); |         }, 2); | ||||||
| 
 | 
 | ||||||
|         return $this; |         return $this; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -230,6 +230,14 @@ class InstantPayment | |||||||
|         elseif($this->request->hash){ |         elseif($this->request->hash){ | ||||||
|             $hash_data['billing_context'] = Cache::get($this->request->hash); |             $hash_data['billing_context'] = Cache::get($this->request->hash); | ||||||
|         } |         } | ||||||
|  |         elseif($old_hash = PaymentHash::where('fee_invoice_id', $first_invoice->id)->whereNull('payment_id')->first()) { | ||||||
|  | 
 | ||||||
|  |             if(isset($old_hash->data->billing_context)) | ||||||
|  |             { | ||||||
|  |                 $hash_data['billing_context'] = $old_hash->data->billing_context; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         $payment_hash = new PaymentHash; |         $payment_hash = new PaymentHash; | ||||||
|         $payment_hash->hash = Str::random(32); |         $payment_hash->hash = Str::random(32); | ||||||
|  | |||||||
| @ -51,7 +51,7 @@ class DeletePayment | |||||||
|                      |                      | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         }, 1); |         }, 2); | ||||||
| 
 | 
 | ||||||
|         return $this->payment; |         return $this->payment; | ||||||
|      |      | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ class SendEmail | |||||||
|         $contact = $this->payment->client->contacts()->first(); |         $contact = $this->payment->client->contacts()->first(); | ||||||
| 
 | 
 | ||||||
|         if ($contact?->email) |         if ($contact?->email) | ||||||
|             EmailPayment::dispatch($this->payment, $this->payment->company, $contact)->delay(now()->addSeconds(3)); |             EmailPayment::dispatch($this->payment, $this->payment->company, $contact)->delay(now()->addSeconds(8)); | ||||||
|           |           | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -47,7 +47,7 @@ class SchedulerService | |||||||
| 
 | 
 | ||||||
|         //Email only the selected clients
 |         //Email only the selected clients
 | ||||||
|         if(count($this->scheduler->parameters['clients']) >= 1) |         if(count($this->scheduler->parameters['clients']) >= 1) | ||||||
|             $query->where('id', $this->transformKeys($this->scheduler->parameters['clients'])); |             $query->whereIn('id', $this->transformKeys($this->scheduler->parameters['clients'])); | ||||||
|       |       | ||||||
|         $query->cursor() |         $query->cursor() | ||||||
|             ->each(function ($_client){ |             ->each(function ($_client){ | ||||||
| @ -119,40 +119,40 @@ class SchedulerService | |||||||
| 
 | 
 | ||||||
|         switch ($this->scheduler->frequency_id) { |         switch ($this->scheduler->frequency_id) { | ||||||
|             case RecurringInvoice::FREQUENCY_DAILY: |             case RecurringInvoice::FREQUENCY_DAILY: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addDay(); |                 $next_run = now()->startOfDay()->addDay(); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_WEEKLY: |             case RecurringInvoice::FREQUENCY_WEEKLY: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addWeek(); |                 $next_run = now()->startOfDay()->addWeek(); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_TWO_WEEKS: |             case RecurringInvoice::FREQUENCY_TWO_WEEKS: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addWeeks(2); |                 $next_run = now()->startOfDay()->addWeeks(2); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_FOUR_WEEKS: |             case RecurringInvoice::FREQUENCY_FOUR_WEEKS: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addWeeks(4); |                 $next_run = now()->startOfDay()->addWeeks(4); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_MONTHLY: |             case RecurringInvoice::FREQUENCY_MONTHLY: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addMonthNoOverflow(); |                 $next_run = now()->startOfDay()->addMonthNoOverflow(); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_TWO_MONTHS: |             case RecurringInvoice::FREQUENCY_TWO_MONTHS: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addMonthsNoOverflow(2); |                 $next_run = now()->startOfDay()->addMonthsNoOverflow(2); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_THREE_MONTHS: |             case RecurringInvoice::FREQUENCY_THREE_MONTHS: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addMonthsNoOverflow(3); |                 $next_run = now()->startOfDay()->addMonthsNoOverflow(3); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_FOUR_MONTHS: |             case RecurringInvoice::FREQUENCY_FOUR_MONTHS: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addMonthsNoOverflow(4); |                 $next_run = now()->startOfDay()->addMonthsNoOverflow(4); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_SIX_MONTHS: |             case RecurringInvoice::FREQUENCY_SIX_MONTHS: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addMonthsNoOverflow(6); |                 $next_run = now()->startOfDay()->addMonthsNoOverflow(6); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_ANNUALLY: |             case RecurringInvoice::FREQUENCY_ANNUALLY: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addYear(); |                 $next_run = now()->startOfDay()->addYear(); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_TWO_YEARS: |             case RecurringInvoice::FREQUENCY_TWO_YEARS: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addYears(2); |                 $next_run = now()->startOfDay()->addYears(2); | ||||||
|                 break; |                 break; | ||||||
|             case RecurringInvoice::FREQUENCY_THREE_YEARS: |             case RecurringInvoice::FREQUENCY_THREE_YEARS: | ||||||
|                 $next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addYears(3); |                 $next_run = now()->startOfDay()->addYears(3); | ||||||
|                 break; |                 break; | ||||||
|             default: |             default: | ||||||
|                 $next_run =  null; |                 $next_run =  null; | ||||||
|  | |||||||
| @ -167,7 +167,7 @@ class SubscriptionService | |||||||
|     public function startTrial(array $data) |     public function startTrial(array $data) | ||||||
|     { |     { | ||||||
|         // Redirects from here work just fine. Livewire will respect it.
 |         // Redirects from here work just fine. Livewire will respect it.
 | ||||||
|         $client_contact = ClientContact::find($data['contact_id']); |         $client_contact = ClientContact::find($this->decodePrimaryKey($data['contact_id'])); | ||||||
| 
 | 
 | ||||||
|         if(!$this->subscription->trial_enabled) |         if(!$this->subscription->trial_enabled) | ||||||
|             return new \Exception("Trials are disabled for this product"); |             return new \Exception("Trials are disabled for this product"); | ||||||
| @ -331,6 +331,7 @@ class SubscriptionService | |||||||
|      * We refund unused days left. |      * We refund unused days left. | ||||||
|      * |      * | ||||||
|      * @param  Invoice $invoice |      * @param  Invoice $invoice | ||||||
|  |      *  | ||||||
|      * @return float |      * @return float | ||||||
|      */ |      */ | ||||||
|     private function calculateProRataRefundForSubscription($invoice) :float |     private function calculateProRataRefundForSubscription($invoice) :float | ||||||
| @ -338,6 +339,20 @@ class SubscriptionService | |||||||
|         if(!$invoice || !$invoice->date || $invoice->status_id != Invoice::STATUS_PAID) |         if(!$invoice || !$invoice->date || $invoice->status_id != Invoice::STATUS_PAID) | ||||||
|             return 0; |             return 0; | ||||||
| 
 | 
 | ||||||
|  |         /*Remove previous refunds from the calculation of the amount*/ | ||||||
|  |         $invoice->line_items = collect($invoice->line_items)->filter(function($item){ | ||||||
|  | 
 | ||||||
|  |             if($item->product_key == ctrans("texts.refund")) | ||||||
|  |             { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  | 
 | ||||||
|  |         })->toArray(); | ||||||
|  | 
 | ||||||
|  |         $amount = $invoice->calc()->getTotal(); | ||||||
|  | 
 | ||||||
|         $start_date = Carbon::parse($invoice->date); |         $start_date = Carbon::parse($invoice->date); | ||||||
| 
 | 
 | ||||||
|         $current_date = now(); |         $current_date = now(); | ||||||
| @ -346,7 +361,7 @@ class SubscriptionService | |||||||
| 
 | 
 | ||||||
|         $days_in_frequency = $this->getDaysInFrequency(); |         $days_in_frequency = $this->getDaysInFrequency(); | ||||||
| 
 | 
 | ||||||
|         $pro_rata_refund = round((($days_in_frequency - $days_of_subscription_used)/$days_in_frequency) * $invoice->amount ,2); |         $pro_rata_refund = round((($days_in_frequency - $days_of_subscription_used)/$days_in_frequency) * $amount ,2); | ||||||
| 
 | 
 | ||||||
|         return max(0, $pro_rata_refund); |         return max(0, $pro_rata_refund); | ||||||
| 
 | 
 | ||||||
| @ -670,6 +685,8 @@ class SubscriptionService | |||||||
|             nlog("pro rata refund = {$pro_rata_refund_amount}"); |             nlog("pro rata refund = {$pro_rata_refund_amount}"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         nlog("{$pro_rata_refund_amount} + {$pro_rata_charge_amount} + {$this->subscription->price}"); | ||||||
|  |          | ||||||
|         $total_payable = $pro_rata_refund_amount + $pro_rata_charge_amount + $this->subscription->price; |         $total_payable = $pro_rata_refund_amount + $pro_rata_charge_amount + $this->subscription->price; | ||||||
| 
 | 
 | ||||||
|         if($total_payable > 0) |         if($total_payable > 0) | ||||||
| @ -734,7 +751,7 @@ class SubscriptionService | |||||||
|     { |     { | ||||||
|         nlog("handle plan change"); |         nlog("handle plan change"); | ||||||
| 
 | 
 | ||||||
|         $old_recurring_invoice = RecurringInvoice::find($payment_hash->data->billing_context->recurring_invoice); |         $old_recurring_invoice = RecurringInvoice::find($this->decodePrimaryKey($payment_hash->data->billing_context->recurring_invoice)); | ||||||
| 
 | 
 | ||||||
|         if(!$old_recurring_invoice)         |         if(!$old_recurring_invoice)         | ||||||
|             return $this->handleRedirect('/client/recurring_invoices/'); |             return $this->handleRedirect('/client/recurring_invoices/'); | ||||||
| @ -1291,7 +1308,12 @@ class SubscriptionService | |||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function getDaysInFrequency() |     /** | ||||||
|  |      * Get the number of days in the currency frequency | ||||||
|  |      *  | ||||||
|  |      * @return int Number of days | ||||||
|  |      */ | ||||||
|  |     private function getDaysInFrequency() :int | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|         switch ($this->subscription->frequency_id) { |         switch ($this->subscription->frequency_id) { | ||||||
| @ -1325,7 +1347,15 @@ class SubscriptionService | |||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function getNextDateForFrequency($date, $frequency) |     /** | ||||||
|  |      * Get the next date by frequency_id | ||||||
|  |      *  | ||||||
|  |      * @param  Carbon $date      The current carbon date | ||||||
|  |      * @param  int               $frequency The frequncy_id of the subscription | ||||||
|  |      *  | ||||||
|  |      * @return ?Carbon           The next date carbon object | ||||||
|  |      */ | ||||||
|  |     public function getNextDateForFrequency($date, $frequency) :?Carbon | ||||||
|     { |     { | ||||||
|         switch ($frequency) { |         switch ($frequency) { | ||||||
|             case RecurringInvoice::FREQUENCY_DAILY: |             case RecurringInvoice::FREQUENCY_DAILY: | ||||||
| @ -1353,11 +1383,56 @@ class SubscriptionService | |||||||
|             case RecurringInvoice::FREQUENCY_THREE_YEARS: |             case RecurringInvoice::FREQUENCY_THREE_YEARS: | ||||||
|                 return $date->addYears(3); |                 return $date->addYears(3); | ||||||
|             default: |             default: | ||||||
|                 return 0; |                 return null; | ||||||
|         }         |         }         | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Handle case where no payment is required | ||||||
|  |      * @param  Invoice       $invoice The Invoice | ||||||
|  |      * @param  array         $bundle  The bundle array | ||||||
|  |      * @param  ClientContact $contact The Client Contact | ||||||
|  |      *  | ||||||
|  |      * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse | ||||||
|  |      */ | ||||||
|  |     public function handleNoPaymentFlow(Invoice $invoice, $bundle, ClientContact $contact) | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         if (strlen($this->subscription->recurring_product_ids) >= 1) { | ||||||
|  | 
 | ||||||
|  |             $recurring_invoice = $this->convertInvoiceToRecurringBundle($contact->client_id, collect($bundle)->map(function ($bund){ return (object) $bund;})); | ||||||
|  | 
 | ||||||
|  |             /* Start the recurring service */ | ||||||
|  |             $recurring_invoice->service() | ||||||
|  |                               ->start() | ||||||
|  |                               ->save(); | ||||||
|  | 
 | ||||||
|  |             $invoice->recurring_id = $recurring_invoice->id; | ||||||
|  |             $invoice->save(); | ||||||
|  | 
 | ||||||
|  |             $context = [ | ||||||
|  |                 'context' => 'recurring_purchase', | ||||||
|  |                 'recurring_invoice' => $recurring_invoice->hashed_id, | ||||||
|  |                 'invoice' => $invoice->hashed_id, | ||||||
|  |                 'client' => $recurring_invoice->client->hashed_id, | ||||||
|  |                 'subscription' => $this->subscription->hashed_id, | ||||||
|  |                 'contact' => $contact->hashed_id, | ||||||
|  |                 'redirect_url' => "/client/recurring_invoices/{$recurring_invoice->hashed_id}", | ||||||
|  |             ]; | ||||||
|  | 
 | ||||||
|  |             $this->triggerWebhook($context); | ||||||
|  | 
 | ||||||
|  |             return $this->handleRedirect($context['redirect_url']); | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $redirect_url = "/client/invoices/{$invoice->hashed_id}"; | ||||||
|  | 
 | ||||||
|  |         return $this->handleRedirect($redirect_url); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|     * 'email' => $this->email ?? $this->contact->email, |     * 'email' => $this->email ?? $this->contact->email, | ||||||
|     * 'quantity' => $this->quantity, |     * 'quantity' => $this->quantity, | ||||||
|  | |||||||
| @ -27,6 +27,9 @@ trait SubscriptionHooker | |||||||
|             'X-Requested-With' => 'XMLHttpRequest', |             'X-Requested-With' => 'XMLHttpRequest', | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|  |         if(!isset($subscription->webhook_configuration['post_purchase_url']) && !isset($subscription->webhook_configuration['post_purchase_rest_method']))    | ||||||
|  |             return []; | ||||||
|  | 
 | ||||||
|         if (count($subscription->webhook_configuration['post_purchase_headers']) >= 1) { |         if (count($subscription->webhook_configuration['post_purchase_headers']) >= 1) { | ||||||
|             $headers = array_merge($headers, $subscription->webhook_configuration['post_purchase_headers']); |             $headers = array_merge($headers, $subscription->webhook_configuration['post_purchase_headers']); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -14,8 +14,8 @@ return [ | |||||||
|     'require_https' => env('REQUIRE_HTTPS', true), |     'require_https' => env('REQUIRE_HTTPS', true), | ||||||
|     'app_url' => rtrim(env('APP_URL', ''), '/'), |     'app_url' => rtrim(env('APP_URL', ''), '/'), | ||||||
|     'app_domain' => env('APP_DOMAIN', 'invoicing.co'), |     'app_domain' => env('APP_DOMAIN', 'invoicing.co'), | ||||||
|     'app_version' => '5.5.56', |     'app_version' => '5.5.57', | ||||||
|     'app_tag' => '5.5.56', |     'app_tag' => '5.5.57', | ||||||
|     'minimum_client_version' => '5.0.16', |     'minimum_client_version' => '5.0.16', | ||||||
|     'terms_version' => '1.0.1', |     'terms_version' => '1.0.1', | ||||||
|     'api_secret' => env('API_SECRET', ''), |     'api_secret' => env('API_SECRET', ''), | ||||||
|  | |||||||
| @ -32,7 +32,7 @@ class SchedulerFactory extends Factory | |||||||
|             'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY, |             'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY, | ||||||
|             'next_run' => now()->addSeconds(rand(86400,8640000)), |             'next_run' => now()->addSeconds(rand(86400,8640000)), | ||||||
|             'next_run_client' => now()->addSeconds(rand(86400,8640000)), |             'next_run_client' => now()->addSeconds(rand(86400,8640000)), | ||||||
|             'template' => 'statement_task', |             'template' => 'client_statement', | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -48,6 +48,7 @@ CREATE TABLE `accounts` ( | |||||||
|   `account_sms_verification_number` text DEFAULT NULL, |   `account_sms_verification_number` text DEFAULT NULL, | ||||||
|   `account_sms_verified` tinyint(1) NOT NULL DEFAULT 0, |   `account_sms_verified` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|   `bank_integration_account_id` text DEFAULT NULL, |   `bank_integration_account_id` text DEFAULT NULL, | ||||||
|  |   `is_trial` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|   PRIMARY KEY (`id`), |   PRIMARY KEY (`id`), | ||||||
|   KEY `accounts_payment_id_index` (`payment_id`), |   KEY `accounts_payment_id_index` (`payment_id`), | ||||||
|   KEY `accounts_key_index` (`key`) |   KEY `accounts_key_index` (`key`) | ||||||
| @ -255,6 +256,7 @@ CREATE TABLE `bank_transactions` ( | |||||||
|   `updated_at` timestamp(6) NULL DEFAULT NULL, |   `updated_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|   `deleted_at` timestamp(6) NULL DEFAULT NULL, |   `deleted_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|   `bank_transaction_rule_id` bigint(20) DEFAULT NULL, |   `bank_transaction_rule_id` bigint(20) DEFAULT NULL, | ||||||
|  |   `payment_id` int(10) unsigned DEFAULT NULL, | ||||||
|   PRIMARY KEY (`id`), |   PRIMARY KEY (`id`), | ||||||
|   KEY `bank_transactions_bank_integration_id_foreign` (`bank_integration_id`), |   KEY `bank_transactions_bank_integration_id_foreign` (`bank_integration_id`), | ||||||
|   KEY `bank_transactions_user_id_foreign` (`user_id`), |   KEY `bank_transactions_user_id_foreign` (`user_id`), | ||||||
| @ -519,7 +521,12 @@ CREATE TABLE `companies` ( | |||||||
|   `invoice_task_project` tinyint(1) NOT NULL DEFAULT 0, |   `invoice_task_project` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|   `report_include_deleted` tinyint(1) NOT NULL DEFAULT 0, |   `report_include_deleted` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|   `invoice_task_lock` tinyint(1) NOT NULL DEFAULT 0, |   `invoice_task_lock` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|   `use_vendor_currency` tinyint(1) NOT NULL DEFAULT 0, |   `matomo_url` varchar(191) DEFAULT NULL, | ||||||
|  |   `matomo_id` bigint(20) DEFAULT NULL, | ||||||
|  |   `convert_payment_currency` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|  |   `convert_expense_currency` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|  |   `notify_vendor_when_paid` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|  |   `invoice_task_hours` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|   PRIMARY KEY (`id`), |   PRIMARY KEY (`id`), | ||||||
|   UNIQUE KEY `companies_company_key_unique` (`company_key`), |   UNIQUE KEY `companies_company_key_unique` (`company_key`), | ||||||
|   KEY `companies_industry_id_foreign` (`industry_id`), |   KEY `companies_industry_id_foreign` (`industry_id`), | ||||||
| @ -1139,6 +1146,7 @@ CREATE TABLE `invoices` ( | |||||||
|   `paid_to_date` decimal(20,6) NOT NULL DEFAULT 0.000000, |   `paid_to_date` decimal(20,6) NOT NULL DEFAULT 0.000000, | ||||||
|   `subscription_id` int(10) unsigned DEFAULT NULL, |   `subscription_id` int(10) unsigned DEFAULT NULL, | ||||||
|   `auto_bill_tries` smallint(6) NOT NULL DEFAULT 0, |   `auto_bill_tries` smallint(6) NOT NULL DEFAULT 0, | ||||||
|  |   `is_proforma` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|   PRIMARY KEY (`id`), |   PRIMARY KEY (`id`), | ||||||
|   UNIQUE KEY `invoices_company_id_number_unique` (`company_id`,`number`), |   UNIQUE KEY `invoices_company_id_number_unique` (`company_id`,`number`), | ||||||
|   KEY `invoices_user_id_foreign` (`user_id`), |   KEY `invoices_user_id_foreign` (`user_id`), | ||||||
| @ -1948,20 +1956,23 @@ DROP TABLE IF EXISTS `schedulers`; | |||||||
| /*!40101 SET character_set_client = utf8 */; | /*!40101 SET character_set_client = utf8 */; | ||||||
| CREATE TABLE `schedulers` ( | CREATE TABLE `schedulers` ( | ||||||
|   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, |   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, | ||||||
|   `paused` tinyint(1) NOT NULL DEFAULT 0, |  | ||||||
|   `is_deleted` tinyint(1) NOT NULL DEFAULT 0, |   `is_deleted` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|   `repeat_every` varchar(191) NOT NULL, |  | ||||||
|   `start_from` timestamp NULL DEFAULT NULL, |  | ||||||
|   `scheduled_run` timestamp NULL DEFAULT NULL, |  | ||||||
|   `company_id` bigint(20) unsigned NOT NULL, |  | ||||||
|   `created_at` timestamp NULL DEFAULT NULL, |   `created_at` timestamp NULL DEFAULT NULL, | ||||||
|   `updated_at` timestamp NULL DEFAULT NULL, |   `updated_at` timestamp NULL DEFAULT NULL, | ||||||
|   `deleted_at` timestamp NULL DEFAULT NULL, |   `deleted_at` timestamp NULL DEFAULT NULL, | ||||||
|   `action_name` varchar(191) NOT NULL, |  | ||||||
|   `action_class` varchar(191) NOT NULL, |  | ||||||
|   `parameters` mediumtext DEFAULT NULL, |   `parameters` mediumtext DEFAULT NULL, | ||||||
|  |   `company_id` int(10) unsigned NOT NULL, | ||||||
|  |   `is_paused` tinyint(1) NOT NULL DEFAULT 0, | ||||||
|  |   `frequency_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `next_run` datetime DEFAULT NULL, | ||||||
|  |   `next_run_client` datetime DEFAULT NULL, | ||||||
|  |   `user_id` int(10) unsigned NOT NULL, | ||||||
|  |   `name` varchar(191) NOT NULL, | ||||||
|  |   `template` varchar(191) NOT NULL, | ||||||
|   PRIMARY KEY (`id`), |   PRIMARY KEY (`id`), | ||||||
|   KEY `schedulers_action_name_index` (`action_name`) |   UNIQUE KEY `schedulers_company_id_name_unique` (`company_id`,`name`), | ||||||
|  |   KEY `schedulers_company_id_deleted_at_index` (`company_id`,`deleted_at`), | ||||||
|  |   CONSTRAINT `schedulers_company_id_foreign` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE ON UPDATE CASCADE | ||||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; | ||||||
| /*!40101 SET character_set_client = @saved_cs_client */; | /*!40101 SET character_set_client = @saved_cs_client */; | ||||||
| DROP TABLE IF EXISTS `sizes`; | DROP TABLE IF EXISTS `sizes`; | ||||||
| @ -2522,3 +2533,10 @@ INSERT INTO `migrations` VALUES (171,'2022_11_06_215526_drop_html_backups_column | |||||||
| INSERT INTO `migrations` VALUES (172,'2022_11_13_034143_bank_transaction_rules_table',1); | INSERT INTO `migrations` VALUES (172,'2022_11_13_034143_bank_transaction_rules_table',1); | ||||||
| INSERT INTO `migrations` VALUES (173,'2022_11_16_093535_calmness_design',1); | INSERT INTO `migrations` VALUES (173,'2022_11_16_093535_calmness_design',1); | ||||||
| INSERT INTO `migrations` VALUES (174,'2022_11_22_215618_lock_tasks_when_invoiced',1); | INSERT INTO `migrations` VALUES (174,'2022_11_22_215618_lock_tasks_when_invoiced',1); | ||||||
|  | INSERT INTO `migrations` VALUES (175,'2022_05_12_56879_add_stripe_klarna',2); | ||||||
|  | INSERT INTO `migrations` VALUES (176,'2022_07_12_45766_add_matomo',2); | ||||||
|  | INSERT INTO `migrations` VALUES (177,'2022_11_30_063229_add_payment_id_to_bank_transaction_table',2); | ||||||
|  | INSERT INTO `migrations` VALUES (178,'2022_12_07_024625_add_properties_to_companies_table',2); | ||||||
|  | INSERT INTO `migrations` VALUES (179,'2022_12_14_004639_vendor_currency_update',2); | ||||||
|  | INSERT INTO `migrations` VALUES (180,'2022_12_20_063038_set_proforma_invoice_type',2); | ||||||
|  | INSERT INTO `migrations` VALUES (181,'2023_01_12_125540_set_auto_bill_on_regular_invoice_setting',2); | ||||||
							
								
								
									
										108
									
								
								phpunit.yml
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								phpunit.yml
									
									
									
									
									
								
							| @ -1,108 +0,0 @@ | |||||||
| on: |  | ||||||
|   push: |  | ||||||
|     branches: |  | ||||||
|       - v5-develop |  | ||||||
|   pull_request: |  | ||||||
|     branches: |  | ||||||
|       - v5-develop |  | ||||||
| 
 |  | ||||||
| name: phpunit |  | ||||||
| jobs: |  | ||||||
|   run: |  | ||||||
|     runs-on: ${{ matrix.operating-system }} |  | ||||||
|     strategy: |  | ||||||
|       matrix: |  | ||||||
|         operating-system: ['ubuntu-18.04', 'ubuntu-20.04'] |  | ||||||
|         php-versions: ['7.3','7.4','8.0'] |  | ||||||
|         phpunit-versions: ['latest'] |  | ||||||
| 
 |  | ||||||
|     env: |  | ||||||
|       DB_DATABASE1: ninja |  | ||||||
|       DB_USERNAME1: root |  | ||||||
|       DB_PASSWORD1: ninja |  | ||||||
|       DB_HOST1: '127.0.0.1' |  | ||||||
|       DB_DATABASE: ninja |  | ||||||
|       DB_USERNAME: root |  | ||||||
|       DB_PASSWORD: ninja |  | ||||||
|       DB_HOST: '127.0.0.1' |  | ||||||
|       BROADCAST_DRIVER: log |  | ||||||
|       CACHE_DRIVER: file |  | ||||||
|       QUEUE_CONNECTION: sync |  | ||||||
|       SESSION_DRIVER: file |  | ||||||
|       NINJA_ENVIRONMENT: hosted |  | ||||||
|       MULTI_DB_ENABLED: false |  | ||||||
|       NINJA_LICENSE: 123456 |  | ||||||
|       TRAVIS: true |  | ||||||
|       MAIL_MAILER: log |  | ||||||
| 
 |  | ||||||
|     services: |  | ||||||
|       mariadb: |  | ||||||
|         image: mariadb:latest |  | ||||||
|         ports: |  | ||||||
|           - 32768:3306 |  | ||||||
|         env: |  | ||||||
|           MYSQL_ALLOW_EMPTY_PASSWORD: yes |  | ||||||
|           MYSQL_USER: ninja |  | ||||||
|           MYSQL_PASSWORD: ninja |  | ||||||
|           MYSQL_DATABASE: ninja |  | ||||||
|           MYSQL_ROOT_PASSWORD: ninja |  | ||||||
|         options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 |  | ||||||
| 
 |  | ||||||
|     steps: |  | ||||||
|     - name: Start mysql service |  | ||||||
|       run: | |  | ||||||
|         sudo systemctl start mysql.service |  | ||||||
|     - name: Verify MariaDB connection |  | ||||||
|       env: |  | ||||||
|         DB_PORT: ${{ job.services.mariadb.ports[3306] }} |  | ||||||
|         DB_PORT1: ${{ job.services.mariadb.ports[3306] }} |  | ||||||
| 
 |  | ||||||
|       run: | |  | ||||||
|         while ! mysqladmin ping -h"127.0.0.1" -P"$DB_PORT" --silent; do |  | ||||||
|           sleep 1 |  | ||||||
|         done |  | ||||||
|     - name: Setup PHP |  | ||||||
|       uses: shivammathur/setup-php@v2 |  | ||||||
|       with: |  | ||||||
|         php-version: ${{ matrix.php-versions }} |  | ||||||
|         extensions: mysql, mysqlnd, sqlite3, bcmath, gmp, gd, curl, zip, openssl, mbstring, xml |  | ||||||
| 
 |  | ||||||
|     - uses: actions/checkout@v1 |  | ||||||
|       with: |  | ||||||
|         ref: v5-develop |  | ||||||
|         fetch-depth: 1 |  | ||||||
| 
 |  | ||||||
|     - name: Copy .env |  | ||||||
|       run: | |  | ||||||
|         cp .env.ci .env |  | ||||||
|     - name: Install composer dependencies |  | ||||||
|       run: | |  | ||||||
|         composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }} |  | ||||||
|         composer install |  | ||||||
|     - name: Prepare Laravel Application |  | ||||||
|       run: | |  | ||||||
|         php artisan key:generate |  | ||||||
|         php artisan optimize |  | ||||||
|         php artisan cache:clear |  | ||||||
|         php artisan config:cache |  | ||||||
|     - name: Create DB and schemas |  | ||||||
|       run: | |  | ||||||
|         mkdir -p database |  | ||||||
|         touch database/database.sqlite |  | ||||||
|     - name: Migrate Database |  | ||||||
|       run: | |  | ||||||
|         php artisan migrate:fresh --seed --force && php artisan db:seed --force |  | ||||||
|     - name: Prepare JS/CSS assets |  | ||||||
|       run: | |  | ||||||
|         npm i |  | ||||||
|         npm run production |  | ||||||
|     - name: Run Testsuite |  | ||||||
|       run: | |  | ||||||
|         cat .env |  | ||||||
|         vendor/bin/phpunit --testdox |  | ||||||
|       env: |  | ||||||
|         DB_PORT: ${{ job.services.mysql.ports[3306] }} |  | ||||||
| 
 |  | ||||||
|     - name: Run php-cs-fixer |  | ||||||
|       run: | |  | ||||||
|         vendor/bin/php-cs-fixer fix |  | ||||||
| @ -51,18 +51,34 @@ | |||||||
|                           </div> |                           </div> | ||||||
|                           <p class="mt-1 text-sm text-gray-500"></p> |                           <p class="mt-1 text-sm text-gray-500"></p> | ||||||
|                         </div> |                         </div> | ||||||
|                         <div class="flex content-end text-sm mt-1"> |                         <div class="flex justify-between text-sm mt-1"> | ||||||
|                             @if($subscription->per_seat_enabled) |                             @if($subscription->per_seat_enabled) | ||||||
|                             <p class="text-gray-500 w-full"></p> |                             <p class="text-gray-500 w-3/4"></p> | ||||||
|                             <div class="flex place-content-end"> |                             <div class="flex place-content-end"> | ||||||
|  |                                 @if($subscription->use_inventory_management && $product->in_stock_quantity == 0) | ||||||
|  |                                 <p class="text-sm font-light text-red-500 text-right mr-2 mt-2">Out of stock</p> | ||||||
|  |                                 @else | ||||||
|                                 <p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p> |                                 <p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p> | ||||||
|  |                                 @endif | ||||||
|  |                                 <select wire:model.debounce.300ms="data.{{ $index }}.recurring_qty" class="rounded-md border-gray-300 shadow-sm sm:text-sm"  | ||||||
|  |                                     @if($subscription->use_inventory_management && $product->in_stock_quantity == 0) | ||||||
|  |                                     disabled  | ||||||
|  |                                     @endif | ||||||
|  |                                     > | ||||||
|  |                                     <option value="1" selected="selected">1</option> | ||||||
| 
 | 
 | ||||||
|                                     <select wire:model.debounce.300ms="data.{{ $index }}.recurring_qty" class="rounded-md border-gray-300 shadow-sm sm:text-sm"> |                                     @if($subscription->max_seats_limit > 1) | ||||||
|                                         <option value="1" selected="selected">1</option> |                                     { | ||||||
|                                         @for ($i = 2; $i <= $subscription->max_seats_limit; $i++) |                                         @for ($i = 2; $i <= ($subscription->use_inventory_management ? min($subscription->max_seats_limit,$product->in_stock_quantity) : $subscription->max_seats_limit); $i++) | ||||||
|                                         <option value="{{$i}}">{{$i}}</option> |                                         <option value="{{$i}}">{{$i}}</option> | ||||||
|                                         @endfor |                                         @endfor | ||||||
|                                     </select> |                                     } | ||||||
|  |                                     @else | ||||||
|  |                                         @for ($i = 2; $i <= ($subscription->use_inventory_management ? min($product->in_stock_quantity, max(100,$product->custom_value2)) : max(100,$product->custom_value2)); $i++) | ||||||
|  |                                         <option value="{{$i}}">{{$i}}</option> | ||||||
|  |                                         @endfor | ||||||
|  |                                     @endif | ||||||
|  |                                 </select> | ||||||
|                             </div> |                             </div> | ||||||
|                             @endif |                             @endif | ||||||
|                         </div> |                         </div> | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ | |||||||
|                             {{ $payment->translatedType() }} |                             {{ $payment->translatedType() }} | ||||||
|                         </td> |                         </td> | ||||||
|                         <td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500"> |                         <td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500"> | ||||||
|                             {!! \App\Utils\Number::formatMoney($payment->amount, $payment->client) !!} |                             {!! \App\Utils\Number::formatMoney($payment->amount > 0 ? $payment->amount : $payment->credits->sum('pivot.amount'), $payment->client) !!} | ||||||
|                         </td> |                         </td> | ||||||
|                         <td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500"> |                         <td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500"> | ||||||
|                             {{ \Illuminate\Support\Str::limit($payment->transaction_reference, 35) }} |                             {{ \Illuminate\Support\Str::limit($payment->transaction_reference, 35) }} | ||||||
|  | |||||||
| @ -66,7 +66,7 @@ | |||||||
|                                 {{ ctrans('texts.amount') }} |                                 {{ ctrans('texts.amount') }} | ||||||
|                             </dt> |                             </dt> | ||||||
|                             <dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2"> |                             <dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2"> | ||||||
|                                 {{ $payment->formattedAmount() }} |                                 {{ $payment->formatAmount($payment->amount > 0 ? $payment->amount : $payment?->invoices->sum('pivot.amount')) }} | ||||||
|                             </dd> |                             </dd> | ||||||
|                         </div> |                         </div> | ||||||
|                     @endif |                     @endif | ||||||
| @ -116,6 +116,7 @@ | |||||||
|                                    href="{{ route('client.invoice.show', ['invoice' => $invoice->hashed_id])}}"> |                                    href="{{ route('client.invoice.show', ['invoice' => $invoice->hashed_id])}}"> | ||||||
|                                     {{ $invoice->number }} |                                     {{ $invoice->number }} | ||||||
|                                 </a> |                                 </a> | ||||||
|  |                                 - {{ \App\Utils\Number::formatMoney($payment->invoices->where('id', $invoice->id)->sum('pivot.amount') - $payment->invoices->where('id', $invoice->id)->sum('pivot.refunded'), $payment->client) }} | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
|                     @endforeach |                     @endforeach | ||||||
|  | |||||||
| @ -12,18 +12,11 @@ | |||||||
| 
 | 
 | ||||||
| namespace Tests\Feature\Account; | namespace Tests\Feature\Account; | ||||||
| 
 | 
 | ||||||
| use App\DataMapper\ClientSettings; | use App\DataMapper\ClientRegistrationFields; | ||||||
| use App\DataMapper\CompanySettings; | use App\DataMapper\CompanySettings; | ||||||
| use App\Http\Livewire\CreditsTable; |  | ||||||
| use App\Models\Account; | use App\Models\Account; | ||||||
| use App\Models\Client; |  | ||||||
| use App\Models\ClientContact; |  | ||||||
| use App\Models\Company; | use App\Models\Company; | ||||||
| use App\Models\Credit; | use App\Utils\Ninja; | ||||||
| use App\Models\User; |  | ||||||
| use App\Utils\Traits\AppSetup; |  | ||||||
| use Faker\Factory; |  | ||||||
| use Illuminate\Foundation\Testing\DatabaseTransactions; |  | ||||||
| use Illuminate\Support\Facades\Cache; | use Illuminate\Support\Facades\Cache; | ||||||
| use Livewire\Livewire; | use Livewire\Livewire; | ||||||
| use Tests\MockAccountData; | use Tests\MockAccountData; | ||||||
| @ -31,30 +24,123 @@ use Tests\TestCase; | |||||||
| 
 | 
 | ||||||
| class AccountEmailQuotaTest extends TestCase | class AccountEmailQuotaTest extends TestCase | ||||||
| { | { | ||||||
|     use DatabaseTransactions; |  | ||||||
|     use AppSetup; |  | ||||||
|     use MockAccountData; |  | ||||||
| 
 | 
 | ||||||
|     protected function setUp(): void |     protected function setUp(): void | ||||||
|     { |     { | ||||||
|         parent::setUp(); |         parent::setUp(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public function testIfQuotaBreached() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         config([ | ||||||
|  |             'ninja.production' => true | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |         $account = Account::factory()->create([ | ||||||
|  |             'hosted_client_count' => 1000, | ||||||
|  |             'hosted_company_count' => 1000, | ||||||
|  |             'is_flagged' => false, | ||||||
|  |             'key' => '123ifyouknowwhatimean', | ||||||
|  |             'created_at' => now(), | ||||||
|  |             'updated_at' => now(), | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |         $account->num_users = 3; | ||||||
|  |         $account->save(); | ||||||
|  | 
 | ||||||
|  |         $company = Company::factory()->create([ | ||||||
|  |             'account_id' => $account->id, | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |         $company->client_registration_fields = ClientRegistrationFields::generate(); | ||||||
|  | 
 | ||||||
|  |         $settings = CompanySettings::defaults(); | ||||||
|  | 
 | ||||||
|  |         $settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png'; | ||||||
|  |         $settings->website = 'www.invoiceninja.com'; | ||||||
|  |         $settings->address1 = 'Address 1'; | ||||||
|  |         $settings->address2 = 'Address 2'; | ||||||
|  |         $settings->city = 'City'; | ||||||
|  |         $settings->state = 'State'; | ||||||
|  |         $settings->postal_code = 'Postal Code'; | ||||||
|  |         $settings->phone = '555-343-2323'; | ||||||
|  |         $settings->email = 'nothingtoofancy@acme.com'; | ||||||
|  |         $settings->country_id = '840'; | ||||||
|  |         $settings->vat_number = 'vat number'; | ||||||
|  |         $settings->id_number = 'id number'; | ||||||
|  |         $settings->use_credits_payment = 'always'; | ||||||
|  |         $settings->timezone_id = '1'; | ||||||
|  |         $settings->entity_send_time = 0; | ||||||
|  | 
 | ||||||
|  |         $company->track_inventory = true; | ||||||
|  |         $company->settings = $settings; | ||||||
|  |         $company->save(); | ||||||
|  | 
 | ||||||
|  |         $account->default_company_id = $company->id; | ||||||
|  |         $account->save(); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         Cache::put($account->key, 3000); | ||||||
|  | 
 | ||||||
|  |         $this->assertFalse($account->isPaid()); | ||||||
|  |         $this->assertTrue(Ninja::isNinja()); | ||||||
|  |         $this->assertEquals(20, $account->getDailyEmailLimit()); | ||||||
|  | 
 | ||||||
|  |         $this->assertEquals(3000, Cache::get($account->key)); | ||||||
|  |         $this->assertTrue($account->emailQuotaExceeded()); | ||||||
|  | 
 | ||||||
|  |         Cache::forget('123ifyouknowwhatimean'); | ||||||
| 
 | 
 | ||||||
|         $this->faker = Factory::create(); |  | ||||||
|         $this->buildCache(true); |  | ||||||
|         $this->makeTestData(); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function testQuotaValidRule() |     public function testQuotaValidRule() | ||||||
|     { |     { | ||||||
|         Cache::increment($this->account->key); |  | ||||||
| 
 | 
 | ||||||
|         $this->assertFalse($this->account->emailQuotaExceeded()); |         $account = Account::factory()->create([ | ||||||
|  |             'hosted_client_count' => 1000, | ||||||
|  |             'hosted_company_count' => 1000, | ||||||
|  |             'is_flagged' => false, | ||||||
|  |             'key' => '123ifyouknowwhatimean', | ||||||
|  |             'created_at' => now(), | ||||||
|  |             'updated_at' => now(), | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |         $account->num_users = 3; | ||||||
|  |         $account->save(); | ||||||
|  | 
 | ||||||
|  |         Cache::increment($account->key); | ||||||
|  | 
 | ||||||
|  |         $this->assertFalse($account->emailQuotaExceeded()); | ||||||
|  | 
 | ||||||
|  |         Cache::forget('123ifyouknowwhatimean'); | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function testQuotaInValidRule() |     public function testEmailSentCount() | ||||||
|     { |     { | ||||||
|         Cache::increment($this->account->key, 3000); |         $account = Account::factory()->create([ | ||||||
|  |             'hosted_client_count' => 1000, | ||||||
|  |             'hosted_company_count' => 1000, | ||||||
|  |             'is_flagged' => false, | ||||||
|  |             'key' => '123ifyouknowwhatimean', | ||||||
|  |             'created_at' => now(), | ||||||
|  |             'updated_at' => now(), | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |         $account->num_users = 3; | ||||||
|  |         $account->save(); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         Cache::put($account->key, 3000); | ||||||
|  | 
 | ||||||
|  |         $count = $account->emailsSent(); | ||||||
|  | 
 | ||||||
|  |         $this->assertEquals(3000, $count); | ||||||
|  | 
 | ||||||
|  |         Cache::forget('123ifyouknowwhatimean'); | ||||||
| 
 | 
 | ||||||
|         $this->assertTrue($this->account->emailQuotaExceeded()); |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,7 +15,6 @@ use App\Utils\Traits\MakesHash; | |||||||
| use Illuminate\Database\Eloquent\Model; | use Illuminate\Database\Eloquent\Model; | ||||||
| use Illuminate\Foundation\Testing\DatabaseTransactions; | use Illuminate\Foundation\Testing\DatabaseTransactions; | ||||||
| use Illuminate\Support\Facades\Session; | use Illuminate\Support\Facades\Session; | ||||||
| use Illuminate\Validation\ValidationException; |  | ||||||
| use Tests\MockAccountData; | use Tests\MockAccountData; | ||||||
| use Tests\TestCase; | use Tests\TestCase; | ||||||
| 
 | 
 | ||||||
| @ -42,6 +41,17 @@ class BankTransactionApiTest extends TestCase | |||||||
|         Model::reguard(); |         Model::reguard(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     public function testBankTransactionGetClientStatus() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/bank_transactions?client_status=unmatched'.$this->encodePrimaryKey($this->bank_transaction->id)); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testBankTransactionGet() |     public function testBankTransactionGet() | ||||||
|     { |     { | ||||||
|         $response = $this->withHeaders([ |         $response = $this->withHeaders([ | ||||||
|  | |||||||
| @ -48,6 +48,19 @@ class CompanyTokenApiTest extends TestCase | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testCompanyTokenListFilter() | ||||||
|  |     { | ||||||
|  |         $this->withoutMiddleware(PasswordProtection::class); | ||||||
|  | 
 | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |             'X-API-PASSWORD' => 'ALongAndBriliantPassword', | ||||||
|  |         ])->get('/api/v1/tokens?filter=xx'); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testCompanyTokenList() |     public function testCompanyTokenList() | ||||||
|     { |     { | ||||||
|         $this->withoutMiddleware(PasswordProtection::class); |         $this->withoutMiddleware(PasswordProtection::class); | ||||||
|  | |||||||
| @ -40,6 +40,16 @@ class CreditTest extends TestCase | |||||||
|         $this->makeTestData(); |         $this->makeTestData(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testCreditGetClientStatus() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/credits?client_status=draft'.$this->encodePrimaryKey($this->bank_transaction->id)); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testCreditsList() |     public function testCreditsList() | ||||||
|     { |     { | ||||||
|         Client::factory()->count(3)->create(['user_id' => $this->user->id, 'company_id' => $this->company->id])->each(function ($c) { |         Client::factory()->count(3)->create(['user_id' => $this->user->id, 'company_id' => $this->company->id])->each(function ($c) { | ||||||
|  | |||||||
							
								
								
									
										212
									
								
								tests/Feature/Email/EmailServiceTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								tests/Feature/Email/EmailServiceTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,212 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Invoice Ninja (https://invoiceninja.com). | ||||||
|  |  * | ||||||
|  |  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com) | ||||||
|  |  * | ||||||
|  |  * @license https://www.elastic.co/licensing/elastic-license | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace Tests\Feature\Email; | ||||||
|  | 
 | ||||||
|  | use App\Services\Email\EmailObject; | ||||||
|  | use App\Services\Email\EmailService; | ||||||
|  | use App\Utils\Traits\GeneratesCounter; | ||||||
|  | use App\Utils\Traits\MakesHash; | ||||||
|  | use Illuminate\Routing\Middleware\ThrottleRequests; | ||||||
|  | use Tests\MockAccountData; | ||||||
|  | use Tests\TestCase; | ||||||
|  | use Illuminate\Mail\Mailables\Address; | ||||||
|  | use Illuminate\Support\Facades\Cache; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @test | ||||||
|  |  * @covers  App\Services\Email\EmailService | ||||||
|  |  */ | ||||||
|  | class EmailServiceTest extends TestCase | ||||||
|  | { | ||||||
|  |     use MakesHash; | ||||||
|  |     use GeneratesCounter; | ||||||
|  |     use MockAccountData; | ||||||
|  | 
 | ||||||
|  |     public EmailService $email_service; | ||||||
|  | 
 | ||||||
|  |     public EmailObject $email_object; | ||||||
|  | 
 | ||||||
|  |     protected function setUp() :void | ||||||
|  |     { | ||||||
|  |         parent::setUp(); | ||||||
|  | 
 | ||||||
|  |         if(!class_exists(\Modules\Admin\Jobs\Account\EmailFilter::class)) | ||||||
|  |             $this->markTestSkipped('Skipped :: test not needed in this environment'); | ||||||
|  | 
 | ||||||
|  |         $this->makeTestData(); | ||||||
|  | 
 | ||||||
|  |         $this->email_object = new EmailObject(); | ||||||
|  |         $this->email_object->to = [new Address("testing@gmail.com", "Cool Name")]; | ||||||
|  |         $this->email_object->attachments = []; | ||||||
|  |         $this->email_object->settings = $this->client->getMergedSettings(); | ||||||
|  |         $this->email_object->company = $this->client->company; | ||||||
|  |         $this->email_object->client = $this->client; | ||||||
|  |         $this->email_object->email_template_subject = 'email_subject_statement'; | ||||||
|  |         $this->email_object->email_template_body = 'email_template_statement'; | ||||||
|  |         $this->email_object->variables = [ | ||||||
|  |             '$client' => $this->client->present()->name(), | ||||||
|  |             '$start_date' => '2022-01-01', | ||||||
|  |             '$end_date' => '2023-01-01', | ||||||
|  |         ]; | ||||||
|  | 
 | ||||||
|  |         $this->email_service = new EmailService($this->email_object, $this->company); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function testScanEmailsAttemptedFromVerifiedAccounts() | ||||||
|  |     { | ||||||
|  |         $email_filter = new \Modules\Admin\Jobs\Account\EmailFilter($this->email_object, $this->client->company); | ||||||
|  | 
 | ||||||
|  |         Cache::put($this->account->key, 1); | ||||||
|  | 
 | ||||||
|  |         config(['ninja.environment' => 'hosted']); | ||||||
|  | 
 | ||||||
|  |         $this->account->account_sms_verified = true; | ||||||
|  |         $this->account->is_verified_account = false; | ||||||
|  |         $this->account->save(); | ||||||
|  | 
 | ||||||
|  |         $this->assertFalse($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  |         collect($email_filter->getSpamKeywords())->each(function ($spam_subject){ | ||||||
|  | 
 | ||||||
|  |             $this->email_object->subject = $spam_subject; | ||||||
|  | 
 | ||||||
|  |             $this->assertTrue($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public function scanEmailsAttemptedFromUnverifiedAccounts() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         config(['ninja.environment' => 'hosted']); | ||||||
|  | 
 | ||||||
|  |         Cache::put($this->account->key, 1); | ||||||
|  | 
 | ||||||
|  |         $this->account->account_sms_verified = false; | ||||||
|  |         $this->account->save(); | ||||||
|  | 
 | ||||||
|  |         $this->assertTrue($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public function testVerifiedAccountsSkipFilters() | ||||||
|  |     { | ||||||
|  |         config(['ninja.environment' => 'hosted']); | ||||||
|  | 
 | ||||||
|  |         Cache::put($this->account->key, 1); | ||||||
|  | 
 | ||||||
|  |         $this->account->is_verified_account = true; | ||||||
|  |         $this->account->save(); | ||||||
|  | 
 | ||||||
|  |         $this->assertFalse($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function testClientMailersAreUnCapped() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         config(['ninja.environment' => 'hosted']); | ||||||
|  | 
 | ||||||
|  |         Cache::put($this->account->key, 1000000); | ||||||
|  | 
 | ||||||
|  |         collect([ | ||||||
|  |             'gmail',  | ||||||
|  |             'office365',  | ||||||
|  |             'client_postmark',  | ||||||
|  |             'client_mailgun']) | ||||||
|  |         ->each(function ($mailer){ | ||||||
|  | 
 | ||||||
|  |             $this->email_object->settings->email_sending_method = $mailer; | ||||||
|  | 
 | ||||||
|  |             $this->assertFalse($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         $this->email_object->settings->email_sending_method = 'postmark'; | ||||||
|  | 
 | ||||||
|  |         $this->assertTrue($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function testFlaggedInvalidEmailsPrevented() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         config(['ninja.environment' => 'hosted']); | ||||||
|  | 
 | ||||||
|  |         Cache::put($this->account->key, 1); | ||||||
|  | 
 | ||||||
|  |             $this->email_object->to = [new Address("user@example.com", "Cool Name")]; | ||||||
|  | 
 | ||||||
|  |             $this->assertTrue($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         collect([ | ||||||
|  |             'user@example.com', | ||||||
|  |             '', | ||||||
|  |             'bademail', | ||||||
|  |             'domain.com', | ||||||
|  |         ])->each(function ($email){ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |             $this->email_object->to = [new Address($email, "Cool Name")]; | ||||||
|  | 
 | ||||||
|  |             $this->assertTrue($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |          | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function testFlaggedAccountsPrevented() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         Cache::put($this->account->key, 1); | ||||||
|  | 
 | ||||||
|  |         config(['ninja.environment' => 'hosted']); | ||||||
|  | 
 | ||||||
|  |         $this->account->is_flagged = true; | ||||||
|  |         $this->account->save(); | ||||||
|  | 
 | ||||||
|  |         $this->assertTrue($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function testPreFlightChecksHosted() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         Cache::put($this->account->key, 1); | ||||||
|  |      | ||||||
|  |         config(['ninja.environment' => 'hosted']); | ||||||
|  |      | ||||||
|  |         $this->assertFalse($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function testPreFlightChecksSelfHost() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         Cache::put($this->account->key, 1); | ||||||
|  | 
 | ||||||
|  |         config(['ninja.environment' => 'selfhost']); | ||||||
|  |      | ||||||
|  |         $this->assertFalse($this->email_service->preFlightChecksFail()); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -1,84 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * Invoice Ninja (https://invoiceninja.com). |  | ||||||
|  * |  | ||||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository |  | ||||||
|  * |  | ||||||
|  * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com) |  | ||||||
|  * |  | ||||||
|  * @license https://www.elastic.co/licensing/elastic-license |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| namespace Tests\Feature; |  | ||||||
| 
 |  | ||||||
| use App\Services\Email\EmailObject; |  | ||||||
| use App\Services\Email\EmailService; |  | ||||||
| use App\Utils\Traits\GeneratesCounter; |  | ||||||
| use App\Utils\Traits\MakesHash; |  | ||||||
| use Illuminate\Routing\Middleware\ThrottleRequests; |  | ||||||
| use Tests\MockAccountData; |  | ||||||
| use Tests\TestCase; |  | ||||||
| use Illuminate\Mail\Mailables\Address; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @test |  | ||||||
|  * @covers  App\Services\Email\EmailService |  | ||||||
|  */ |  | ||||||
| class EmailTest extends TestCase |  | ||||||
| { |  | ||||||
|     use MakesHash; |  | ||||||
|     use GeneratesCounter; |  | ||||||
|     use MockAccountData; |  | ||||||
| 
 |  | ||||||
|     public EmailService $email_service; |  | ||||||
| 
 |  | ||||||
|     public EmailObject $email_object; |  | ||||||
| 
 |  | ||||||
|     protected function setUp() :void |  | ||||||
|     { |  | ||||||
|         parent::setUp(); |  | ||||||
| 
 |  | ||||||
|         if(!class_exists(\Modules\Admin\Jobs\Account\EmailFilter::class)) |  | ||||||
|             $this->markTestSkipped('Skip test not needed in this environment'); |  | ||||||
| 
 |  | ||||||
|         $this->makeTestData(); |  | ||||||
| 
 |  | ||||||
|         $this->email_object = new EmailObject(); |  | ||||||
|         $this->email_object->to = [new Address("testing@gmail.com", "Cool Name")]; |  | ||||||
|         $this->email_object->attachments = []; |  | ||||||
|         $this->email_object->settings = $this->client->getMergedSettings(); |  | ||||||
|         $this->email_object->company = $this->client->company; |  | ||||||
|         $this->email_object->client = $this->client; |  | ||||||
|         $this->email_object->email_template_subject = 'email_subject_statement'; |  | ||||||
|         $this->email_object->email_template_body = 'email_template_statement'; |  | ||||||
|         $this->email_object->variables = [ |  | ||||||
|             '$client' => $this->client->present()->name(), |  | ||||||
|             '$start_date' => '2022-01-01', |  | ||||||
|             '$end_date' => '2023-01-01', |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         $this->email_service = new EmailService($this->email_object, $this->company); |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function testPreFlightChecksHosted() |  | ||||||
|     { |  | ||||||
|      |  | ||||||
|         config(['ninja.environment' => 'hosted']); |  | ||||||
|      |  | ||||||
|         $this->assertFalse($this->email_service->preFlightChecksFail()); |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function testPreFlightChecksSelfHost() |  | ||||||
|     { |  | ||||||
|      |  | ||||||
|         config(['ninja.environment' => 'selfhost']); |  | ||||||
|      |  | ||||||
|         $this->assertFalse($this->email_service->preFlightChecksFail()); |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -41,6 +41,18 @@ class ExpenseApiTest extends TestCase | |||||||
|         Model::reguard(); |         Model::reguard(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testExpenseGetClientStatus() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/expenses?client_status=paid'); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testExpensePost() |     public function testExpensePost() | ||||||
|     { |     { | ||||||
|         $data = [ |         $data = [ | ||||||
|  | |||||||
| @ -66,6 +66,8 @@ class ProductSalesReportTest extends TestCase | |||||||
| 
 | 
 | ||||||
|     public $account; |     public $account; | ||||||
| 
 | 
 | ||||||
|  |     public $client; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      *      start_date - Y-m-d |      *      start_date - Y-m-d | ||||||
|             end_date - Y-m-d |             end_date - Y-m-d | ||||||
| @ -108,6 +110,9 @@ class ProductSalesReportTest extends TestCase | |||||||
|             'settings' => $settings, |             'settings' => $settings, | ||||||
|         ]); |         ]); | ||||||
| 
 | 
 | ||||||
|  |         $this->company->settings = $settings; | ||||||
|  |         $this->company->save(); | ||||||
|  | 
 | ||||||
|         $this->payload = [ |         $this->payload = [ | ||||||
|             'start_date' => '2000-01-01', |             'start_date' => '2000-01-01', | ||||||
|             'end_date' => '2030-01-11', |             'end_date' => '2030-01-11', | ||||||
| @ -115,6 +120,13 @@ class ProductSalesReportTest extends TestCase | |||||||
|             'is_income_billed' => true, |             'is_income_billed' => true, | ||||||
|             'include_tax' => false, |             'include_tax' => false, | ||||||
|         ]; |         ]; | ||||||
|  | 
 | ||||||
|  |         $this->client = Client::factory()->create([ | ||||||
|  |             'user_id' => $this->user->id, | ||||||
|  |             'company_id' => $this->company->id, | ||||||
|  |             'is_deleted' => 0, | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function testProductSalesInstance() |     public function testProductSalesInstance() | ||||||
| @ -133,22 +145,16 @@ class ProductSalesReportTest extends TestCase | |||||||
|         $this->buildData(); |         $this->buildData(); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         $client = Client::factory()->create([ |  | ||||||
|             'user_id' => $this->user->id, |  | ||||||
|             'company_id' => $this->company->id, |  | ||||||
|             'is_deleted' => 0, |  | ||||||
|         ]); |  | ||||||
| 
 |  | ||||||
|         $this->payload = [ |         $this->payload = [ | ||||||
|             'start_date' => '2000-01-01', |             'start_date' => '2000-01-01', | ||||||
|             'end_date' => '2030-01-11', |             'end_date' => '2030-01-11', | ||||||
|             'date_range' => 'custom', |             'date_range' => 'custom', | ||||||
|             'client_id' => $client->id, |             'client_id' => $this->client->id, | ||||||
|             'report_keys' => [] |             'report_keys' => [] | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         $i = Invoice::factory()->create([ |         $i = Invoice::factory()->create([ | ||||||
|             'client_id' => $client->id, |             'client_id' => $this->client->id, | ||||||
|             'user_id' => $this->user->id, |             'user_id' => $this->user->id, | ||||||
|             'company_id' => $this->company->id, |             'company_id' => $this->company->id, | ||||||
|             'amount' => 0, |             'amount' => 0, | ||||||
| @ -174,7 +180,6 @@ class ProductSalesReportTest extends TestCase | |||||||
|         $response = $pl->run(); |         $response = $pl->run(); | ||||||
| 
 | 
 | ||||||
|         $this->assertIsString($response); |         $this->assertIsString($response); | ||||||
| // nlog($response);
 |  | ||||||
| 
 | 
 | ||||||
|         $this->account->delete(); |         $this->account->delete(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ use App\Models\Product; | |||||||
| use App\Models\TaxRate; | use App\Models\TaxRate; | ||||||
| use App\Models\Vendor; | use App\Models\Vendor; | ||||||
| use App\Utils\Traits\MakesHash; | use App\Utils\Traits\MakesHash; | ||||||
|  | use App\Utils\TruthSource; | ||||||
| use Illuminate\Routing\Middleware\ThrottleRequests; | use Illuminate\Routing\Middleware\ThrottleRequests; | ||||||
| use Illuminate\Support\Facades\Cache; | use Illuminate\Support\Facades\Cache; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| @ -50,6 +51,9 @@ class CsvImportTest extends TestCase | |||||||
|         $this->makeTestData(); |         $this->makeTestData(); | ||||||
| 
 | 
 | ||||||
|         $this->withoutExceptionHandling(); |         $this->withoutExceptionHandling(); | ||||||
|  | 
 | ||||||
|  |         auth()->login($this->user); | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function testExpenseCsvImport() |     public function testExpenseCsvImport() | ||||||
| @ -274,6 +278,11 @@ class CsvImportTest extends TestCase | |||||||
| 
 | 
 | ||||||
|         Cache::put($hash.'-invoice', base64_encode($csv), 360); |         Cache::put($hash.'-invoice', base64_encode($csv), 360); | ||||||
| 
 | 
 | ||||||
|  |         $truth = app()->make(TruthSource::class); | ||||||
|  |         $truth->setCompanyUser($this->cu); | ||||||
|  |         $truth->setUser($this->user); | ||||||
|  |         $truth->setCompany($this->company); | ||||||
|  | 
 | ||||||
|         $csv_importer = new Csv($data, $this->company); |         $csv_importer = new Csv($data, $this->company); | ||||||
| 
 | 
 | ||||||
|         $csv_importer->import('invoice'); |         $csv_importer->import('invoice'); | ||||||
|  | |||||||
| @ -40,6 +40,9 @@ class InvitationTest extends TestCase | |||||||
|     protected function setUp() :void |     protected function setUp() :void | ||||||
|     { |     { | ||||||
|         parent::setUp(); |         parent::setUp(); | ||||||
|  | 
 | ||||||
|  |         $this->faker = \Faker\Factory::create(); | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function testInvoiceCreationAfterInvoiceMarkedSent() |     public function testInvoiceCreationAfterInvoiceMarkedSent() | ||||||
| @ -52,10 +55,13 @@ class InvitationTest extends TestCase | |||||||
|         $account->default_company_id = $company->id; |         $account->default_company_id = $company->id; | ||||||
|         $account->save(); |         $account->save(); | ||||||
| 
 | 
 | ||||||
|         $user = User::where('email', 'user@example.com')->first(); |         $fake_email = $this->faker->email(); | ||||||
|  | 
 | ||||||
|  |         $user = User::where('email', $fake_email)->first(); | ||||||
| 
 | 
 | ||||||
|         if (! $user) { |         if (! $user) { | ||||||
|             $user = User::factory()->create([ |             $user = User::factory()->create([ | ||||||
|  |                 'email' => $fake_email, | ||||||
|                 'account_id' => $account->id, |                 'account_id' => $account->id, | ||||||
|                 'confirmation_code' => $this->createDbHash(config('database.default')), |                 'confirmation_code' => $this->createDbHash(config('database.default')), | ||||||
|             ]); |             ]); | ||||||
|  | |||||||
| @ -47,6 +47,16 @@ class InvoiceTest extends TestCase | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |     public function testInvoiceGetPaidInvoices() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/invoices?client_status=paid',) | ||||||
|  |         ->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testInvoiceArchiveAction() |     public function testInvoiceArchiveAction() | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -48,6 +48,17 @@ class PaymentTermsApiTest extends TestCase | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testPaymentTermsGetWithFilter() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/payment_terms?filter=hey'); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     public function testPaymentTermsGet() |     public function testPaymentTermsGet() | ||||||
|     { |     { | ||||||
|         $response = $this->withHeaders([ |         $response = $this->withHeaders([ | ||||||
|  | |||||||
| @ -62,6 +62,18 @@ class PaymentTest extends TestCase | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testGetPaymentMatchList() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/payments?match_transactions=true') | ||||||
|  |           ->assertStatus(200); | ||||||
|  | 
 | ||||||
|  |          | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testStorePaymentIdempotencyKeyIllegalLength() |     public function testStorePaymentIdempotencyKeyIllegalLength() | ||||||
|     { |     { | ||||||
|         $client = ClientFactory::create($this->company->id, $this->user->id); |         $client = ClientFactory::create($this->company->id, $this->user->id); | ||||||
|  | |||||||
| @ -47,6 +47,15 @@ class ProductTest extends TestCase | |||||||
|         $this->makeTestData(); |         $this->makeTestData(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testProductGetProductKeyFilter() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/products?product_key=xx') | ||||||
|  |         ->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testProductList() |     public function testProductList() | ||||||
|     { |     { | ||||||
|         $response = $this->withHeaders([ |         $response = $this->withHeaders([ | ||||||
|  | |||||||
| @ -42,6 +42,16 @@ class ProjectApiTest extends TestCase | |||||||
|         Model::reguard(); |         Model::reguard(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testProjectGetFilter() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/projects?filter=xx'); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testProjectGet() |     public function testProjectGet() | ||||||
|     { |     { | ||||||
|         $response = $this->withHeaders([ |         $response = $this->withHeaders([ | ||||||
|  | |||||||
| @ -40,6 +40,16 @@ class PurchaseOrderTest extends TestCase | |||||||
|         $this->makeTestData(); |         $this->makeTestData(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testPurchaseOrderGetWithClientStatus() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/purchase_orders?client_status=sent'.$this->encodePrimaryKey($this->purchase_order->id)); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testPostNewPurchaseOrderPdf() |     public function testPostNewPurchaseOrderPdf() | ||||||
|     { |     { | ||||||
|         $purchase_order = [ |         $purchase_order = [ | ||||||
|  | |||||||
| @ -50,6 +50,15 @@ class QuoteTest extends TestCase | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testQuoteListApproved() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/quotes?client_status=approved'); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     public function testQuoteConvertToProject() |     public function testQuoteConvertToProject() | ||||||
|  | |||||||
| @ -43,6 +43,16 @@ class RecurringExpenseApiTest extends TestCase | |||||||
|         Model::reguard(); |         Model::reguard(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testRecurringExpenseGetFiltered() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/recurring_expenses?filter=xx'); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testRecurringExpenseGet() |     public function testRecurringExpenseGet() | ||||||
|     { |     { | ||||||
|         $response = $this->withHeaders([ |         $response = $this->withHeaders([ | ||||||
|  | |||||||
| @ -52,6 +52,17 @@ class RecurringInvoiceTest extends TestCase | |||||||
|         $this->makeTestData(); |         $this->makeTestData(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testRecurringGetStatus() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/recurring_invoices?client_status=active') | ||||||
|  |           ->assertStatus(200); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     public function testPostRecurringInvoiceWithPlaceholderVariables() |     public function testPostRecurringInvoiceWithPlaceholderVariables() | ||||||
|     { |     { | ||||||
|         $line_items = []; |         $line_items = []; | ||||||
|  | |||||||
| @ -47,6 +47,17 @@ class RecurringQuoteTest extends TestCase | |||||||
|         $this->makeTestData(); |         $this->makeTestData(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testRecurringQuoteListFilter() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/recurring_quotes?filter=xx'); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testRecurringQuoteList() |     public function testRecurringQuoteList() | ||||||
|     { |     { | ||||||
|         RecurringQuote::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]); |         RecurringQuote::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]); | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ namespace Tests\Feature\Scheduler; | |||||||
| use App\Factory\SchedulerFactory; | use App\Factory\SchedulerFactory; | ||||||
| use App\Models\Client; | use App\Models\Client; | ||||||
| use App\Models\RecurringInvoice; | use App\Models\RecurringInvoice; | ||||||
|  | use App\Models\Scheduler; | ||||||
| use App\Services\Scheduler\SchedulerService; | use App\Services\Scheduler\SchedulerService; | ||||||
| use App\Utils\Traits\MakesHash; | use App\Utils\Traits\MakesHash; | ||||||
| use Carbon\Carbon; | use Carbon\Carbon; | ||||||
| @ -53,6 +54,72 @@ class SchedulerTest extends TestCase | |||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testClientCountResolution() | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         $c = Client::factory()->create([ | ||||||
|  |             'company_id' => $this->company->id, | ||||||
|  |             'user_id' => $this->user->id, | ||||||
|  |             'number' => rand(1000,100000), | ||||||
|  |             'name' => 'A fancy client' | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |         $c2 = Client::factory()->create([ | ||||||
|  |             'company_id' => $this->company->id, | ||||||
|  |             'user_id' => $this->user->id, | ||||||
|  |             'number' => rand(1000,100000), | ||||||
|  |             'name' => 'A fancy client' | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |         $data = [ | ||||||
|  |             'name' => 'A test statement scheduler', | ||||||
|  |             'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY, | ||||||
|  |             'next_run' => now()->format('Y-m-d'), | ||||||
|  |             'template' => 'client_statement', | ||||||
|  |             'parameters' => [ | ||||||
|  |                 'date_range' => 'previous_month', | ||||||
|  |                 'show_payments_table' => true, | ||||||
|  |                 'show_aging_table' => true, | ||||||
|  |                 'status' => 'paid', | ||||||
|  |                 'clients' => [ | ||||||
|  |                     $c2->hashed_id,  | ||||||
|  |                     $c->hashed_id | ||||||
|  |                 ], | ||||||
|  |             ], | ||||||
|  |         ]; | ||||||
|  | 
 | ||||||
|  |         $response = false; | ||||||
|  | 
 | ||||||
|  |         try{ | ||||||
|  |             $response = $this->withHeaders([ | ||||||
|  |                 'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |                 'X-API-TOKEN' => $this->token, | ||||||
|  |             ])->postJson('/api/v1/task_schedulers', $data); | ||||||
|  | 
 | ||||||
|  |         } catch (ValidationException $e) { | ||||||
|  |             $message = json_decode($e->validator->getMessageBag(), 1); | ||||||
|  |             nlog($message); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  | 
 | ||||||
|  |         $data = $response->json(); | ||||||
|  | 
 | ||||||
|  |         $scheduler = Scheduler::find($this->decodePrimaryKey($data['data']['id'])); | ||||||
|  | 
 | ||||||
|  |         $this->assertInstanceOf(Scheduler::class, $scheduler); | ||||||
|  | 
 | ||||||
|  |         $this->assertCount(2, $scheduler->parameters['clients']); | ||||||
|  | 
 | ||||||
|  |         $q = Client::query() | ||||||
|  |               ->where('company_id', $scheduler->company_id) | ||||||
|  |               ->whereIn('id', $this->transformKeys($scheduler->parameters['clients'])) | ||||||
|  |               ->cursor(); | ||||||
|  | 
 | ||||||
|  |         $this->assertCount(2, $q); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testClientsValidationInScheduledTask() |     public function testClientsValidationInScheduledTask() | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
| @ -162,7 +229,7 @@ class SchedulerTest extends TestCase | |||||||
|         $data = [ |         $data = [ | ||||||
|             'name' => 'A test statement scheduler', |             'name' => 'A test statement scheduler', | ||||||
|             'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY, |             'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY, | ||||||
|             'next_run' => "2023-01-01", |             'next_run' => now()->format('Y-m-d'), | ||||||
|             'template' => 'client_statement', |             'template' => 'client_statement', | ||||||
|             'parameters' => [ |             'parameters' => [ | ||||||
|                 'date_range' => 'previous_month', |                 'date_range' => 'previous_month', | ||||||
| @ -184,7 +251,7 @@ class SchedulerTest extends TestCase | |||||||
| 
 | 
 | ||||||
|         $scheduler->fresh(); |         $scheduler->fresh(); | ||||||
| 
 | 
 | ||||||
|         $this->assertEquals("2023-02-01", $scheduler->next_run->format('Y-m-d')); |         $this->assertEquals(now()->addMonth()->format('Y-m-d'), $scheduler->next_run->format('Y-m-d')); | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -50,6 +50,17 @@ class SubscriptionApiTest extends TestCase | |||||||
|         Model::reguard(); |         Model::reguard(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testSubscriptionFilter() | ||||||
|  |     { | ||||||
|  |          | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/subscriptions?filter=xx') | ||||||
|  |           ->assertStatus(200); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testSubscriptionsGet() |     public function testSubscriptionsGet() | ||||||
|     { |     { | ||||||
|         $product = Product::factory()->create([ |         $product = Product::factory()->create([ | ||||||
|  | |||||||
| @ -34,6 +34,18 @@ class SystemLogApiTest extends TestCase | |||||||
|         $this->makeTestData(); |         $this->makeTestData(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     public function testFilters() | ||||||
|  |     { | ||||||
|  |          | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/system_logs?type_id=3') | ||||||
|  |         ->assertStatus(200);; | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testSystemLogRoutes() |     public function testSystemLogRoutes() | ||||||
|     { |     { | ||||||
|         $sl = [ |         $sl = [ | ||||||
|  | |||||||
| @ -44,6 +44,17 @@ class TaskApiTest extends TestCase | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     public function testTaskListClientStatus() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/tasks?client_status=invoiced') | ||||||
|  |           ->assertStatus(200); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testTaskLockingGate() |     public function testTaskLockingGate() | ||||||
|     { |     { | ||||||
|         $data = [ |         $data = [ | ||||||
|  | |||||||
| @ -41,6 +41,16 @@ class TaskStatusApiTest extends TestCase | |||||||
|         Model::reguard(); |         Model::reguard(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testTaskStatusGetFilter() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/task_statuses?filter=xx'); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testTaskStatusPost() |     public function testTaskStatusPost() | ||||||
|     { |     { | ||||||
|         $data = [ |         $data = [ | ||||||
|  | |||||||
| @ -42,6 +42,16 @@ class TaxRateApiTest extends TestCase | |||||||
|         Model::reguard(); |         Model::reguard(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function testTaxRatesGetFilter() | ||||||
|  |     { | ||||||
|  |         $response = $this->withHeaders([ | ||||||
|  |             'X-API-SECRET' => config('ninja.api_secret'), | ||||||
|  |             'X-API-TOKEN' => $this->token, | ||||||
|  |         ])->get('/api/v1/tax_rates?filter=gst'); | ||||||
|  | 
 | ||||||
|  |         $response->assertStatus(200); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function testTaxRatePost() |     public function testTaxRatePost() | ||||||
|     { |     { | ||||||
|         $rate_name = $this->faker->firstName(); |         $rate_name = $this->faker->firstName(); | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user