diff --git a/gulliver/js/codemirror/addon/hint/php-hint.js b/gulliver/js/codemirror/addon/hint/php-hint.js index 320dfe2a8..2f535dcd4 100644 --- a/gulliver/js/codemirror/addon/hint/php-hint.js +++ b/gulliver/js/codemirror/addon/hint/php-hint.js @@ -90,6 +90,10 @@ var evaluateFunctionFunction = [evaluateFunction+"($gridName,$Expression)"]; arrayFunctions[evaluateFunction] = evaluateFunctionFunction; + var PMFTotalCalculation = "PMFTotalCalculation"; + var PMFTotalCalculationFunction = [PMFTotalCalculation + "($gridName, $field, 'function')"]; + arrayFunctions[PMFTotalCalculation] = PMFTotalCalculationFunction; + var PMFTaskCase = "PMFTaskCase"; var PMFTaskCaseFunction = [PMFTaskCase+"($caseId)"]; arrayFunctions[PMFTaskCase] = PMFTaskCaseFunction; @@ -219,7 +223,7 @@ arrayFunctions[PMFGetCaseNotes] = PMFGetCaseNotesFunction; var phpPMFunctions = [formatDate,getCurrentDate,getCurrentTime,literalDate,capitalize,lowerCase,upperCase,userInfo,executeQuery,orderGrid, - evaluateFunction,PMFTaskCase,PMFTaskList,PMFUserList,PMFGroupList,PMFRoleList,PMFCaseList,PMFProcessList,PMFSendVariables,PMFDerivateCase, + evaluateFunction, PMFTotalCalculation, PMFTaskCase,PMFTaskList,PMFUserList,PMFGroupList,PMFRoleList,PMFCaseList,PMFProcessList,PMFSendVariables,PMFDerivateCase, PMFNewCaseImpersonate,PMFNewCase,PMFPauseCase,PMFUnpauseCase,PMFAssignUserToGroup,PMFCreateUser,PMFUpdateUser,PMFInformationUser, generateCode,setCaseTrackerCode,jumping,PMFRedirectToStep,pauseCase,PMFSendMessage,PMFgetLabelOption,PMFGenerateOutputDocument, PMFGetUserEmailAddress,PMFGetNextAssignedUser,PMFDeleteCase,PMFCancelCase,PMFAddInputDocument,PMFAddCaseNote,PMFGetCaseNotes]; diff --git a/tests/unit/workflow/engine/classes/PmFunctions/PMFTotalCalculationTest.php b/tests/unit/workflow/engine/classes/PmFunctions/PMFTotalCalculationTest.php new file mode 100644 index 000000000..1624a21b2 --- /dev/null +++ b/tests/unit/workflow/engine/classes/PmFunctions/PMFTotalCalculationTest.php @@ -0,0 +1,260 @@ + [ + "field1" => "Value 1", + "field2" => 2 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 5 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 3 + ] + ]; + $field = "field2"; + $this->assertEquals(10, PMFTotalCalculation($grid, $field, 'sum')); + } + /** + * This tests if the "PMFTotalCalculation" execute correctly the average + * @test + */ + public function it_must_return_the_average_of_the_method() + { + $grid = [ + '1' => [ + "field1" => "Value 1", + "field2" => 2 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 5 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 3 + ] + ]; + $this->assertEquals(3.3333333333, PMFTotalCalculation($grid, 'field2', 'average')); + } + /** + * This tests if the "PMFTotalCalculation" execute correctly the median + * @test + */ + public function it_must_return_the_median_of_the_method() + { + $grid1 = [ + '1' => [ + "field1" => "Value 1", + "field2" => 2 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 5 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 3 + ] + ]; + $grid2 = [ + '1' => [ + "field1" => "Value 1", + "field2" => 2 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 5 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 3 + ], + '4' => [ + "field1" => "Value 3", + "field2" => 8 + ] + ]; + $this->assertEquals(3, PMFTotalCalculation($grid1, 'field2', 'median')); + $this->assertEquals(4, PMFTotalCalculation($grid2, 'field2', 'median')); + } + /** + * This tests if the "PMFTotalCalculation" execute correctly the minimum + * @test + */ + public function it_must_return_the_minimum_of_the_method() + { + $grid = [ + '1' => [ + "field1" => "Value 1", + "field2" => 5 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 2 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 3 + ] + ]; + $this->assertEquals(2, PMFTotalCalculation($grid, 'field2', 'minimum')); + } + /** + * This tests if the "PMFTotalCalculation" execute correctly the maximum + * @test + */ + public function it_must_return_the_maximum_of_the_method() + { + $grid = [ + '1' => [ + "field1" => "Value 1", + "field2" => 2 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 5 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 3 + ] + ]; + $this->assertEquals(5, PMFTotalCalculation($grid, 'field2', 'maximum')); + } + /** + * This tests if the "PMFTotalCalculation" execute correctly the standardDeviation + * @test + */ + public function it_must_return_the_standardDeviation_of_the_method() + { + $grid = [ + '1' => [ + "field1" => "Value 1", + "field2" => 25 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 40 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 10 + ] + ]; + $this->assertEquals(12.2474487139, PMFTotalCalculation($grid, 'field2', 'standardDeviation')); + } + /** + * This tests if the "PMFTotalCalculation" execute correctly the variance + * @test + */ + public function it_must_return_the_variance_of_the_method() + { + $grid = [ + '1' => [ + "field1" => "Value 1", + "field2" => 25 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 40 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 10 + ] + ]; + $this->assertEquals(150, PMFTotalCalculation($grid, 'field2', 'variance')); + } + /** + * This tests if the "PMFTotalCalculation" execute correctly the percentile + * @test + */ + public function it_must_return_the_percentile_of_the_method() + { + $grid = [ + '1' => [ + "field1" => "Value 1", + "field2" => 10 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 35 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 5 + ] + ]; + $expectedArray = [ + "0" => 20, + "1" => 70, + "2" => 10, + ]; + $this->assertEquals($expectedArray, PMFTotalCalculation($grid, 'field2', 'percentile')); + } + /** + * This tests if the "PMFTotalCalculation" execute correctly the count + * @test + */ + public function it_must_return_the_count_of_the_method() + { + $grid = [ + '1' => [ + "field1" => "Value 1", + "field2" => 25 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 40 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 10 + ] + ]; + $this->assertEquals(3, PMFTotalCalculation($grid, 'field2', 'count')); + } + /** + * This tests if the "PMFTotalCalculation" execute correctly the count distinct + * @test + */ + public function it_must_return_the_count_distinct_of_the_method() + { + $grid = [ + '1' => [ + "field1" => "Value 1", + "field2" => 20 + ], + '2' => [ + "field1" => "Value 2", + "field2" => 20 + ], + '3' => [ + "field1" => "Value 3", + "field2" => 10 + ] + ]; + $this->assertEquals(2, PMFTotalCalculation($grid, 'field2', 'countDistinct')); + } +} \ No newline at end of file diff --git a/workflow/engine/classes/class.pmFunctions.php b/workflow/engine/classes/class.pmFunctions.php index e99854804..37d40f81b 100644 --- a/workflow/engine/classes/class.pmFunctions.php +++ b/workflow/engine/classes/class.pmFunctions.php @@ -446,6 +446,123 @@ function evaluateFunction($aGrid, $sExpresion) return $aGrid; } +/** + * + * @method + * + * Executes operations in the grid fields, such as sum, average, median, minimum, maximun, + * stantard derivation, variance, percentile, count, count distinct + * + * @name PMFTotalCalculation + * @label PMFTotalCalculation Function + * @link http://wiki.processmaker.com/index.php/ProcessMaker_Functions#PMFTotalCalculation.28.29 + * @param array | $grid | Grid | The input grid. + * @param string (32) | $field | Name of field | The name of the field. + * @param string (32) | $function | Operation. + * @return object|array | $result | Result | Result according of the function + * + */ +function PMFTotalCalculation($grid, $field, $function) +{ + $systemConfiguration = Bootstrap::getSystemConfiguration(); + $floatPointNumber = $systemConfiguration['PMFTOTALCALCULATION_FLOATING_POINT_NUMBER']; + $function = strtolower($function); + $totalRows = count($grid); + $result = 0; + $sum = 0; + + switch ($function) { + case "sum": + for ($i = 1; $i <= $totalRows; $i += 1) { + $result += $grid[$i][$field]; + } + break; + case "average": + for ($i = 1; $i <= $totalRows; $i += 1) { + $result += $grid[$i][$field]; + } + $result = $result / $totalRows; + break; + case "median": + $arrayAux = []; + for ($i = 1; $i <= $totalRows; $i += 1) { + $arrayAux[] = $grid[$i][$field]; + } + sort($arrayAux); + $term = ($totalRows + 1) / 2; + if ($totalRows % 2 === 0) { + $term = floor($term); + $result = ($arrayAux[$term - 1] + $arrayAux[$term]) / 2; + } else { + $result = $arrayAux[$term - 1]; + } + break; + case "minimum": + $result = $grid[1][$field]; + for ($i = 2; $i <= $totalRows; $i += 1) { + if ($grid[$i][$field] < $result) { + $result = $grid[$i][$field]; + } + } + break; + case "maximum": + $result = $grid[1][$field]; + for ($i = 2; $i <= $totalRows; $i += 1) { + if ($grid[$i][$field] > $result) { + $result = $grid[$i][$field]; + } + } + break; + case "standarddeviation": + $mean = 0; + for ($i = 1; $i <= $totalRows; $i += 1) { + $mean += $grid[$i][$field]; + } + $mean = $mean / $totalRows; + for ($i = 1; $i <= $totalRows; $i += 1) { + $result += pow($grid[$i][$field] - $mean, 2); + } + $result = sqrt($result / $totalRows); + break; + case "variance": + $mean = 0; + for ($i = 1; $i <= $totalRows; $i += 1) { + $mean += $grid[$i][$field]; + } + $mean = $mean / $totalRows; + for ($i = 1; $i <= $totalRows; $i += 1) { + $result += pow($grid[$i][$field] - $mean, 2); + } + $result = $result / $totalRows; + break; + case "percentile": + $result = []; + $arrayAux = []; + for ($i = 1; $i <= $totalRows; $i += 1) { + $sum += $grid[$i][$field]; + $arrayAux[] = $grid[$i][$field]; + } + for ($i = 0; $i < count($arrayAux); $i += 1) { + $result[] = round(($arrayAux[$i] * 100) / $sum, $floatPointNumber); + } + break; + case "count": + $result = $totalRows; + break; + case "countdistinct": + $arrayAux = []; + for ($i = 1; $i <= $totalRows; $i += 1) { + $arrayAux[] = $grid[$i][$field]; + } + $result = count(array_count_values($arrayAux)); + break; + } + if ($function !== "percentile") { + return round($result, $floatPointNumber); + } + return $result; +} + /** * Web Services Functions * */ diff --git a/workflow/engine/src/ProcessMaker/Core/System.php b/workflow/engine/src/ProcessMaker/Core/System.php index 91ad8ab49..9b35594e5 100644 --- a/workflow/engine/src/ProcessMaker/Core/System.php +++ b/workflow/engine/src/ProcessMaker/Core/System.php @@ -78,7 +78,8 @@ class System 'highlight_home_folder_enable' => 0, 'highlight_home_folder_refresh_time' => 10, 'highlight_home_folder_scope' => 'unassigned', // For now only this list is supported - 'disable_advanced_search_case_title_fulltext' => 0 + 'disable_advanced_search_case_title_fulltext' => 0, + 'PMFTOTALCALCULATION_FLOATING_POINT_NUMBER' => 10 ]; /**