diff --git a/composer.json b/composer.json index 6e2eec268..b52a58582 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,9 @@ "ralouphie/getallheaders": "^2.0", "smarty/smarty": "2.6.30", "pdepend/pdepend": "@stable", - "chumper/zipper": "^1.0" + "chumper/zipper": "^1.0", + "nikic/php-parser": "3.1.5", + "laravel/tinker": "^1.0" }, "require-dev": { "fzaninotto/faker": "^1.7", diff --git a/composer.lock b/composer.lock index 527736ee1..510c23ba6 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3242f53453d9e9a3d7fdf3a56961ae40", + "content-hash": "a9ba65f7fb68be7c36dd45b62216b2c6", "packages": [ { "name": "bshaffer/oauth2-server-php", @@ -209,6 +209,39 @@ ], "time": "2018-03-09T06:07:41+00:00" }, + { + "name": "dnoegel/php-xdg-base-dir", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "@stable" + }, + "type": "project", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "time": "2014-10-24T07:27:01+00:00" + }, { "name": "doctrine/inflector", "version": "v1.1.0", @@ -405,6 +438,94 @@ ], "time": "2015-10-16T22:11:08+00:00" }, + { + "name": "jakub-onderka/php-console-color", + "version": "v0.2", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "1.0", + "jakub-onderka/php-parallel-lint": "1.0", + "jakub-onderka/php-var-dump-check": "0.*", + "phpunit/phpunit": "~4.3", + "squizlabs/php_codesniffer": "1.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "JakubOnderka\\PhpConsoleColor\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "jakub.onderka@gmail.com" + } + ], + "time": "2018-09-29T17:23:10+00:00" + }, + { + "name": "jakub-onderka/php-console-highlighter", + "version": "v0.4", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", + "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/9f7a229a69d52506914b4bc61bfdb199d90c5547", + "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "jakub-onderka/php-console-color": "~0.2", + "php": ">=5.4.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "~1.0", + "jakub-onderka/php-parallel-lint": "~1.0", + "jakub-onderka/php-var-dump-check": "~0.1", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "JakubOnderka\\PhpConsoleHighlighter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "acci@acci.cz", + "homepage": "http://www.acci.cz/" + } + ], + "description": "Highlight PHP code in terminal", + "time": "2018-09-29T18:48:56+00:00" + }, { "name": "laravel/framework", "version": "v5.4.36", @@ -534,6 +655,69 @@ ], "time": "2017-08-30T09:26:16+00:00" }, + { + "name": "laravel/tinker", + "version": "v1.0.8", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "cafbf598a90acde68985660e79b2b03c5609a405" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/cafbf598a90acde68985660e79b2b03c5609a405", + "reference": "cafbf598a90acde68985660e79b2b03c5609a405", + "shasum": "" + }, + "require": { + "illuminate/console": "~5.1", + "illuminate/contracts": "~5.1", + "illuminate/support": "~5.1", + "php": ">=5.5.9", + "psy/psysh": "0.7.*|0.8.*|0.9.*", + "symfony/var-dumper": "~3.0|~4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (~5.1)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", + "keywords": [ + "REPL", + "Tinker", + "laravel", + "psysh" + ], + "time": "2018-10-12T19:39:35+00:00" + }, { "name": "league/flysystem", "version": "1.0.49", @@ -923,6 +1107,57 @@ ], "time": "2018-11-22T18:23:02+00:00" }, + { + "name": "nikic/php-parser", + "version": "v3.1.5", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", + "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2018-02-28T20:30:58+00:00" + }, { "name": "paragonie/random_compat", "version": "v2.0.17", @@ -1364,6 +1599,80 @@ ], "time": "2012-12-21T11:40:51+00:00" }, + { + "name": "psy/psysh", + "version": "v0.9.9", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "9aaf29575bb8293206bb0420c1e1c87ff2ffa94e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/9aaf29575bb8293206bb0420c1e1c87ff2ffa94e", + "reference": "9aaf29575bb8293206bb0420c1e1c87ff2ffa94e", + "shasum": "" + }, + "require": { + "dnoegel/php-xdg-base-dir": "0.1", + "ext-json": "*", + "ext-tokenizer": "*", + "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*", + "nikic/php-parser": "~1.3|~2.0|~3.0|~4.0", + "php": ">=5.4.0", + "symfony/console": "~2.3.10|^2.4.2|~3.0|~4.0", + "symfony/var-dumper": "~2.7|~3.0|~4.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "hoa/console": "~2.15|~3.16", + "phpunit/phpunit": "~4.8.35|~5.0|~6.0|~7.0" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.", + "hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.9.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "time": "2018-10-13T15:16:03+00:00" + }, { "name": "ralouphie/getallheaders", "version": "2.0.5", @@ -4883,6 +5192,7 @@ "mock", "xunit" ], + "abandoned": true, "time": "2017-06-30T09:13:00+00:00" }, { @@ -5823,6 +6133,7 @@ "phpcs", "standards" ], + "abandoned": "phpcompatibility/php-compatibility", "time": "2018-10-07T17:38:02+00:00" } ], diff --git a/config/app.php b/config/app.php index fad6a83a2..651ebfc6a 100644 --- a/config/app.php +++ b/config/app.php @@ -21,7 +21,7 @@ return [ Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class, - + Laravel\Tinker\TinkerServiceProvider::class, ], 'aliases' => [ diff --git a/database/factories/ApplicationFactory.php b/database/factories/ApplicationFactory.php new file mode 100644 index 000000000..76728224a --- /dev/null +++ b/database/factories/ApplicationFactory.php @@ -0,0 +1,26 @@ +define(\ProcessMaker\Model\Application::class, function(Faker $faker) { + $process = \ProcessMaker\Model\Process::all()->random(); + $statuses = ['DRAFT', 'TO_DO']; + $status = $faker->randomElement($statuses); + $statusId = array_search($status, $statuses) + 1; + return [ + 'APP_UID' => G::generateUniqueID(), + 'APP_TITLE' => G::generateUniqueID(), + 'APP_NUMBER' => $faker->unique()->numberBetween(1000), + 'APP_STATUS' => $status, + 'APP_STATUS_ID' => $statusId, + 'PRO_UID' => $process->PRO_UID, + 'APP_PARALLEL' => 'N', + 'APP_INIT_USER' => \ProcessMaker\Model\User::all()->random()->USR_UID, + 'APP_CUR_USER' => \ProcessMaker\Model\User::all()->random()->USR_UID, + 'APP_PIN' => G::generateUniqueID(), + 'APP_CREATE_DATE' => $faker->dateTime(), + 'APP_UPDATE_DATE' => $faker->dateTime(), + 'APP_INIT_DATE' => $faker->dateTime(), + 'APP_DATA' => serialize(['APP_NUMBER' => 12]) + ]; +}); \ No newline at end of file diff --git a/database/factories/DelegationFactory.php b/database/factories/DelegationFactory.php new file mode 100644 index 000000000..e5917a414 --- /dev/null +++ b/database/factories/DelegationFactory.php @@ -0,0 +1,38 @@ +define(\ProcessMaker\Model\Delegation::class, function(Faker $faker) { + $app = factory(\ProcessMaker\Model\Application::class)->create(); + $process = \ProcessMaker\Model\Process::where('PRO_UID', $app->PRO_UID)->first(); + $task = $process->tasks->first(); + + // Grab a user if random + $users = \ProcessMaker\Model\User::all(); + if(!count($users)) { + $user = factory(\ProcessMaker\Model\User::class)->create(); + } else{ + $user = $users->random(); + } + return [ + 'APP_UID' => $app->APP_UID, + 'DEL_INDEX' => 1, + 'APP_NUMBER' => $app->APP_NUMBER, + 'DEL_PREVIOUS' => 0, + 'PRO_UID' => $app->PRO_UID, + 'TAS_UID' => $task->TAS_UID, + 'USR_UID' => $user->USR_UID, + 'DEL_TYPE' => 'NORMAL', + 'DEL_THREAD' => 1, + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_PRIORITY' => 3, + 'DEL_DELEGATE_DATE' => $faker->dateTime(), + 'DEL_INIT_DATE' => $faker->dateTime(), + 'DEL_TASK_DUE_DATE' => $faker->dateTime(), + 'DEL_RISK_DATE' => $faker->dateTime(), + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process->PRO_ID, + 'TAS_ID' => $task->TAS_ID, + 'DEL_DATA' => '' + ]; +}); \ No newline at end of file diff --git a/database/factories/ProcessCategoryFactory.php b/database/factories/ProcessCategoryFactory.php new file mode 100644 index 000000000..0f8f19776 --- /dev/null +++ b/database/factories/ProcessCategoryFactory.php @@ -0,0 +1,14 @@ +define(\ProcessMaker\Model\ProcessCategory::class, function (Faker $faker) { + return [ + 'CATEGORY_UID' => G::generateUniqueID(), + 'CATEGORY_PARENT' => '', + 'CATEGORY_NAME' => $faker->sentence(5), + 'CATEGORY_ICON' => '', + ]; +}); diff --git a/database/factories/ProcessFactory.php b/database/factories/ProcessFactory.php index d8a60d371..40ae93dc3 100644 --- a/database/factories/ProcessFactory.php +++ b/database/factories/ProcessFactory.php @@ -5,13 +5,56 @@ use Faker\Generator as Faker; $factory->define(\ProcessMaker\Model\Process::class, function(Faker $faker) { - /** * @todo Determine if we need more base columns populated */ - return [ + $process = [ 'PRO_UID' => G::generateUniqueID(), 'PRO_TITLE' => $faker->sentence(3), - 'PRO_DESCRIPTION' => $faker->paragraph(3) + 'PRO_DESCRIPTION' => $faker->paragraph(3), + 'PRO_CREATE_USER' => '00000000000000000000000000000001', + 'PRO_DYNAFORMS' => '', + 'PRO_ITEE' => 1, ]; + + $task1 = factory(\ProcessMaker\Model\Task::class) + ->create([ + 'PRO_UID' => $process['PRO_UID'], + 'TAS_START'=>'TRUE' + ]); + + $task2 = factory(\ProcessMaker\Model\Task::class) + ->create([ + 'PRO_UID' => $process['PRO_UID'], + ]); + + //routes + factory(\ProcessMaker\Model\Route::class) + ->create([ + 'PRO_UID' => $process['PRO_UID'], + 'TAS_UID' => $task2['TAS_UID'], + 'ROU_NEXT_TASK' => '-1', + ]); + + factory(\ProcessMaker\Model\Route::class) + ->create([ + 'PRO_UID' => $process['PRO_UID'], + 'TAS_UID' => $task1['TAS_UID'], + 'ROU_NEXT_TASK' => $task2['TAS_UID'] + ]); + + //User assignments + factory(\ProcessMaker\Model\TaskUser::class) + ->create([ + 'TAS_UID' => $task1['TAS_UID'], + 'USR_UID' => \ProcessMaker\Model\User::all()->random()->USR_UID + ]); + + factory(\ProcessMaker\Model\TaskUser::class) + ->create([ + 'TAS_UID' => $task2['TAS_UID'], + 'USR_UID' => \ProcessMaker\Model\User::all()->random()->USR_UID + ]); + + return $process; }); \ No newline at end of file diff --git a/database/factories/RouteFactory.php b/database/factories/RouteFactory.php new file mode 100644 index 000000000..18a3e2f57 --- /dev/null +++ b/database/factories/RouteFactory.php @@ -0,0 +1,22 @@ +define(\ProcessMaker\Model\Route::class, function(Faker $faker) { + return [ + 'PRO_UID' => function() { + $process = factory(\ProcessMaker\Model\Process::class)->create(); + return $process->PRO_UID; + }, + 'TAS_UID' => function() { + $task = factory(\ProcessMaker\Model\Task::class)->create(); + return $task->TAS_UID; + }, + 'ROU_UID' => G::generateUniqueID(), + 'ROU_PARENT' => 0, + 'ROU_CASE' => 1, + 'ROU_TYPE' => 'SEQUENTIAL' + ]; +}); \ No newline at end of file diff --git a/database/factories/TaskFactory.php b/database/factories/TaskFactory.php new file mode 100644 index 000000000..41f1167a9 --- /dev/null +++ b/database/factories/TaskFactory.php @@ -0,0 +1,33 @@ +define(\ProcessMaker\Model\Task::class, function(Faker $faker) { + return [ + 'PRO_UID' => function() { + $process = factory(\ProcessMaker\Model\Process::class)->create(); + return $process->PRO_UID; + }, + 'TAS_UID' => G::generateUniqueID(), + 'TAS_TITLE' => $faker->sentence(2), + 'TAS_TYPE' => 'NORMAL', + 'TAS_TYPE_DAY' => 1, + 'TAS_DURATION' => 1, + 'TAS_ASSIGN_TYPE' => 'BALANCED', + 'TAS_ASSIGN_VARIABLE' => '@@SYS_NEXT_USER_TO_BE_ASSIGNED', + 'TAS_MI_INSTANCE_VARIABLE' => '@@SYS_VAR_TOTAL_INSTANCE', + 'TAS_MI_COMPLETE_VARIABLE' => '@@SYS_VAR_TOTAL_INSTANCES_COMPLETE', + 'TAS_ASSIGN_LOCATION' => 'FALSE', + 'TAS_ASSIGN_LOCATION_ADHOC' => 'FALSE', + 'TAS_TRANSFER_FLY' => 'FALSE', + 'TAS_LAST_ASSIGNED' => 0, + 'TAS_USER' => 0, + 'TAS_CAN_UPLOAD' => 'FALSE', + 'TAS_CAN_CANCEL' => 'FALSE', + 'TAS_OWNER_APP' => 'FALSE', + 'TAS_CAN_SEND_MESSAGE' => 'FALSE', + 'TAS_SEND_LAST_EMAIL' => 'FALSE', + ]; +}); \ No newline at end of file diff --git a/database/factories/TaskUserFactory.php b/database/factories/TaskUserFactory.php new file mode 100644 index 000000000..a4c0a5e7d --- /dev/null +++ b/database/factories/TaskUserFactory.php @@ -0,0 +1,16 @@ +define(\ProcessMaker\Model\TaskUser::class, function(Faker $faker) { + return [ + 'TAS_UID' => function() { + $task = factory(\ProcessMaker\Model\Task::class)->create(); + return $task->TAS_UID; + }, + 'TU_TYPE' => 1, + 'TU_RELATION' => 1 + ]; +}); \ No newline at end of file diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php new file mode 100644 index 000000000..1885c421e --- /dev/null +++ b/database/factories/UserFactory.php @@ -0,0 +1,19 @@ +define(\ProcessMaker\Model\User::class, function(Faker $faker) { + return [ + 'USR_UID' => G::generateUniqueID(), + 'USR_USERNAME' => $faker->unique()->userName, + 'USR_PASSWORD' => $faker->password, + 'USR_FIRSTNAME' => $faker->firstName, + 'USR_LASTNAME' => $faker->lastName, + 'USR_EMAIL' => $faker->unique()->email, + 'USR_DUE_DATE' => new \Carbon\Carbon(2030,1,1), + 'USR_STATUS' => 'ACTIVE', + 'USR_ROLE' => $faker->randomElement(['PROCESSMAKER_ADMIN', 'PROCESSMAKER_OPERATOR']), + 'USR_UX' => 'NORMAL', + 'USR_TIME_ZONE' => 'America/Anguilla', + 'USR_DEFAULT_LANG' => 'en', + ]; +}); \ No newline at end of file diff --git a/tests/unit/workflow/engine/src/ProcessMaker/Model/DelegationTest.php b/tests/unit/workflow/engine/src/ProcessMaker/Model/DelegationTest.php new file mode 100644 index 000000000..a584902b4 --- /dev/null +++ b/tests/unit/workflow/engine/src/ProcessMaker/Model/DelegationTest.php @@ -0,0 +1,1031 @@ +create(); + factory(Process::class, 10)->create(); + factory(Delegation::class, 51)->create(); + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure pagination is working properly + * @test + */ + public function it_should_return_pages_of_data_unassigned() + { + factory(User::class, 100)->create(); + factory(Process::class, 10)->create(); + + factory(Delegation::class, 50)->create(); + factory(Delegation::class, 1)->create([ + 'USR_ID' => 0 // A self service delegation + ]); + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure filter by process is working properly + * @test + */ + public function it_should_return_process_of_data() + { + factory(User::class, 100)->create(); + $process = factory(Process::class, 1)->create([ + 'PRO_ID' => 1 + ]); + factory(Delegation::class, 51)->create([ + 'PRO_ID' => $process[0]->id + ]); + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, $process[0]->id); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, $process[0]->id); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, $process[0]->id); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure filter by status is working properly + * Review status filter by a specific status, such as Draft + * @test + */ + public function it_should_return_status_draft_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_STATUS_ID' => 1, + 'APP_STATUS' => 'DRAFT' + ]); + factory(Delegation::class, 51)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Review the filter by status DRAFT + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure filter by status is working properly + * Review status filter by a specific status, such as To Do + * @test + */ + public function it_should_return_status_todo_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_STATUS_ID' => 2, + 'APP_STATUS' => 'TO_DO' + ]); + factory(Delegation::class, 51)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Review the filter by status TO_DO + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure filter by status is working properly + * Review status filter by a specific status, such as Completed + * @test + */ + public function it_should_return_status_completed_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_STATUS_ID' => 3, + 'APP_STATUS' => 'COMPLETED', + ]); + + factory(Delegation::class, 51)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_LAST_INDEX' => 1 + ]); + // Review the filter by status COMPLETED + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure filter by status is working properly + * Review status filter by a specific status, such as Cancelled + * @test + */ + public function it_should_return_status_cancelled_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_STATUS_ID' => 4, + 'APP_STATUS' => 'CANCELLED' + ]); + + factory(Delegation::class, 51)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_LAST_INDEX' => 1 + ]); + // Review the filter by status CANCELLED + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(1, $results['data']); + } + + /** + * This ensures searching for a valid user works + * @test + */ + public function it_should_return_one_result_for_specified_user() + { + factory(User::class, 100)->create(); + factory(Process::class, 10)->create(); + // Create our unique user, with a unique username + $user = factory(User::class)->create([ + 'USR_USERNAME' => 'testcaseuser' + ]); + // Create a new delegation, but for this specific user + factory(Delegation::class)->create([ + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->id + ]); + // Now fetch results, and assume delegation count is 1 and the user points to our user + $results = Delegation::search($user->id); + $this->assertCount(1, $results['data']); + $this->assertEquals('testcaseuser', $results['data'][0]['USRCR_USR_USERNAME']); + } + + /** + * This ensures searching by case number and review the page + * @test + */ + public function it_should_search_by_case_id_and_pages_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2010 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2011 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2012 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2013 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2014 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2015 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Get first page, the major case id + $results = Delegation::search(null, 0, 10, 1, null, null, 'DESC', + 'APP_NUMBER', null, null, null, 'APP_NUMBER'); + $this->assertCount(7, $results['data']); + $this->assertEquals(2015, $results['data'][0]['APP_NUMBER']); + // Get first page, the minor case id + $results = Delegation::search(null, 0, 10, 1, null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_NUMBER'); + $this->assertCount(7, $results['data']); + $this->assertEquals(2001, $results['data'][0]['APP_NUMBER']); + //Check the pagination + $results = Delegation::search(null, 0, 5, 1, null, null, 'DESC', + 'APP_NUMBER', null, null, null, 'APP_NUMBER'); + $this->assertCount(5, $results['data']); + $results = Delegation::search(null, 5, 2, 1, null, null, 'DESC', + 'APP_NUMBER', null, null, null, 'APP_NUMBER'); + $this->assertCount(2, $results['data']); + } + + /** + * This ensures searching by case title and review the page + * case title contain the case number, ex: APP_TITLE = 'Request # @=APP_NUMBER' + * @test + */ + public function it_should_search_by_case_title_and_pages_of_data_app_number_matches_case_title() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3001, + 'APP_TITLE' => 'Request # 3001' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3010, + 'APP_TITLE' => 'Request # 3010' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3011, + 'APP_TITLE' => 'Request # 3011' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3012, + 'APP_TITLE' => 'Request # 3012' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3013, + 'APP_TITLE' => 'Request # 3013' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_TITLE' => 3014, + 'APP_TITLE' => 'Request # 3014' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + + // Get first page, the major case id + $results = Delegation::search(null, 0, 10, '1', null, null, 'DESC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(6, $results['data']); + $this->assertEquals('Request # 3014', $results['data'][0]['APP_TITLE']); + + // Get first page, the minor case id + $results = Delegation::search(null, 0, 10, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(6, $results['data']); + $this->assertEquals(3001, $results['data'][0]['APP_NUMBER']); + $this->assertEquals('Request # 3001', $results['data'][0]['APP_TITLE']); + //Check the pagination + $results = Delegation::search(null, 0, 5, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(5, $results['data']); + $results = Delegation::search(null, 5, 2, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(1, $results['data']); + } + + /** + * This ensures searching by task title and review the page + * @test + */ + public function it_should_search_by_task_title_and_pages_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $task = factory(Task::class, 1)->create([ + 'TAS_ID' => 1, + 'TAS_TITLE' => 'Request task' + ]); + factory(Delegation::class, 5)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + $task = factory(Task::class, 1)->create([ + 'TAS_ID' => 2, + 'TAS_TITLE' => 'Account task' + ]); + factory(Delegation::class, 5)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + // Get first page, the order taskTitle + $results = Delegation::search(null, 0, 6, 'task', null, null, 'ASC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertCount(6, $results['data']); + $this->assertEquals('Account task', $results['data'][0]['APP_TAS_TITLE']); + $results = Delegation::search(null, 6, 6, 'task', null, null, 'ASC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertEquals('Request task', $results['data'][0]['APP_TAS_TITLE']); + + // Get first page, the order taskTitle + $results = Delegation::search(null, 0, 6, 'task', null, null, 'DESC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertCount(6, $results['data']); + $this->assertEquals('Request task', $results['data'][0]['APP_TAS_TITLE']); + $results = Delegation::search(null, 6, 6, 'task', null, null, 'DESC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertEquals('Account task', $results['data'][0]['APP_TAS_TITLE']); + //Check the pagination + $results = Delegation::search(null, 0, 6, 'task', null, null, 'DESC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertCount(6, $results['data']); + $results = Delegation::search(null, 6, 6, 'task', null, null, 'DESC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertCount(4, $results['data']); + } + + /** + * This ensures searching by case title and review the page + * case title does not match with case number (hertland use case) + * @test + */ + public function it_should_search_by_case_title_and_pages_of_data_app_number_no_matches_case_title() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_TITLE' => 'Request from Abigail check nro 25001' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2010, + 'APP_TITLE' => 'Request from Abigail check nro 12' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2011, + 'APP_TITLE' => 'Request from Abigail check nro 1000' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2012, + 'APP_TITLE' => 'Request from Abigail check nro 11000' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2013, + 'APP_TITLE' => 'Request from Abigail check nro 12000' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_TITLE' => 2014, + 'APP_TITLE' => 'Request from Abigail check nro 111' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Get first page, the major case title + $results = Delegation::search(null, 0, 10, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(6, $results['data']); + $this->assertEquals(2001, $results['data'][0]['APP_NUMBER']); + $this->assertEquals('Request from Abigail check nro 25001', $results['data'][0]['APP_TITLE']); + + //Check the pagination + $results = Delegation::search(null, 0, 5, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(5, $results['data']); + $results = Delegation::search(null, 5, 2, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(1, $results['data']); + } + + /** + * This ensures ordering ascending and descending works by case number APP_NUMBER + * @test + */ + public function it_should_sort_by_case_id() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 30002 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Get first page, the minor case id + $results = Delegation::search(null, 0, 25, null, null, null, 'ASC', 'APP_NUMBER'); + $this->assertCount(2, $results['data']); + $this->assertEquals(2001, $results['data'][0]['APP_NUMBER']); + $this->assertEquals(30002, $results['data'][1]['APP_NUMBER']); + // Get first page, the major case id + $results = Delegation::search(null, 0, 25, null, null, null, 'DESC', 'APP_NUMBER'); + $this->assertCount(2, $results['data']); + $this->assertEquals(30002, $results['data'][0]['APP_NUMBER']); + $this->assertEquals(2001, $results['data'][1]['APP_NUMBER']); + } + + /** + * This ensures ordering ascending and descending works by case title APP_TITLE + * @test + */ + public function it_should_sort_by_case_title() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_TITLE' => 'Request by Thomas' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 30002, + 'APP_TITLE' => 'Request by Ariel' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Get first page, the minor case id + $results = Delegation::search(null, 0, 25, null, null, null, 'ASC', 'APP_TITLE'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Request by Ariel', $results['data'][0]['APP_TITLE']); + $this->assertEquals('Request by Thomas', $results['data'][1]['APP_TITLE']); + // Get first page, the major case id + $results = Delegation::search(null, 0, 25, null, null, null, 'DESC', 'APP_TITLE'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Request by Thomas', $results['data'][0]['APP_TITLE']); + $this->assertEquals('Request by Ariel', $results['data'][1]['APP_TITLE']); + } + + /** + * This ensures ordering ascending and descending works by case title APP_PRO_TITLE + * @test + */ + public function it_should_sort_by_process() + { + factory(User::class, 100)->create(); + $process = factory(Process::class, 1)->create([ + 'PRO_ID' => 2, + 'PRO_TITLE' => 'Egypt Supplier Payment Proposal' + ]); + factory(Delegation::class, 1)->create([ + 'PRO_ID' => $process[0]->id + ]); + $process = factory(Process::class, 1)->create([ + 'PRO_ID' => 1, + 'PRO_TITLE' => 'China Supplier Payment Proposal' + ]); + factory(Delegation::class, 1)->create([ + 'PRO_ID' => $process[0]->id + ]); + $process = factory(Process::class, 1)->create([ + 'PRO_ID' => 3, + 'PRO_TITLE' => 'Russia Supplier Payment Proposal' + ]); + factory(Delegation::class, 1)->create([ + 'PRO_ID' => $process[0]->id + ]); + // Get first page, all process ordering ascending + $results = Delegation::search(null, 0, 3, null, null, null, 'ASC', 'APP_PRO_TITLE'); + $this->assertCount(3, $results['data']); + $this->assertEquals('China Supplier Payment Proposal', $results['data'][0]['APP_PRO_TITLE']); + $this->assertEquals('Egypt Supplier Payment Proposal', $results['data'][1]['APP_PRO_TITLE']); + $this->assertEquals('Russia Supplier Payment Proposal', $results['data'][2]['APP_PRO_TITLE']); + // Get first page, all process ordering descending + $results = Delegation::search(null, 0, 3, null, null, null, 'DESC', 'APP_PRO_TITLE'); + $this->assertCount(3, $results['data']); + $this->assertEquals('Russia Supplier Payment Proposal', $results['data'][0]['APP_PRO_TITLE']); + $this->assertEquals('Egypt Supplier Payment Proposal', $results['data'][1]['APP_PRO_TITLE']); + $this->assertEquals('China Supplier Payment Proposal', $results['data'][2]['APP_PRO_TITLE']); + } + + /** + * This ensures ordering ascending and descending works by task title APP_TAS_TITLE + * @test + */ + public function it_should_sort_by_task_title() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + + $task = factory(Task::class, 1)->create([ + 'TAS_ID' => 1000, + 'TAS_TITLE' => 'Initiate Request' + ]); + factory(Delegation::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + + $task = factory(Task::class, 1)->create([ + 'TAS_ID' => 4000, + 'TAS_TITLE' => 'Waiting for AP Manager Validation' + ]); + factory(Delegation::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + + $results = Delegation::search(null, 0, 25, null, null, null, 'ASC', 'APP_TAS_TITLE'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Initiate Request', $results['data'][0]['APP_TAS_TITLE']); + $this->assertEquals('Waiting for AP Manager Validation', $results['data'][1]['APP_TAS_TITLE']); + + $results = Delegation::search(null, 0, 25, null, null, null, 'DESC', 'APP_TAS_TITLE'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Waiting for AP Manager Validation', $results['data'][0]['APP_TAS_TITLE']); + $this->assertEquals('Initiate Request', $results['data'][1]['APP_TAS_TITLE']); + } + + /** + * This ensures ordering ascending and descending works by current user + * @test + */ + public function it_should_sort_by_user() + { + factory(User::class, 100)->create(); + factory(Process::class, 10)->create(); + // Create our unique user, with a unique username + $user = factory(User::class)->create([ + 'USR_USERNAME' => 'gary', + 'USR_LASTNAME' => 'Gary', + 'USR_FIRSTNAME' => 'Bailey', + ]); + // Create a new delegation, but for this specific user + factory(Delegation::class)->create([ + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->id + ]); + $user = factory(User::class)->create([ + 'USR_USERNAME' => 'paul', + 'USR_LASTNAME' => 'Paul', + 'USR_FIRSTNAME' => 'Griffis', + ]); + // Create a new delegation, but for this specific user + factory(Delegation::class)->create([ + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->id + ]); + // Now fetch results, and assume delegation count is 2 and the ordering ascending return Gary + $results = Delegation::search(null, 0, 25, null, null, null, 'ASC', 'APP_CURRENT_USER'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Gary Bailey', $results['data'][0]['APP_CURRENT_USER']); + + // Now fetch results, and assume delegation count is 2 and the ordering descending return Gary + $results = Delegation::search(null, 0, 25, null, null, null, 'DESC', 'APP_CURRENT_USER'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Paul Griffis', $results['data'][0]['APP_CURRENT_USER']); + } + + /** + * This ensures ordering ordering ascending and descending works by last modified APP_UPDATE_DATE + * @test + */ + public function it_should_sort_by_last_modified() + { + factory(User::class,100)->create(); + factory(Process::class,1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_UPDATE_DATE' => '2019-01-02 00:00:00' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_UPDATE_DATE' => '2019-01-03 00:00:00' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_UPDATE_DATE' => '2019-01-04 00:00:00' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Get first page, the minor last modified + $results = Delegation::search(null, 0, 1, null, null, null, 'ASC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-02 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + + $results = Delegation::search(null, 1, 1, null, null, null, 'ASC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-03 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + + $results = Delegation::search(null, 2, 1, null, null, null, 'ASC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-04 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + + $results = Delegation::search(null, 0, 1, null, null, null, 'DESC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-04 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + + $results = Delegation::search(null, 1, 1, null, null, null, 'DESC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-03 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + + $results = Delegation::search(null, 2, 1, null, null, null, 'DESC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-02 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + } + + /** + * This ensures ordering ascending and descending works by due date DEL_TASK_DUE_DATE + * @test + */ + public function it_should_sort_by_due_date() + { + factory(User::class,100)->create(); + factory(Process::class,1)->create(); + factory(Delegation::class, 10)->create([ + 'DEL_TASK_DUE_DATE' => '2019-01-02 00:00:00' + ]); + factory(Delegation::class, 10)->create([ + 'DEL_TASK_DUE_DATE' => '2019-01-03 00:00:00' + ]); + factory(Delegation::class, 9)->create([ + 'DEL_TASK_DUE_DATE' => '2019-01-04 00:00:00' + ]); + // Get first page, the minor last modified + $results = Delegation::search(null, 0, 10, null, null, null, 'ASC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(10, $results['data']); + $this->assertEquals('2019-01-02 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + + $results = Delegation::search(null, 10, 10, null, null, null, 'ASC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(10, $results['data']); + $this->assertEquals('2019-01-03 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + + $results = Delegation::search(null, 20, 10, null, null, null, 'ASC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(9, $results['data']); + $this->assertEquals('2019-01-04 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + + $results = Delegation::search(null, 0, 10, null, null, null, 'DESC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(10, $results['data']); + $this->assertEquals('2019-01-04 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + + $results = Delegation::search(null, 10, 10, null, null, null, 'DESC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(10, $results['data']); + $this->assertEquals('2019-01-03 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + + $results = Delegation::search(null, 20, 10, null, null, null, 'DESC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(9, $results['data']); + $this->assertEquals('2019-01-02 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + } + + /** + * This ensures ordering ascending and descending works by status APP_STATUS + * @test + */ + public function it_should_sort_by_status() + { + factory(User::class,100)->create(); + factory(Process::class,1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_STATUS' => 'DRAFT' + ]); + factory(Delegation::class, 25)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_STATUS' => 'TO_DO' + ]); + factory(Delegation::class, 25)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_STATUS' => 'COMPLETED' + ]); + factory(Delegation::class, 25)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_STATUS' => 'CANCELLED' + ]); + factory(Delegation::class, 25)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + + // Get first page, the minor status label + $results = Delegation::search(null, 0, 25, null, null, null, 'ASC', 'APP_STATUS'); + $this->assertEquals('CANCELLED', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 25, 25, null, null, null, 'ASC', 'APP_STATUS'); + $this->assertEquals('COMPLETED', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 50, 25, null, null, null, 'ASC', 'APP_STATUS'); + $this->assertEquals('DRAFT', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 75, 25, null, null, null, 'ASC', 'APP_STATUS'); + $this->assertEquals('TO_DO', $results['data'][0]['APP_STATUS']); + // Get first page, the major status label + $results = Delegation::search(null, 0, 25, null, null, null, 'DESC', 'APP_STATUS'); + $this->assertEquals('TO_DO', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 25, 25, null, null, null, 'DESC', 'APP_STATUS'); + $this->assertEquals('DRAFT', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 50, 25, null, null, null, 'DESC', 'APP_STATUS'); + $this->assertEquals('COMPLETED', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 75, 25, null, null, null, 'DESC', 'APP_STATUS'); + $this->assertEquals('CANCELLED', $results['data'][0]['APP_STATUS']); + } + + /** + * This checks to make sure filter by category is working properly + * @test + */ + public function it_should_return_data_filtered_by_process_category() + { + factory(User::class, 100)->create(); + // Dummy Processes + factory(ProcessCategory::class, 4)->create(); + factory(Process::class, 4)->create([ + 'PRO_CATEGORY' => ProcessCategory::all()->random()->CATEGORY_UID + ]); + // Dummy Delegations + factory(Delegation::class, 100)->create([ + 'PRO_ID' => Process::all()->random()->PRO_ID + ]); + // Process with the category to search + $processCategorySearch = factory(ProcessCategory::class, 1)->create(); + $categoryUid = $processCategorySearch[0]->CATEGORY_UID; + $processSearch = factory(Process::class, 1)->create([ + 'PRO_ID' => 5, + 'PRO_CATEGORY' => $categoryUid + ]); + // Delegations to found + factory(Delegation::class, 51)->create([ + 'PRO_ID' => $processSearch[0]->id + ]); + + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, null, null, null, null, $categoryUid); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, null, null, null, null, $categoryUid); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, null, null, null, null, $categoryUid); + $this->assertCount(1, $results['data']); + } + + /** + * This ensure the result is right when you search between two given dates + * @test + */ + public function it_should_return_right_data_between_two_dates() + { + factory(User::class, 10)->create(); + factory(Process::class, 10)->create(); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-02 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-03 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-04 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-05 00:00:00']); + $results = Delegation::search(null, 0, 25, null, null, null, null, null, null, '2019-01-02 00:00:00', + '2019-01-03 00:00:00'); + $this->assertCount(20, $results['data']); + foreach ($results['data'] as $value) { + $this->assertGreaterThanOrEqual('2019-01-02 00:00:00', $value['DEL_DELEGATE_DATE']); + $this->assertLessThanOrEqual('2019-01-03 00:00:00', $value['DEL_DELEGATE_DATE']); + $this->assertRegExp('(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ', $value['DEL_DELEGATE_DATE']); + } + } + + /** + * This ensure the result is right when you search from a given date + * @test + */ + public function it_should_return_right_data_when_you_send_only_dateFrom_parameter() + { + factory(User::class, 10)->create(); + factory(Process::class, 10)->create(); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-02 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-03 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-04 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-05 00:00:00']); + $results = Delegation::search(null, 0, 50, null, null, null, null, null, null, '2019-01-02 00:00:00', + null); + $this->assertCount(40, $results['data']); + foreach ($results['data'] as $value) { + $this->assertGreaterThanOrEqual('2019-01-02 00:00:00', $value['DEL_DELEGATE_DATE']); + $this->assertRegExp('(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ', $value['DEL_DELEGATE_DATE']); + } + } + + /** + * This ensure the result is right when you search to a given date + * @test + */ + public function it_should_return_right_data_when_you_send_only_dateTo_parameter() + { + factory(User::class, 10)->create(); + factory(Process::class, 10)->create(); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-02 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-03 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-04 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-05 00:00:00']); + $results = Delegation::search(null, 0, 50, null, null, null, null, null, null, null, + '2019-01-04 00:00:00'); + $this->assertCount(30, $results['data']); + foreach ($results['data'] as $value) { + $this->assertLessThanOrEqual('2019-01-04 00:00:00', $value['DEL_DELEGATE_DATE']); + $this->assertRegExp('(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ', $value['DEL_DELEGATE_DATE']); + } + } + + /** + * This ensures return the correct data by sequential + * @test + */ + public function it_should_return_by_sequential_tasks_pages_of_data() + { + factory(User::class, 100)->create(); + // Create a threads over the process + $process = factory(Process::class, 1)->create([ + 'PRO_ID' => 1 + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 1, + 'APP_TITLE' => 'Request by Thomas', + ]); + // Create a user Gary in a thread + $user = factory(User::class)->create([ + 'USR_USERNAME' => 'gary', + 'USR_LASTNAME' => 'Bailey', + 'USR_FIRSTNAME' => 'Gary', + ]); + // Create a thread with the user Gary + factory(Delegation::class, 1)->create([ + 'PRO_ID' => $process[0]->id, + 'USR_ID' => $user->id, + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_THREAD_STATUS' => 'CLOSED' + ]); + + // Define a dummy task + $task = factory(Task::class, 1)->create([ + 'TAS_TYPE' => 'INTERMEDIATE-THROW' + ]); + // Create a thread with the dummy task this does not need a user + factory(Delegation::class, 1)->create([ + 'PRO_ID' => $process[0]->id, + 'USR_ID' => 0, + 'TAS_ID' => $task[0]->id, + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Create a user Paul in a thread + $user = factory(User::class)->create([ + 'USR_USERNAME' => 'paul', + 'USR_LASTNAME' => 'Griffis', + 'USR_FIRSTNAME' => 'Paul', + ]); + // Create a thread with the user Paul + factory(Delegation::class, 1)->create([ + 'PRO_ID' => $process[0]->id, + 'USR_ID' => $user->id, + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_THREAD_STATUS' => 'OPEN' + ]); + // Get first page, which is 25 of 26 + $results = Delegation::search(null, 0, 10, null, $process[0]->id, null, 'ASC', 'APP_NUMBER'); + $this->assertCount(1, $results['data']); + $this->assertEquals('Griffis Paul', $results['data'][0]['APP_CURRENT_USER']); + } + + /** + * This ensures return the correct data by parallel task all threads CLOSED + * @test + */ + public function it_should_return_by_parallel_tasks_threads_closed() + { + factory(User::class,100)->create(); + factory(Process::class,1)->create(); + $task = factory(Task::class,1)->create([ + 'TAS_TITLE' => 'Parallel task 1' + ]); + factory(Delegation::class, 5)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'DEL_THREAD_STATUS' => 'CLOSED' + ]); + $task = factory(Task::class,1)->create([ + 'TAS_TITLE' => 'Parallel task 2' + ]); + factory(Delegation::class, 5)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'DEL_THREAD_STATUS' => 'CLOSED' + ]); + // Get first page, the order taskTitle + $results = Delegation::search(null, 0, 2, null, null, null, 'ASC', + 'TAS_TITLE', null, null, null,'TAS_TITLE'); + $this->assertCount(0, $results['data']); + + // Get first page, the order taskTitle + $results = Delegation::search(null, 0, 2, null, null, null, 'DESC', + 'TAS_TITLE', null, null, null,'TAS_TITLE'); + $this->assertCount(0, $results['data']); + } + + /** + * This ensures return the correct data by parallel task all threads OPEN + * @test + */ + public function it_should_return_by_parallel_tasks_threads_open() + { + factory(User::class,100)->create(); + factory(Process::class,1)->create(); + //Create the threads + factory(Delegation::class, 5)->create([ + 'DEL_THREAD_STATUS' => 'OPEN' + ]); + // Get first page, all the open status + $results = Delegation::search(null, 0, 5, null, null, null); + $this->assertCount(5, $results['data']); + $this->assertEquals('OPEN', $results['data'][0]['DEL_THREAD_STATUS']); + $this->assertEquals('OPEN', $results['data'][4]['DEL_THREAD_STATUS']); + + } +} \ No newline at end of file diff --git a/workflow/engine/methods/cases/proxyCasesList.php b/workflow/engine/methods/cases/proxyCasesList.php index bfec0df59..0be7607f4 100644 --- a/workflow/engine/methods/cases/proxyCasesList.php +++ b/workflow/engine/methods/cases/proxyCasesList.php @@ -1,4 +1,9 @@ error = G::LoadTranslation('ID_LOGIN_AGAIN'); @@ -9,31 +14,59 @@ if (!isset($_SESSION['USER_LOGGED'])) { } +/** + * Do input filtering, although filtering should be done on the frontend rendering, not here + */ $filter = new InputFilter(); $_GET = $filter->xssFilterHard($_GET); $_REQUEST = $filter->xssFilterHard($_REQUEST); $_SESSION['USER_LOGGED'] = $filter->xssFilterHard($_SESSION['USER_LOGGED']); -//Getting the extJs parameters +// Callback in the UI to utilize $callback = isset($_REQUEST["callback"]) ? $_REQUEST["callback"] : "stcCallback1001"; -//This default value was defined in casesList.js -$dir = isset($_REQUEST["dir"]) ? $_REQUEST["dir"] : "DESC"; -//This default value was defined in casesList.js + +// Sort column $sort = isset($_REQUEST["sort"]) ? $_REQUEST["sort"] : "APP_NUMBER"; +// Sort direction +$dir = isset($_REQUEST["dir"]) ? $_REQUEST["dir"] : "DESC"; + +// Pagination control $start = !empty($_REQUEST["start"]) ? $_REQUEST["start"] : 0; $limit = !empty($_REQUEST["limit"]) ? $_REQUEST["limit"] : 25; + +// Our search filter $filter = isset($_REQUEST["filter"]) ? $_REQUEST["filter"] : ""; + +// What process $process = isset($_REQUEST["process"]) ? $_REQUEST["process"] : ""; + +// What category $category = isset($_REQUEST["category"]) ? $_REQUEST["category"] : ""; + +// What status $status = isset($_REQUEST["status"]) ? strtoupper($_REQUEST["status"]) : ""; $filterStatus = isset($_REQUEST["filterStatus"]) ? strtoupper($_REQUEST["filterStatus"]) : ""; + +// What user $user = isset($_REQUEST["user"]) ? $_REQUEST["user"] : ""; + +// What keywords to search $search = isset($_REQUEST["search"]) ? $_REQUEST["search"] : ""; + +// What kind of action $action = isset($_GET["action"]) ? $_GET["action"] : (isset($_REQUEST["action"]) ? $_REQUEST["action"] : "todo"); + +// What kind of search $type = isset($_GET["type"]) ? $_GET["type"] : (isset($_REQUEST["type"]) ? $_REQUEST["type"] : "extjs"); + +// Date ranges $dateFrom = isset($_REQUEST["dateFrom"]) ? substr($_REQUEST["dateFrom"], 0, 10) : ""; $dateTo = isset($_REQUEST["dateTo"]) ? substr($_REQUEST["dateTo"], 0, 10) : ""; + +// First? No idea $first = isset($_REQUEST["first"]) ? true : false; + + $openApplicationUid = (isset($_REQUEST['openApplicationUid']) && $_REQUEST['openApplicationUid'] != '') ? $_REQUEST['openApplicationUid'] : null; $search = (!is_null($openApplicationUid)) ? $openApplicationUid : $search; @@ -67,10 +100,8 @@ try { break; } - $apps = new Applications(); - if ($action == 'search') { - $data = $apps->searchAll( + $data = Delegation::search( $userUid, $start, $limit, @@ -85,7 +116,7 @@ try { $columnSearch ); } else { - $data = $apps->getAll( + $data = Delegation::search( $userUid, $start, $limit, diff --git a/workflow/engine/src/ProcessMaker/Model/Application.php b/workflow/engine/src/ProcessMaker/Model/Application.php new file mode 100644 index 000000000..eb367a03c --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Model/Application.php @@ -0,0 +1,27 @@ +hasMany(Delegation::class, 'APP_UID', 'APP_UID'); + } + + public function parent() + { + return $this->hasOne(Application::class, 'APP_PARENT', 'APP_UID'); + } + + public function currentUser() + { + return $this->hasOne(User::class, 'APP_CUR_USER', 'USR_UID'); + } +} diff --git a/workflow/engine/src/ProcessMaker/Model/Delegation.php b/workflow/engine/src/ProcessMaker/Model/Delegation.php new file mode 100644 index 000000000..a5a11b08b --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Model/Delegation.php @@ -0,0 +1,333 @@ +belongsTo(Application::class, 'APP_UID', 'APP_UID'); + } + + /** + * Returns the user this delegation belongs to + */ + public function user() + { + return $this->belongsTo(User::class, 'USR_ID', 'USR_ID'); + } + + /** + * Return the process task this belongs to + */ + public function task() + { + return $this->belongsTo(Task::class, 'TAS_ID', 'TAS_ID'); + } + + /** + * Return the process this delegation belongs to + */ + public function process() + { + return $this->belongsTo(Process::class, 'PRO_ID', 'PRO_ID'); + } + + /** + * Searches for delegations which match certain criteria + * + * The query is related to advanced search with different filters + * We can search by process, status of case, category of process, users, delegate date from and to + * + * @param integer $userId The USR_ID to search for (Note, this is no longer the USR_UID) + * @param integer $start for the pagination + * @param integer $limit for the pagination + * @param string $search + * @param integer $process the pro_id + * @param integer $status of the case + * @param string $dir if the order is DESC or ASC + * @param string $sort name of column by sort, can be: + * [APP_NUMBER, APP_TITLE, APP_PRO_TITLE, APP_TAS_TITLE, APP_CURRENT_USER, APP_UPDATE_DATE, DEL_DELEGATE_DATE, DEL_TASK_DUE_DATE, APP_STATUS_LABEL] + * @param string $category uid for the process + * @param date $dateFrom + * @param date $dateTo + * @param string $filterBy name of column for a specific search, can be: [APP_NUMBER, APP_TITLE, TAS_TITLE] + * @return array $result result of the query + */ + + public static function search( + $userId = null, + // Default pagination values + $start = 0, + $limit = 25, + $search = null, + $process = null, + $status = null, + $dir = null, + $sort = null, + $category = null, + $dateFrom = null, + $dateTo = null, + $filterBy = 'APP_TITLE' + ) { + $search = trim($search); + + // Start the query builder, selecting our base attributes + $selectColumns = [ + 'APPLICATION.APP_NUMBER', + 'APPLICATION.APP_UID', + 'APPLICATION.APP_STATUS', + 'APPLICATION.APP_STATUS AS APP_STATUS_LABEL', + 'APPLICATION.PRO_UID', + 'APPLICATION.APP_CREATE_DATE', + 'APPLICATION.APP_FINISH_DATE', + 'APPLICATION.APP_UPDATE_DATE', + 'APPLICATION.APP_TITLE', + 'APP_DELEGATION.USR_UID', + 'APP_DELEGATION.TAS_UID', + 'APP_DELEGATION.USR_ID', + 'APP_DELEGATION.PRO_ID', + 'APP_DELEGATION.DEL_INDEX', + 'APP_DELEGATION.DEL_LAST_INDEX', + 'APP_DELEGATION.DEL_DELEGATE_DATE', + 'APP_DELEGATION.DEL_INIT_DATE', + 'APP_DELEGATION.DEL_FINISH_DATE', + 'APP_DELEGATION.DEL_TASK_DUE_DATE', + 'APP_DELEGATION.DEL_RISK_DATE', + 'APP_DELEGATION.DEL_THREAD_STATUS', + 'APP_DELEGATION.DEL_PRIORITY', + 'APP_DELEGATION.DEL_DURATION', + 'APP_DELEGATION.DEL_QUEUE_DURATION', + 'APP_DELEGATION.DEL_STARTED', + 'APP_DELEGATION.DEL_DELAY_DURATION', + 'APP_DELEGATION.DEL_FINISHED', + 'APP_DELEGATION.DEL_DELAYED', + 'APP_DELEGATION.DEL_DELAY_DURATION', + 'TASK.TAS_TITLE AS APP_TAS_TITLE', + 'TASK.TAS_TYPE AS APP_TAS_TYPE', + ]; + $query = DB::table('APP_DELEGATION')->select(DB::raw(implode(',', $selectColumns))); + + // Add join for task, filtering for task title if needed + // It doesn't make sense for us to search for any delegations that match tasks that are events or web entry + $query->join('TASK', function ($join) use ($filterBy, $search) { + $join->on('APP_DELEGATION.TAS_ID', '=', 'TASK.TAS_ID') + ->whereNotIn('TASK.TAS_TYPE', [ + 'WEBENTRYEVENT', + 'END-MESSAGE-EVENT', + 'START-MESSAGE-EVENT', + 'INTERMEDIATE-THROW', + ]); + if ($filterBy == 'TAS_TITLE' && $search) { + $join->where('TASK.TAS_TITLE', 'LIKE', "%${search}%"); + } + }); + + // Add join for application, taking care of status and filtering if necessary + $query->join('APPLICATION', function ($join) use ($filterBy, $search, $status, $query) { + $join->on('APP_DELEGATION.APP_NUMBER', '=', 'APPLICATION.APP_NUMBER'); + if ($filterBy == 'APP_TITLE' && $search) { + $join->where('APPLICATION.APP_TITLE', 'LIKE', "%${search}%"); + } + // Based on the below, we can further limit the join so that we have a smaller data set based on join criteria + switch ($status) { + case 1: //DRAFT + $join->where('APPLICATION.APP_STATUS_ID', 1); + break; + case 2: //TO_DO + $join->where('APPLICATION.APP_STATUS_ID', 2); + break; + case 3: //COMPLETED + $join->where('APPLICATION.APP_STATUS_ID', 3); + break; + case 4: //CANCELLED + $join->where('APPLICATION.APP_STATUS_ID', 4); + break; + case "PAUSED": + $join->where('APPLICATION.APP_STATUS', 'TO_DO'); + break; + default: //All status + // Don't do anything here, we'll need to do the more advanced where below + } + }); + + // Add join for process, but only for certain scenarios such as category or process + if (($category && !$process) || $sort == 'APP_PRO_TITLE') { + $query->join('PROCESS', function ($join) use ($category) { + $join->on('APP_DELEGATION.PRO_ID', '=', 'PROCESS.PRO_ID'); + if ($category) { + $join->where('PROCESS.PRO_CATEGORY', $category); + } + }); + } + + // Add join for user, but only for certain scenarios as sorting + if ($sort == 'APP_CURRENT_USER') { + $query->join('USERS', function ($join) use ($userId) { + $join->on('APP_DELEGATION.USR_ID', '=', 'USERS.USR_ID'); + }); + } + + // Search for specified user + if ($userId) { + $query->where('APP_DELEGATION.USR_ID', $userId); + } + + // Search for specified process + if ($process) { + $query->where('APP_DELEGATION.PRO_ID', $process); + } + + // Search for an app/case number + if ($filterBy == 'APP_NUMBER' && $search) { + $query->where('APP_DELEGATION.APP_NUMBER', 'LIKE', "%${search}%"); + } + + // Date range filter + if (!empty($dateFrom)) { + $query->where('APP_DELEGATION.DEL_DELEGATE_DATE', '>=', $dateFrom); + } + if (!empty($dateTo)) { + $dateTo = $dateTo . " 23:59:59"; + // This is inclusive + $query->where('APP_DELEGATION.DEL_DELEGATE_DATE', '<=', $dateTo); + } + + // Status Filter + // This is tricky, the below behavior is combined with the application join behavior above + switch ($status) { + case 1: //DRAFT + $query->where('APP_DELEGATION.DEL_THREAD_STATUS', 'OPEN'); + break; + case 2: //TO_DO + $query->where('APP_DELEGATION.DEL_THREAD_STATUS', 'OPEN'); + break; + case 3: //COMPLETED + $query->where('APP_DELEGATION.DEL_LAST_INDEX', 1); + break; + case 4: //CANCELLED + $query->where('APP_DELEGATION.DEL_LAST_INDEX', 1); + break; + case "PAUSED": + // Do nothing, as the app status check for TO_DO is performed in the join above + break; + default: //All statuses. + $query->where(function ($query) { + // Check to see if thread status is open + $query->where('APP_DELEGATION.DEL_THREAD_STATUS', 'OPEN') + ->orWhere(function ($query) { + // Or, we make sure if the thread is closed, and it's the last delegation, and if the app is completed or cancelled + $query->where('APP_DELEGATION.DEL_THREAD_STATUS', 'CLOSED') + ->where('APP_DELEGATION.DEL_LAST_INDEX', 1) + ->whereIn('APPLICATION.APP_STATUS_ID', [3, 4]); + }); + }); + break; + } + + // Add any sort if needed + if($sort) { + switch ($sort) { + case 'APP_NUMBER': + $query->orderBy('APP_DELEGATION.APP_NUMBER', $dir); + break; + case 'APP_PRO_TITLE': + // We can do this because we joined the process table if sorting by it + $query->orderBy('PROCESS.PRO_TITLE', $dir); + break; + case 'APP_TAS_TITLE': + $query->orderBy('TASK.TAS_TITLE', $dir); + break; + case 'APP_CURRENT_USER': + // We can do this because we joined the user table if sorting by it + $query->orderBy('USERS.USR_LASTNAME', $dir); + $query->orderBy('USERS.USR_FIRSTNAME', $dir); + break; + default: + $query->orderBy($sort, $dir); + } + } + + // Add pagination to the query + $query = $query->offset($start) + ->limit($limit); + + // Fetch results and transform to a laravel collection + $results = $query->get(); + + // Transform with additional data + $priorities = ['1' => 'VL', '2' => 'L', '3' => 'N', '4' => 'H', '5' => 'VH']; + $results->transform(function ($item, $key) use ($priorities) { + // Convert to an array as our results must be an array + $item = json_decode(json_encode($item), true); + // If it's assigned, fetch the user + if($item['USR_ID']) { + $user = User::where('USR_ID', $item['USR_ID'])->first(); + } else { + $user = null; + } + $process = Process::where('PRO_ID', $item['PRO_ID'])->first(); + + // Rewrite priority string + if ($item['DEL_PRIORITY']) { + $item['DEL_PRIORITY'] = G::LoadTranslation("ID_PRIORITY_{$priorities[$item['DEL_PRIORITY']]}", 'en'); + } + + // Merge in desired application data + if ($item['APP_STATUS']) { + $item['APP_STATUS_LABEL'] = G::LoadTranslation("ID_${item['APP_STATUS']}", 'en'); + } else { + $item['APP_STATUS_LABEL'] = $application->APP_STATUS; + } + + // Merge in desired process data + // Handle situation where the process might not be in the system anymore + $item['APP_PRO_TITLE'] = $process ? $process->PRO_TITLE : ''; + + // Merge in desired user data + $item['USR_LASTNAME'] = $user ? $user->USR_LASTNAME : ''; + $item['USR_FIRSTNAME'] = $user ? $user->USR_FIRSTNAME : ''; + $item['USR_USERNAME'] = $user ? $user->USR_USERNAME : ''; + + //@todo: this section needs to use 'User Name Display Format', currently in the extJs is defined this + $item["APP_CURRENT_USER"] = $item["USR_LASTNAME"] . ' ' . $item["USR_FIRSTNAME"]; + + $item["APPDELCR_APP_TAS_TITLE"] = ''; + + $item["USRCR_USR_UID"] = $item["USR_UID"]; + $item["USRCR_USR_FIRSTNAME"] = $item["USR_FIRSTNAME"]; + $item["USRCR_USR_LASTNAME"] = $item["USR_LASTNAME"]; + $item["USRCR_USR_USERNAME"] = $item["USR_USERNAME"]; + $item["APP_OVERDUE_PERCENTAGE"] = ''; + + return $item; + }); + + // Remove any empty erroenous data + $results = $results->filter(); + + // Bundle into response array + $response = [ + // Fake totalCount to show pagination + 'totalCount' => $start + $limit + 1, + 'sql' => $query->toSql(), + 'bindings' => $query->getBindings(), + 'data' => $results->values()->toArray(), + ]; + + return $response; + } + +} diff --git a/workflow/engine/src/ProcessMaker/Model/Process.php b/workflow/engine/src/ProcessMaker/Model/Process.php index f131fb318..b32b92eb1 100644 --- a/workflow/engine/src/ProcessMaker/Model/Process.php +++ b/workflow/engine/src/ProcessMaker/Model/Process.php @@ -14,8 +14,29 @@ class Process extends Model { // Set our table name protected $table = 'PROCESS'; - // We do have a created at, but we don't store an updated at + // Our custom timestamp columns const CREATED_AT = 'PRO_CREATE_DATE'; - const UPDATED_AT = null; + const UPDATED_AT = 'PRO_UPDATE_DATE'; + /** + * Retrieve all applications that belong to this process + */ + public function applications() + { + return $this->hasMany(Application::class, 'PRO_ID', 'PRO_ID'); + } -} \ No newline at end of file + public function tasks() + { + return $this->hasMany(Task::class, 'PRO_UID', 'PRO_UID'); + } + + public function creator() + { + return $this->hasOne(User::class, 'PRO_CREATE_USER', 'USR_UID'); + } + + public function category() + { + return $this->hasOne(ProcessCategory::class, 'PRO_CATEGORY', 'CATEGORY_UID'); + } +} diff --git a/workflow/engine/src/ProcessMaker/Model/ProcessCategory.php b/workflow/engine/src/ProcessMaker/Model/ProcessCategory.php new file mode 100644 index 000000000..8ad9d705e --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Model/ProcessCategory.php @@ -0,0 +1,19 @@ +belongsTo(Process::class, 'PRO_UID', 'PRO_UID'); + } + + public function delegations() + { + return $this->hasMany(Delegation::class, 'TAS_ID', 'TAS_ID'); + } +} diff --git a/workflow/engine/src/ProcessMaker/Model/TaskUser.php b/workflow/engine/src/ProcessMaker/Model/TaskUser.php new file mode 100644 index 000000000..67549792b --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Model/TaskUser.php @@ -0,0 +1,12 @@ +hasMany(Delegation::class, 'USR_ID', 'USR_ID'); + } +}