Conflicts

This commit is contained in:
Paula Quispe
2020-06-12 19:04:53 -04:00
33 changed files with 2799 additions and 620 deletions

View File

@@ -0,0 +1,14 @@
<?php
namespace App\Jobs;
class GenerateReportTable extends QueuedClosure
{
/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 1;
}

View File

@@ -6,9 +6,37 @@ use ProcessMaker\Model\ProcessVariables;
$factory->define(ProcessVariables::class, function (Faker $faker) {
return [
'VAR_UID' => G::generateUniqueID(),
'PRO_ID' => G::generateUniqueID(),
'PRJ_UID' => G::generateUniqueID(),
'VAR_NAME' => $faker->word,
'VAR_FIELD_TYPE' => G::generateUniqueID(),
'VAR_FIELD_TYPE_ID' => G::generateUniqueID(),
'VAR_FIELD_SIZE' => 10,
'VAR_LABEL' => 'string',
'VAR_DBCONNECTION' => 'workflow',
'VAR_SQL' => '',
'VAR_NULL' => 0,
'VAR_DEFAULT' => '',
'VAR_ACCEPTED_VALUES' => '[]',
'INP_DOC_UID' => ''
];
});
// Create a processVariables with the foreign keys
$factory->state(ProcessVariables::class, 'foreign_keys', function (Faker $faker) {
$types = ['string', 'integer', 'float', 'boolean', 'datetime', 'grid', 'array', 'file', 'multiplefile', 'object'];
$varType = $faker->randomElement($types);
$varTypeId = array_search($varType, $types) + 1;
// Create values in the foreign key relations
$process = factory(\ProcessMaker\Model\Process::class)->create();
return [
'VAR_UID' => G::generateUniqueID(),
'PRO_ID' => $process->PRO_ID,
'PRJ_UID' => $process->PRO_UID,
'VAR_NAME' => $faker->word,
'VAR_FIELD_TYPE' => $varType,
'VAR_FIELD_TYPE_ID' => $varTypeId,
'VAR_FIELD_SIZE' => 10,
'VAR_LABEL' => 'string',
'VAR_DBCONNECTION' => 'workflow',

View File

@@ -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];

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
{
"data": {
"var_Text1": "5298067855ed6e6893e1424067710552",
"var_Textarea1": "4835809915ed6e6893e14a6079656976",
"var_Dropdown1": "5287566085ed6e6893e14e0083475368",
"var_Suggest1": "4813021735ed6e6893e1520081779769",
"var_DateTime1": "1975-04-04 16:34:22",
"var_String1": "7984290665ed6e6893e15b2092042769",
"var_Integer1": "44"
},
"mapping": [{
"sFieldName": "var_Text1",
"sType": "char"
}, {
"sFieldName": "var_Textarea1",
"sType": "text"
}, {
"sFieldName": "var_Dropdown1",
"sType": "char"
}, {
"sFieldName": "var_Suggest1",
"sType": "char"
}, {
"sFieldName": "var_DateTime1",
"sType": "date"
}, {
"sFieldName": "var_String1",
"sType": "char"
}, {
"sFieldName": "var_Integer1",
"sType": "number"
}]
}

View File

@@ -984,6 +984,64 @@ class PmDynaformTest extends TestCase
// Compare the values
$this->assertEquals($dynaformTitle, $dynaform->DYN_TITLE);
}
/**
* This test should verify the setDependentOptionsForDatetime() method, to
* add the dependentOptions property to the datetime control.
* @test
* @covers PmDynaform::jsonr()
* @covers PmDynaform::setDependentOptionsForDatetime()
*/
public function it_should_test_dependent_options_for_datetime_control()
{
$pathData = PATH_TRUNK . "/tests/resources/dynaform1.json";
$data = file_get_contents($pathData);
$json = json_decode($data);
//assert for not contain property: dependentOptions
$result = json_decode(json_encode($json), JSON_OBJECT_AS_ARRAY);
$fn = function($item) use(&$fn) {
if (is_array($item)) {
if (isset($item['type']) && $item['type'] === 'datetime') {
$this->assertArrayNotHasKey('dependentOptions', $item);
}
array_map($fn, $item);
}
};
array_map($fn, $result);
//assert new property: dependentOptions
$dynaform = new PmDynaform();
$dynaform->jsonr($json);
$result = json_decode(json_encode($json), JSON_OBJECT_AS_ARRAY);
$fn = function($item) use(&$fn) {
if (is_array($item)) {
if (isset($item['type']) && $item['type'] === 'datetime') {
$this->assertArrayHasKey('dependentOptions', $item);
$this->assertArrayHasKey('minDate', $item['dependentOptions']);
$this->assertArrayHasKey('maxDate', $item['dependentOptions']);
$this->assertArrayHasKey('defaultDate', $item['dependentOptions']);
}
array_map($fn, $item);
}
};
array_map($fn, $result);
$dynaform = new PmDynaform();
$reflection = new ReflectionClass($dynaform);
$reflectionMethod = $reflection->getMethod('setDependentOptionsForDatetime');
$reflectionMethod->setAccessible(true);
$a = new stdClass();
$reflectionMethod->invokeArgs($dynaform, [&$a]);
$this->assertInstanceOf('ReflectionMethod', $reflectionMethod);
$a = new stdClass();
$a->type = 'suggest';
$reflectionMethod->invokeArgs($dynaform, [&$a]);
$this->assertInstanceOf('ReflectionMethod', $reflectionMethod);
}
}
// Dummy function used for the coverture

View File

@@ -0,0 +1,260 @@
<?php
namespace Tests\unit\workflow\engine\classes\PmFunctions;
use Faker\Factory;
use Tests\TestCase;
/**
* Test the PMFTotalCalculation() function
*
* @link https://wiki.processmaker.com/3.1/ProcessMaker_Functions#executeQuery.28.29
*/
class PMFTotalCalculationTest extends TestCase
{
/**
* This tests if the "PMFTotalCalculation" execute correctly the sum
* @test
*/
public function it_must_return_the_sum_of_the_method()
{
$grid = [
'1' => [
"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 = [
"1" => 20,
"2" => 70,
"3" => 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'));
}
}

View File

@@ -12,6 +12,7 @@ use Tests\TestCase;
class ReportTablesTest extends TestCase
{
use CreateTestSite;
use DatabaseTransactions;
@@ -21,14 +22,12 @@ class ReportTablesTest extends TestCase
public function setUp()
{
parent::setUp();
$this->markTestIncomplete(""
. "This test has started using the ./processmaker command, this "
. "command requires the file 'paths_installed.php', that is, a "
. "valid installation of processmaker.");
$_SERVER["REQUEST_URI"] = "";
config(['queue.default' => 'sync']);
config(["system.workspace" => "test"]);
$workspace = config("system.workspace");
$this->createDBFile($workspace);
$this->createConstantsOfConnection();
}
/**
@@ -39,6 +38,33 @@ class ReportTablesTest extends TestCase
parent::tearDown();
}
/**
* Create constants of connection to databases.
*/
private function createConstantsOfConnection()
{
$constants = [
'DB_ADAPTER' => env('mysql'),
'DB_HOST' => env('DB_HOST'),
'DB_NAME' => env('DB_DATABASE'),
'DB_USER' => env('DB_USERNAME'),
'DB_PASS' => env('DB_PASSWORD'),
'DB_RBAC_HOST' => env('DB_HOST'),
'DB_RBAC_NAME' => env('DB_DATABASE'),
'DB_RBAC_USER' => env('DB_USERNAME'),
'DB_RBAC_PASS' => env('DB_PASSWORD'),
'DB_REPORT_HOST' => env('DB_HOST'),
'DB_REPORT_NAME' => env('DB_DATABASE'),
'DB_REPORT_USER' => env('DB_USERNAME'),
'DB_REPORT_PASS' => env('DB_PASSWORD'),
];
foreach ($constants as $key => $value) {
if (!defined($key)) {
define($key, $value);
}
}
}
/**
* Check if the "populateTable" function returns an array value if entered all parameters.
* @test
@@ -565,97 +591,6 @@ class ReportTablesTest extends TestCase
$this->assertEquals($expected, $actual);
}
/**
* Get mapping fields supported by report table.
* @return array
*/
private function getMapFields()
{
return [
[
'sFieldName' => 'var_Text1',
'sType' => 'char'
],
[
'sFieldName' => 'var_Textarea1',
'sType' => 'text'
],
[
'sFieldName' => 'var_Dropdown1',
'sType' => 'char'
],
[
'sFieldName' => 'var_Suggest1',
'sType' => 'char'
],
[
'sFieldName' => 'var_DateTime1',
'sType' => 'date'
],
[
'sFieldName' => 'var_String1',
'sType' => 'char'
],
[
'sFieldName' => 'var_Integer1',
'sType' => 'number'
],
[
'sFieldName' => 'var_Boolean1',
'sType' => 'boolean'
],
[
'sFieldName' => 'var_Array1',
'sType' => 'array'
]
];
}
/**
* Create fields data by type supported.
* @param array $types
* @return array
*/
private function createFieldsByType($types = [])
{
$fields = [];
$mapping = [];
$faker = Faker\Factory::create();
$date = $faker->dateTime();
$mapFields = $this->getMapFields();
foreach ($mapFields as $key => $value) {
if (!in_array($value['sType'], $types)) {
continue;
}
switch ($value['sType']) {
case 'number':
$mapping[] = $value;
$fields[$value['sFieldName']] = (string) random_int(0, 100);
break;
case 'char':
$mapping[] = $value;
$fields[$value['sFieldName']] = G::generateUniqueID();
break;
case 'text':
$mapping[] = $value;
$fields[$value['sFieldName']] = G::generateUniqueID();
break;
case 'date':
$mapping[] = $value;
$fields[$value['sFieldName']] = $date->format('Y-m-d H:i:s');
break;
case 'boolean':
$mapping[] = $value;
$fields[$value['sFieldName']] = ['0' => 0];
break;
}
}
return [
'data' => $fields,
'mapping' => $mapping
];
}
/**
* Prepare data initial for test, the grid parameter is optional if you want
* to create a grid type field.
@@ -665,7 +600,7 @@ class ReportTablesTest extends TestCase
* @param boolean $grid
* @return object
*/
private function prepareData($tableName, $grid = null)
private function prepareData($tableName, $grid = null, $structure = [])
{
$applicationNumber = Application::max('APP_NUMBER');
if (is_null($applicationNumber)) {
@@ -681,7 +616,10 @@ class ReportTablesTest extends TestCase
$taskUid = G::generateUniqueID();
$applicationUid = G::generateUniqueID();
$structure = $this->createFieldsByType(['number', 'char', 'text', 'date']);
if (empty($structure)) {
$structure = $this->getDataFromFile('structureReportTable.json');
}
$fields = $structure['mapping'];
$dataFields = $structure['data'];
$appData = [
@@ -753,4 +691,157 @@ class ReportTablesTest extends TestCase
$result->application = $application;
return $result;
}
/**
* Check if the "populateTable" method is it filling with missing values into app_data.
* @test
* @covers ReportTables::populateTable
*/
public function it_should_populating_data_with_fields_missing_in_to_app_data()
{
$tableName = 'TestReportTable';
$result = $this->prepareData($tableName);
$connectionShortName = 'wf';
$type = 'NORMAL';
$fields = $result->fields;
$proUid = $result->processUid;
$grid = '';
$app = Application::where('APP_UID', '=', $result->applicationUid)->get()->first();
$appData = unserialize($app->APP_DATA);
unset($appData['var_Textarea1']);
$appData = serialize($appData);
Application::where('APP_UID', '=', $result->applicationUid)->update(['APP_DATA' => $appData]);
$reportTables = new ReportTables();
$reportTables->populateTable($tableName, $connectionShortName, $type, $fields, $proUid, $grid);
$expected = $result->dataFields;
$expected['APP_UID'] = $result->applicationUid;
$expected['APP_NUMBER'] = $result->applicationNumber;
$expected['var_Textarea1'] = '';
$actual = (array) DB::table($tableName)
->select()
->first();
$this->assertEquals($expected, $actual);
}
/**
* Check if the "populateTable" method is it filling with arrays values.
* @test
* @covers ReportTables::populateTable
*/
public function it_should_populating_data_with_arrays_values()
{
$tableName = 'TestReportTable';
$result = $this->prepareData($tableName);
$connectionShortName = 'wf';
$type = 'NORMAL';
$fields = $result->fields;
$proUid = $result->processUid;
$grid = '';
$app = Application::where('APP_UID', '=', $result->applicationUid)->get()->first();
$appData = unserialize($app->APP_DATA);
$appData['var_Textarea1'] = [];
$appData = serialize($appData);
Application::where('APP_UID', '=', $result->applicationUid)->update(['APP_DATA' => $appData]);
$reportTables = new ReportTables();
$reportTables->populateTable($tableName, $connectionShortName, $type, $fields, $proUid, $grid);
$expected = $result->dataFields;
$expected['APP_UID'] = $result->applicationUid;
$expected['APP_NUMBER'] = $result->applicationNumber;
$expected['var_Textarea1'] = '';
$actual = (array) DB::table($tableName)
->select()
->first();
$this->assertEquals($expected, $actual);
}
/**
* Check if the "populateTable" method is it filling with missing values into app_data for grids control.
* parameters and type and grid are correct values.
* @test
* @covers ReportTables::populateTable
*/
public function it_should_populating_data_with_all_parameters_with_type_is_grid_fields_missing_in_to_app_data()
{
$tableName = 'TestReportTable';
$result = $this->prepareData($tableName, true);
$connectionShortName = 'wf';
$type = 'GRID';
$fields = $result->fields;
$proUid = $result->processUid;
$grid = 'var_Grid1';
$app = Application::where('APP_UID', '=', $result->applicationUid)->get()->first();
$appData = unserialize($app->APP_DATA);
unset($appData['var_Grid1'][1]['var_Textarea1']);
$appData = serialize($appData);
Application::where('APP_UID', '=', $result->applicationUid)->update(['APP_DATA' => $appData]);
$reportTables = new ReportTables();
$reportTables->populateTable($tableName, $connectionShortName, $type, $fields, $proUid, $grid);
$indexRow = 1;
$expected = $result->appData[$grid];
foreach ($expected as &$row) {
$row['APP_UID'] = $result->applicationUid;
$row['APP_NUMBER'] = $result->applicationNumber;
$row['ROW'] = (string) ($indexRow++);
}
$expected = array_values($expected);
$expected[0]['var_Textarea1'] = '';
$actual = DB::table($tableName)
->select()
->get();
$actual->transform(function ($item, $key) {
return (array) $item;
});
$actual = $actual->toArray();
$this->assertEquals($expected, $actual);
}
/**
* Check an exception if the input parameters are wrong.
* @test
* @covers ReportTables::populateTable
*/
public function it_should_catch_an_exception()
{
$tableName = 'TestReportTable';
$result = $this->prepareData($tableName, true);
$connectionShortName = 'wf';
$type = 'GRID';
$fields = $result->fields;
$proUid = $result->processUid;
$grid = 'var_Grid1';
//assert exception
$this->expectException(Exception::class);
$reportTables = new ReportTables();
$reportTables->populateTable($tableName, $connectionShortName, $type, null, $proUid, $grid);
}
/**
* This gets data from a json file.
* @param string $pathData
* @return array
*/
private function getDataFromFile(string $pathData): array
{
$pathData = PATH_TRUNK . "tests/resources/{$pathData}";
$data = file_get_contents($pathData);
$result = json_decode($data, JSON_OBJECT_AS_ARRAY);
return $result;
}
}

View File

@@ -3,17 +3,32 @@
namespace Tests\unit\workflow\engine\classes\model;
use AdditionalTables;
use App\Jobs\GenerateReportTable;
use Exception;
use G;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Schema;
use ProcessMaker\BusinessModel\ReportTable;
use ProcessMaker\Model\AdditionalTables as AdditionalTablesModel;
use ProcessMaker\Model\Application;
use ProcessMaker\Model\DbSource;
use ProcessMaker\Model\Delegation;
use ProcessMaker\Model\Process;
use ProcessMaker\Model\Task;
use Tests\TestCase;
class AdditionalTablesTest extends TestCase
{
/**
* Set up method.
*/
public function setUp()
{
parent::setUp();
}
/**
* This tests the creation of a PMTable.
* @test
@@ -198,6 +213,74 @@ class AdditionalTablesTest extends TestCase
$this->assertContains($actual[0], $expected, false);
}
/**
* Check if populate report table is added to job queue.
* @test
* @covers \AdditionalTables::populateReportTable
*/
public function it_should_test_populate_report_table()
{
$proUid = factory(Process::class)->create()->PRO_UID;
$task = factory(Task::class)->create([
'PRO_UID' => $proUid
]);
//local connections
$dbSource = factory(DbSource::class)->create([
'PRO_UID' => $proUid,
'DBS_SERVER' => env('DB_HOST'),
'DBS_DATABASE_NAME' => env('DB_DATABASE'),
'DBS_USERNAME' => env('DB_USERNAME'),
'DBS_PASSWORD' => G::encrypt(env('DB_PASSWORD'), env('DB_DATABASE')) . "_2NnV3ujj3w",
'DBS_PORT' => '3306',
'DBS_CONNECTION_TYPE' => 'NORMAL'
]);
$additionalTable = factory(AdditionalTablesModel::class)->create([
'PRO_UID' => $proUid,
'DBS_UID' => $dbSource->DBS_UID,
]);
$tableName = $additionalTable->ADD_TAB_NAME;
$name = $additionalTable->ADD_TAB_CLASS_NAME;
$this->createSchema($dbSource->DBS_DATABASE_NAME, $tableName, $name, $dbSource->DBS_UID);
//external connection
$dbSource = factory(DbSource::class)->create([
'PRO_UID' => $proUid,
'DBS_SERVER' => config('database.connections.testexternal.host'),
'DBS_DATABASE_NAME' => config('database.connections.testexternal.database'),
'DBS_USERNAME' => config('database.connections.testexternal.username'),
'DBS_PASSWORD' => G::encrypt(config('database.connections.testexternal.password'), config('database.connections.testexternal.database')) . "_2NnV3ujj3w",
'DBS_PORT' => '3306',
'DBS_CONNECTION_TYPE' => 'NORMAL'
]);
$additionalTable = factory(AdditionalTablesModel::class)->create([
'PRO_UID' => $proUid,
'DBS_UID' => $dbSource->DBS_UID,
]);
$tableNameExternal = $additionalTable->ADD_TAB_NAME;
$nameExternal = $additionalTable->ADD_TAB_CLASS_NAME;
$this->createSchema($dbSource->DBS_DATABASE_NAME, $tableNameExternal, $nameExternal, $dbSource->DBS_UID);
$application = factory(Application::class)->create([
'PRO_UID' => $proUid
]);
factory(Delegation::class)->create([
'DEL_THREAD_STATUS' => 'CLOSED',
'APP_NUMBER' => $application->APP_NUMBER,
'TAS_UID' => $task->TAS_UID,
]);
//assertions
Queue::fake();
Queue::assertNothingPushed();
$additionalTables = new AdditionalTables();
$additionalTables->populateReportTable($tableName, 'workflow', 'NORMAL', $proUid, '', $additionalTable->ADD_TAB_UID);
Queue::assertPushed(GenerateReportTable::class);
}
/**
* This gets the content from template file.
* @param string $pathData

View File

@@ -188,4 +188,43 @@ class VariableTest extends TestCase
$this->assertArrayHasKey('var_accepted_values', $res, "The result does not contains 'var_accepted_values' as key");
$this->assertArrayHasKey('inp_doc_uid', $res, "The result does not contains 'inp_doc_uid' as key");
}
/**
* Test it return the variables by type related to the PRO_UID
*
* @covers \ProcessMaker\BusinessModel\Variable::getVariablesByType()
* @test
*/
public function it_list_variables_by_type_related_a_process()
{
$process = factory(Process::class)->create();
$varType = 'integer';
$varTypeId = 2;
for ($x = 1; $x <= 5; $x++) {
$processVar = factory(ProcessVariables::class)->states('foreign_keys')->create([
'PRO_ID' => $process->PRO_ID,
'PRJ_UID' => $process->PRO_UID,
'VAR_FIELD_TYPE' => $varType,
'VAR_FIELD_TYPE_ID' => $varTypeId,
'VAR_NAME' => 'varTestName' . $x,
]);
}
$variable = new Variable();
// Get all results
$res = $variable->getVariablesByType($process->PRO_UID, 2);
$this->assertEquals(5, count($res));
$res = head($res);
$this->assertArrayHasKey('value', $res, "The result does not contains 'value' as key");
// Get a specific start and limit
$res = $variable->getVariablesByType($process->PRO_UID, 2, 0, 2);
$this->assertNotEmpty($res);
$this->assertEquals(2, count($res));
// Get a specific search
$res = $variable->getVariablesByType($process->PRO_UID, 2, 0, 4, 'varTest');
$this->assertNotEmpty($res);
$this->assertEquals(4, count($res));
// When the search does not match
$res = $variable->getVariablesByType($process->PRO_UID, 2, null, null, 'other');
$this->assertEmpty($res);
}
}

View File

@@ -2,6 +2,7 @@
namespace ProcessMaker\Core;
use App\Jobs\Email;
use Tests\TestCase;
class JobsManagerTest extends TestCase

View File

@@ -70,4 +70,41 @@ class ProcessVariablesTest extends TestCase
$result = ProcessVariables::getVariables($process->PRO_ID);
$this->assertNotEmpty($result);
}
/**
* Test it return the variables by type related to the PRO_ID
*
* @covers \ProcessMaker\Model\ProcessVariables::getVariablesByType()
* @test
*/
public function it_list_variables_type_by_process()
{
$process = factory(Process::class)->create();
$varType = 'integer';
$varTypeId = 2;
for ($x = 1; $x <= 5; $x++) {
$processVar = factory(ProcessVariables::class)->states('foreign_keys')->create([
'PRO_ID' => $process->PRO_ID,
'PRJ_UID' => $process->PRO_UID,
'VAR_FIELD_TYPE' => $varType,
'VAR_FIELD_TYPE_ID' => $varTypeId,
'VAR_NAME' => 'varTestName' . $x,
]);
}
$res = ProcessVariables::getVariablesByType($processVar->PRO_ID, 2, null, null, null);
$this->assertNotEmpty($res);
$this->assertEquals(5, count($res));
// Get a specific start and limit
$res = ProcessVariables::getVariablesByType($process->PRO_ID, 2, 0, 2);
$this->assertNotEmpty($res);
$this->assertEquals(2, count($res));
// Get a specific search
$res = ProcessVariables::getVariablesByType($process->PRO_ID, 2, 0, 4, 'varTest');
$this->assertNotEmpty($res);
$this->assertEquals(4, count($res));
// When the search does not match
$res = ProcessVariables::getVariablesByType($process->PRO_ID, 2, null, null, 'other');
$this->assertEmpty($res);
}
}

View File

@@ -1,74 +0,0 @@
<?php
use Illuminate\Support\Facades\DB;
use ProcessMaker\Core\System;
CLI::taskName("generate-data-report");
CLI::taskRun("generateDataReport");
CLI::taskDescription("\nGenerate data report by process in a respective workspace, you must pass through arguments the project identifier and the processing interval.");
CLI::taskArg("workspace", false);
CLI::taskOpt("uid", "Identifier that represents the process, must be 32 characters.", "", "process=");
CLI::taskOpt("start", "The start option skips so many rows before returning results.", "", "start=");
CLI::taskOpt("limit", "The limit option restricts the number of rows returned.", "", "limit=");
/**
* Generate data report by process in a respective workspace, you must pass through
* arguments the project identifier and the processing interval.
* @param array $options
* @return void
*/
function generateDataReport(array $options): void
{
//get workspace
if (empty($options[0])) {
CLI::logging("Workspace undefined!\n");
return;
}
$workspace = $options[0];
//get options
$parameters = [
"tableName=" => "",
"type=" => "",
"process=" => "",
"gridKey=" => "",
"additionalTable=" => "",
"className=" => "",
"pathWorkspace=" => "",
"start=" => "",
"limit=" => ""
];
foreach ($parameters as $key => $value) {
for ($i = 1; $i < count($options); $i++) {
if (strpos($options[$i], $key) !== false) {
$parameters[$key] = str_replace($key, "", $options[$i]);
break;
}
}
}
//validations
$needed = [
"process="
];
foreach ($needed as $value) {
if (empty($parameters[$value])) {
CLI::logging("Missing options {$value}.\n");
return;
}
}
//run method
$workspaceTools = new WorkspaceTools($workspace);
$workspaceTools->generateDataReport(
$parameters["tableName="],
$parameters["type="],
$parameters["process="],
$parameters["gridKey="],
$parameters["additionalTable="],
$parameters["className="],
$parameters["pathWorkspace="],
(int) $parameters["start="],
(int) $parameters["limit="]
);
}

View File

@@ -1,21 +0,0 @@
<?php
CLI::taskName("populate-table");
CLI::taskRun("populateTable");
CLI::taskDescription("\nThis function populates the report table with the APP_DATA data");
CLI::taskArg("workspace", false);
/**
* This function populates the report table with the APP_DATA data.
* @return void
*/
function populateTable($options): void
{
//get options
$workspaceName = $options[0];
$query = base64_decode($options[1]);
$isRbac = (bool) $options[2];
$workspace = new WorkspaceTools($workspaceName);
$workspace->populateTableReport($query, $isRbac);
}

View File

@@ -29,6 +29,7 @@ class PmDynaform
public $lang = SYS_LANG;
public $translations = null;
public $onPropertyRead = "onPropertyReadFormInstance";
public $onAfterPropertyRead = "onAfterPropertyReadFormInstance";
public $pathRTLCss = '';
public $record = null;
public $records = null;
@@ -545,6 +546,7 @@ class PmDynaform
if (isset($this->fields["APP_DATA"][$json->name . "_label"])) {
$json->data->label = $this->fields["APP_DATA"][$json->name . "_label"];
}
$this->setDependentOptionsForDatetime($json, $this->fields);
}
if ($key === "type" && ($value === "file") && isset($this->fields["APP_DATA"]["APPLICATION"])) {
$oCriteriaAppDocument = new Criteria("workflow");
@@ -771,6 +773,11 @@ class PmDynaform
}
}
}
//read event after
$fn = $this->onAfterPropertyRead;
if (is_callable($fn) || function_exists($fn)) {
$fn($json, $key, $value);
}
}
}
}
@@ -2489,4 +2496,38 @@ class PmDynaform
$json->dataSchema[$key] = $columnsData;
}
}
/**
* Sets the dependentOptions property for datetime control, if it contains dependent fields.
* @param stdClass $json
* @param array $fields
* @return void
*/
private function setDependentOptionsForDatetime(stdClass &$json, array $fields = []): void
{
if (!isset($json->type)) {
return;
}
if ($json->type !== 'datetime') {
return;
}
$json->dependentOptions = '';
$backup = $this->onAfterPropertyRead;
$properties = [
'defaultDate' => $json->defaultDate,
'minDate' => $json->minDate,
'maxDate' => $json->maxDate
];
$this->onAfterPropertyRead = function(stdClass &$json, $key, $value) use($backup, $properties) {
if (isset($json->type) && $json->type === 'datetime' && $key === "dependentOptions") {
$json->dependentOptions = new stdClass();
foreach ($properties as $property => $value) {
if (is_string($value) && in_array(substr($value, 0, 2), self::$prefixs)) {
$json->dependentOptions->{$property} = $value;
}
}
$this->onAfterPropertyRead = $backup;
}
};
}
}

View File

@@ -1,8 +1,8 @@
<?php
use App\Jobs\GenerateReportTable;
use Illuminate\Support\Facades\DB;
use ProcessMaker\Core\MultiProcOpen;
use ProcessMaker\Commands\PopulateTableReport;
use ProcessMaker\Core\JobsManager;
use ProcessMaker\Model\Application;
/**
@@ -205,6 +205,9 @@ class ReportTables
*/
public function populateTable($tableName, $connectionShortName = 'report', $type = 'NORMAL', $fields = [], $proUid = '', $grid = '')
{
$config = System::getSystemConfiguration();
$reportTableBatchRegeneration = $config['report_table_batch_regeneration'];
$tableName = $this->sPrefix . $tableName;
//we have to do the propel connection
$database = $this->chooseDB($connectionShortName);
@@ -222,7 +225,7 @@ class ReportTables
$applications = Application::getByProUid($proUid);
$i = 1;
$queryValues = "";
$numberRecords = 1000;
$numberRecords = $reportTableBatchRegeneration;
$n = count($applications);
foreach ($applications as $application) {
$appData = $case->unserializeData($application->APP_DATA);
@@ -262,11 +265,12 @@ class ReportTables
$queryValues = rtrim($queryValues, ",");
$query = $headQuery . $queryValues;
$queryValues = "";
$workspace = config("system.workspace");
$processesManager = new MultiProcOpen();
$processesManager->chunk(1, 1, function($size, $start, $limit) use ($query, $workspace) {
return new PopulateTableReport($workspace, $query);
});
//add to queue
$closure = function() use($query) {
DB::insert($query);
};
JobsManager::getSingleton()->dispatch(GenerateReportTable::class, $closure);
}
} else {
if (isset($appData[$grid])) {
@@ -304,11 +308,12 @@ class ReportTables
$queryValues = rtrim($queryValues, ",");
$query = $headQuery . $queryValues;
$queryValues = "";
$workspace = config("system.workspace");
$processesManager = new MultiProcOpen();
$processesManager->chunk(1, 1, function($size, $start, $limit) use ($query, $workspace) {
return new PopulateTableReport($workspace, $query);
});
//add to queue
$closure = function() use($query) {
DB::insert($query);
};
JobsManager::getSingleton()->dispatch(GenerateReportTable::class, $closure);
}
}
}

View File

@@ -249,15 +249,16 @@ function executeQuery ($SqlStatement, $DBConnectionUID = 'workflow', $aParameter
if (is_null(config('database.connections.' . $DBConnectionUID . '.driver'))) {
// Force to load the external connections
DbConnections::loadAdditionalConnections();
if (config('database.connections.' . $DBConnectionUID . '.driver') !== 'oracle') {
// If the connections drivers are "mysql", "pgsql" or "sqlsrv" we're using Laravel
$con = DB::connection($DBConnectionUID);
$con->beginTransaction();
} else {
// If the connection driver is "oracle" we're using the native oci8 functions
$con = Propel::getConnection($DBConnectionUID);
$con->begin();
}
}
if (config('database.connections.' . $DBConnectionUID . '.driver') !== 'oracle') {
// If the connections drivers are "mysql", "pgsql" or "sqlsrv" we're using Laravel
$con = DB::connection($DBConnectionUID);
$con->beginTransaction();
} else {
// If the connection driver is "oracle" we are using the native oci8 functions
$con = Propel::getConnection($DBConnectionUID);
$con->begin();
}
$blackList = System::getQueryBlackList();
@@ -459,6 +460,123 @@ function evaluateFunction($aGrid, $sExpresion)
return $aGrid;
}
/**
*
* @method
*
* Executes operations in the grid fields, such as sum, average, median, minimum, maximun,
* stantard deviation, 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 int|float|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[$i] = $grid[$i][$field];
}
for ($i = 1; $i <= count($arrayAux); $i += 1) {
$result[$i] = 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 *
*/

View File

@@ -1,8 +1,9 @@
<?php
use App\Jobs\GenerateReportTable;
use Illuminate\Support\Facades\DB;
use ProcessMaker\Commands\GenerateDataReport;
use ProcessMaker\Core\MultiProcOpen;
use ProcessMaker\Core\JobsManager;
use ProcessMaker\Core\System;
use ProcessMaker\Model\Application;
use ProcessMaker\Model\Fields;
@@ -735,28 +736,23 @@ class AdditionalTables extends BaseAdditionalTables
$workspace = config("system.workspace");
$pathWorkspace = PATH_WORKSPACE;
$n = Application::count();
$processesManager = new MultiProcOpen();
$processesManager->chunk($n, 1000, function($size, $start, $limit) use(
$workspace,
$tableName,
$type,
$processUid,
$gridKey,
$addTabUid,
$className,
$pathWorkspace) {
return new GenerateDataReport(
$workspace,
$tableName,
$type,
$processUid,
$gridKey,
$addTabUid,
$className,
$pathWorkspace,
$start,
$limit);
});
//batch process
$config = System::getSystemConfiguration();
$reportTableBatchRegeneration = $config['report_table_batch_regeneration'];
$size = $n;
$start = 0;
$limit = $reportTableBatchRegeneration;
for ($i = 1; $start < $size; $i++) {
$closure = function() use($workspace, $tableName, $type, $processUid, $gridKey, $addTabUid, $className, $pathWorkspace, $start, $limit) {
$workspaceTools = new WorkspaceTools($workspace);
$workspaceTools->generateDataReport($tableName, $type, $processUid, $gridKey, $addTabUid, $className, $pathWorkspace, $start, $limit);
};
JobsManager::getSingleton()->dispatch(GenerateReportTable::class, $closure);
$start = $i * $limit;
}
}
/**

View File

@@ -77,7 +77,7 @@ class AppMessageMapBuilder
$tMap->addColumn('APP_MSG_TYPE_ID', 'AppMsgTypeId', 'int', CreoleTypes::TINYINT, false, null);
$tMap->addColumn('APP_MSG_SUBJECT', 'AppMsgSubject', 'string', CreoleTypes::VARCHAR, true, 150);
$tMap->addColumn('APP_MSG_SUBJECT', 'AppMsgSubject', 'string', CreoleTypes::VARCHAR, true, 998);
$tMap->addColumn('APP_MSG_FROM', 'AppMsgFrom', 'string', CreoleTypes::VARCHAR, true, 100);

View File

@@ -579,9 +579,6 @@ abstract class BaseEmailServerPeer
}
} else {
if ($obj->isNew() || $obj->isColumnModified(EmailServerPeer::MESS_ENGINE))
$columns[EmailServerPeer::MESS_ENGINE] = $obj->getMessEngine();
}
return BasePeer::doValidate(EmailServerPeer::DATABASE_NAME, EmailServerPeer::TABLE_NAME, $columns);

View File

@@ -1,27 +1,4 @@
<?php
/**
* databases.php
*
* ProcessMaker Open Source Edition
* Copyright (C) 2004 - 2008 Colosa Inc.23
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* For more information, contact Colosa Inc, 2566 Le Jeune Rd.,
* Coral Gables, FL, 33134, USA, or email info@colosa.com.
*
*/
if (defined('PATH_DB') && !empty(config("system.workspace"))) {
@@ -29,7 +6,32 @@ if (defined('PATH_DB') && !empty(config("system.workspace"))) {
throw new Exception("Could not find db.php in current workspace " . config("system.workspace"));
}
require_once(PATH_DB . config("system.workspace") . '/db.php');
//These constants must not exist, they will be created by "db.php".
$constants = [
'DB_ADAPTER',
'DB_HOST',
'DB_NAME',
'DB_USER',
'DB_PASS',
'DB_RBAC_HOST',
'DB_RBAC_NAME',
'DB_RBAC_USER',
'DB_RBAC_PASS' ,
'DB_REPORT_HOST',
'DB_REPORT_NAME',
'DB_REPORT_USER',
'DB_REPORT_PASS',
];
$load = true;
foreach ($constants as $value) {
if (defined($value)) {
$load = false;
break;
}
}
if ($load === true) {
require_once(PATH_DB . config("system.workspace") . '/db.php');
}
//to do: enable for other databases
$dbType = DB_ADAPTER;
$dsn = DB_ADAPTER . '://' . DB_USER . ':' . urlencode(DB_PASS) . '@' . DB_HOST . '/' . DB_NAME;
@@ -42,15 +44,12 @@ if (defined('PATH_DB') && !empty(config("system.workspace"))) {
switch (DB_ADAPTER) {
case 'mysql':
$dsn .= '?encoding=utf8';
$dsnRbac .= '?encoding=utf8';
$dsn .= '?encoding=utf8';
$dsnRbac .= '?encoding=utf8';
$dsnReport .= '?encoding=utf8';
break;
case 'mssql':
case 'sqlsrv':
//$dsn .= '?sendStringAsUnicode=false';
//$dsnRbac .= '?sendStringAsUnicode=false';
//$dsnReport .= '?sendStringAsUnicode=false';
break;
default:
break;
@@ -64,7 +63,7 @@ if (defined('PATH_DB') && !empty(config("system.workspace"))) {
$pro ['datasources']['rp']['connection'] = $dsnReport;
$pro ['datasources']['rp']['adapter'] = DB_ADAPTER;
$dbHost = explode(':', DB_HOST);
config(['database.connections.workflow.host' => $dbHost[0]]);
config(['database.connections.workflow.database' => DB_NAME]);
@@ -76,6 +75,6 @@ if (defined('PATH_DB') && !empty(config("system.workspace"))) {
}
$pro ['datasources']['dbarray']['connection'] = 'dbarray://user:pass@localhost/pm_os';
$pro ['datasources']['dbarray']['adapter'] = 'dbarray';
$pro ['datasources']['dbarray']['adapter'] = 'dbarray';
return $pro;

View File

@@ -25325,6 +25325,12 @@ msgstr "The PHP files execution was disabled please contact the system administr
msgid "Please complete the reassign reason."
msgstr "Please complete the reassign reason."
# TRANSLATION
# LABEL/ID_THE_REPORT_TABLE_IS_REGENERATING_PLEASE_COME_BACK_IN_A_FEW_MINUTES
#: LABEL/ID_THE_REPORT_TABLE_IS_REGENERATING_PLEASE_COME_BACK_IN_A_FEW_MINUTES
msgid "The report table is regenerating please come back in a few minutes."
msgstr "The report table is regenerating please come back in a few minutes."
# TRANSLATION
# LABEL/ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED
#: LABEL/ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED

View File

@@ -1215,7 +1215,7 @@ class pmTablesProxy extends HttpProxyController
if (!empty($table) && $table['PRO_UID'] != '') {
try {
$additionalTables->populateReportTable($table['ADD_TAB_NAME'], PmTable::resolveDbSource($table['DBS_UID']), $table['ADD_TAB_TYPE'], $table['PRO_UID'], $table['ADD_TAB_GRID'], $table['ADD_TAB_UID']);
$result->message = 'Generated for table ' . $table['ADD_TAB_NAME'];
$result->message = G::LoadTranslation("ID_THE_REPORT_TABLE_IS_REGENERATING_PLEASE_COME_BACK_IN_A_FEW_MINUTES");
} catch (Exception $e) {
$context = Bootstrap::getDefaultContextLog();
$context['proUid'] = $table['PRO_UID'];

View File

@@ -61112,6 +61112,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE
( 'LABEL','ID_THE_NAME_CHANGE_MAY_CAUSE_DATA_LOSS','en','The change might cause data loss in the PM table. Do you want to continue?','2017-03-30') ,
( 'LABEL','ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED','en','The PHP files execution was disabled please contact the system administrator.','2018-04-20') ,
( 'LABEL','ID_THE_REASON_REASSIGN_USER_EMPTY','en','Please complete the reassign reason.','2016-10-20') ,
( 'LABEL','ID_THE_REPORT_TABLE_IS_REGENERATING_PLEASE_COME_BACK_IN_A_FEW_MINUTES','en','The report table is regenerating please come back in a few minutes.','2020-06-01') ,
( 'LABEL','ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED','en','The upload of PHP files was disabled please contact the system administrator.','2018-04-20') ,
( 'LABEL','ID_THE_USERNAME_EMAIL_IS_INCORRECT','en','The username or email is incorrect','2018-01-18') ,
( 'LABEL','ID_THIS_MONTH','en','This Month','2014-01-15') ,

View File

@@ -1178,7 +1178,9 @@ class DynaForm
}
foreach ($oldColumns as $oldColumn) {
if (strtolower(AdditionalTables::getPHPName($column->id)) === strtolower(AdditionalTables::getPHPName($oldColumn->id))) {
$identicals[] = "'" . $column->id . "' - '" . $oldColumn->id . "'";
if (strtolower(AdditionalTables::getPHPName($column->var_name)) === strtolower(AdditionalTables::getPHPName($oldColumn->var_name))) {
$identicals[] = "'" . $column->id . "' - '" . $oldColumn->id . "'";
}
}
}
}

View File

@@ -26,6 +26,16 @@ class Variable
'object' => 10
];
/**
* Get the variables types accepted
*
* @return array
*/
public function getVariableTypes()
{
return $this->variableTypes;
}
/**
* Create Variable for a Process
*
@@ -355,6 +365,33 @@ class Variable
return $arrayVariables;
}
/**
* Get data of Variables related to the specific type
*
* @param string $processUid Unique id of Process
* @param int $typeVarId
* @param int $start
* @param int $limit
* @param string $search
* @param string $prefix
*
* @return array, return an array with varaibles filter by type
*/
public function getVariablesByType($processUid, $typeVarId = 0, $start = null, $limit = null, $search = null, $prefix = null)
{
//Verify data
$proId = Validator::proUid($processUid, '$prj_uid');
$variables = ProcessVariables::getVariablesByType($proId, $typeVarId, $start, $limit, $search);
$arrayVariables = [];
foreach ($variables as $var) {
$arrayVariables[] = [
'value' => is_null($prefix) ? $var['VAR_NAME'] : $prefix . $var['VAR_NAME'],
];
}
return $arrayVariables;
}
/**
* Verify field definition
*

View File

@@ -1,80 +0,0 @@
<?php
namespace ProcessMaker\Commands;
use ProcessMaker\Core\ProcOpen;
class GenerateDataReport extends ProcOpen
{
private $workspace;
private $tableName;
private $type;
private $processUid;
private $gridKey;
private $addTabUid;
private $className;
private $pathWorkspace;
private $start;
private $limit;
/**
* Initializes the command parameters.
* @param string $workspace
* @param string $tableName
* @param string $type
* @param string $processUid
* @param string $gridKey
* @param string $addTabUid
* @param string $className
* @param string $pathWorkspace
* @param integer $start
* @param integer $limit
*/
public function __construct(
$workspace,
$tableName,
$type = 'NORMAL',
$processUid = '',
$gridKey = '',
$addTabUid = '',
$className = '',
$pathWorkspace,
$start = 0,
$limit = 10)
{
$this->workspace = $workspace;
$this->tableName = $tableName;
$this->type = $type;
$this->processUid = $processUid;
$this->gridKey = $gridKey;
$this->addTabUid = $addTabUid;
$this->className = $className;
$this->pathWorkspace = $pathWorkspace;
$this->start = $start;
$this->limit = $limit;
$this->setCwd(PATH_TRUNK);
parent::__construct($this->buildCommand());
}
/**
* Returns the command to execute.
* @return string
*/
private function buildCommand(): string
{
$command = PHP_BINDIR . "/php "
. "./processmaker "
. "'generate-data-report' "
. "'{$this->workspace}' "
. "'tableName={$this->tableName}' "
. "'type={$this->type}' "
. "'process={$this->processUid}' "
. "'gridKey={$this->gridKey}' "
. "'additionalTable={$this->addTabUid}' "
. "'className={$this->className}' "
. "'pathWorkspace={$this->pathWorkspace}' "
. "'start={$this->start}' "
. "'limit={$this->limit}' ";
return $command;
}
}

View File

@@ -1,42 +0,0 @@
<?php
namespace ProcessMaker\Commands;
use ProcessMaker\Core\ProcOpen;
class PopulateTableReport extends ProcOpen
{
private $workspace;
private $sql;
private $isRbac;
/**
* Initializes the command parameters.
* @param string $workspace
* @param string $sql
* @param boolean $isRbac
*/
public function __construct($workspace, $sql, $isRbac = false)
{
$this->workspace = $workspace;
$this->sql = $sql;
$this->isRbac = $isRbac;
$this->setCwd(PATH_TRUNK);
parent::__construct($this->buildCommand());
}
/**
* Returns the command to execute.
* @return string
*/
public function buildCommand()
{
$command = PHP_BINDIR . "/php "
. "./processmaker "
. "'populate-table' "
. "'{$this->workspace}' "
. base64_encode($this->sql) . " "
. ($this->isRbac ? "'1'" : "'0'");
return $command;
}
}

View File

@@ -1,92 +0,0 @@
<?php
namespace ProcessMaker\Core;
class MultiProcOpen
{
/**
* Represents the waiting time before starting the process monitoring.
* @var integer
*/
private $sleepTime = 1;
/**
* This method obtains a paging by returning the start and limit indexes
* compatible with the mysql pagination in its call function.
* The return function must return an instance of the object "ProcessMaker\Core\ProcOpen".
* Returns an array containing the status, content, and errors generated by
* the open process.
* @param int $size
* @param int $chunk
* @param callable $callback
* @return array
*/
public function chunk(int $size, int $chunk, callable $callback): array
{
$start = 0;
$limit = $chunk;
$queries = [];
for ($i = 1; $start < $size; $i++) {
$queries[] = $callback($size, $start, $limit);
$start = $i * $limit;
}
return $this->run($queries);
}
/**
* Open a set of background processes.
* The array must contain one or more instances of the object inherited from
* the class "ProcessMaker\Core\ProcOpen"
* Returns an array containing the status, content, and errors generated by
* the open process.
* @param array $processes
* @return array
*/
public function run(array $processes): array
{
foreach ($processes as $procOpen) {
$procOpen->open();
}
return $this->processMonitoring($processes);
}
/**
* It monitors the open processes, verifying if they have ended or thrown an
* error and later closing the resources related to the process.
* Returns an array containing the status, content, and errors generated by
* the open process.
* @param array $processes
* @return array
*/
private function processMonitoring(array $processes): array
{
sleep($this->sleepTime); //this sleep is very important
$i = 0;
$n = count($processes);
if ($n === 0) {
return [];
}
$outputs = [];
do {
$index = $i % $n;
if (isset($processes[$index])) {
$procOpen = $processes[$index];
$status = $procOpen->getStatus();
$contents = $procOpen->getContents();
$errors = $procOpen->getErrors();
if ($status->running === false || !empty($errors)) {
$outputs[] = [
"status" => $status,
"contents" => $contents,
"errors" => $errors,
];
$procOpen->terminate();
$procOpen->close();
unset($processes[$index]);
}
}
$i = $i + 1;
} while (!empty($processes));
return $outputs;
}
}

View File

@@ -1,126 +0,0 @@
<?php
namespace ProcessMaker\Core;
class ProcOpen
{
private $command;
private $resource;
private $descriptorspec;
private $pipes;
private $cwd;
/**
* This initializes the descriptors and the command for the open process.
* @param string $command
*/
public function __construct(string $command)
{
$this->descriptorspec = [
['pipe', 'r'],
['pipe', 'w'],
['pipe', 'w']
];
$this->command = $command;
}
/**
* Gets the resource that represents the process.
* @return resource
*/
public function getResource()
{
return $this->resource;
}
/**
* Sets the process execution directory.
* @param string $cwd
*/
public function setCwd(string $cwd)
{
$this->cwd = $cwd;
}
/**
* Open a background process.
*/
public function open()
{
if (empty($this->cwd)) {
$this->resource = proc_open($this->command, $this->descriptorspec, $this->pipes);
} else {
$this->resource = proc_open($this->command, $this->descriptorspec, $this->pipes, $this->cwd);
}
}
/**
* Get the content of the process when it is finished.
* @return string
*/
public function getContents()
{
if (is_resource($this->pipes[1])) {
return stream_get_contents($this->pipes[1]);
}
return "";
}
/**
* Get the process errors when it is finished.
* @return string
*/
public function getErrors()
{
if (is_resource($this->pipes[2])) {
return stream_get_contents($this->pipes[2]);
}
return "";
}
/**
* Close the resources related to the open process.
* return void
*/
public function close()
{
if (is_resource($this->resource)) {
foreach ($this->pipes as $value) {
fclose($value);
}
proc_close($this->resource);
}
}
/**
* End the process before it ends.
*/
public function terminate()
{
if (is_resource($this->resource)) {
proc_terminate($this->resource);
}
}
/**
* Gets the status of the process.
* @return object
*/
public function getStatus()
{
$status = [
"command" => $this->command,
"pid" => null,
"running" => false,
"signaled" => false,
"stopped" => false,
"exitcode" => -1,
"termsig" => 0,
"stopsig" => 0
];
if (is_resource($this->resource)) {
$status = proc_get_status($this->resource);
}
return (object) $status;
}
}

View File

@@ -77,7 +77,9 @@ 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,
'report_table_batch_regeneration' => 1000
];
/**

View File

@@ -72,8 +72,21 @@ class ProcessVariables extends Model
*/
public function scopeProcessId($query, int $proId)
{
return $query->where('PRO_ID', $proId);
return $query->where('PROCESS_VARIABLES.PRO_ID', $proId);
}
/**
* Scope a query to filter a specific type for variable
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param int $typeId
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeTypeId($query, int $typeId)
{
return $query->where('VAR_FIELD_TYPE_ID', $typeId);
}
/**
* Return the variables list
*
@@ -96,4 +109,46 @@ class ProcessVariables extends Model
return $variablesList;
}
/**
* Return the variables list
*
* @param int $proId
* @param int $typeId
* @param int $start
* @param int $limit
* @param string $search
*
* @return array
*/
public static function getVariablesByType(int $proId, int $typeId = 0, $start = null, $limit = null, $search = null)
{
$query = ProcessVariables::query()->select();
$query->leftJoin('DB_SOURCE', function ($join) {
$join->on('DB_SOURCE.PRO_ID', '=', 'PROCESS_VARIABLES.PRO_ID');
});
$query->processId($proId);
// Check if we need to filter the type of variables
if ($typeId > 0) {
$query->typeId($typeId);
}
// search a specific variable name
if (!empty($search)) {
$query->where('VAR_NAME', 'LIKE', "${search}%");
}
// order by varNane
$query->orderBy('VAR_NAME', 'ASC');
// Check if we need to add a pagination
if(!is_null($start) && !is_null($limit)) {
$query->offset($start)->limit($limit);
}
// Get records
$results = $query->get();
$variablesList = [];
$results->each(function ($item, $key) use (&$variablesList) {
$variablesList[] = $item->toArray();
});
return $variablesList;
}
}

View File

@@ -1,8 +1,12 @@
<?php
namespace ProcessMaker\Services\Api\Project;
use \ProcessMaker\Services\Api;
use \Luracast\Restler\RestException;
use Exception;
use G;
use Luracast\Restler\RestException;
use ProcessMaker\BusinessModel\Variable as BmVariable;
use ProcessMaker\Services\Api;
/**
* Project\Variable Api Controller
*
@@ -28,6 +32,43 @@ class Variable extends Api
}
}
/**
* Get variables by type
*
* @url GET /:prj_uid/process-variables/:typeVariable/paged
*
* @param string $prj_uid {@min 32}{@max 32}
* @param string $typeVariable {@from path}
* @param int $start {@from path}
* @param int $limit {@from path}
* @param string $search {@from path}
*/
public function doGetVariablesByType($prj_uid, $typeVariable, $start = null, $limit = null, $search = null)
{
try {
$variable = new BmVariable();
$typesAccepted = $variable::$varTypesValues;
if (!empty($typesAccepted[$typeVariable])) {
$typeVatId = $typesAccepted[$typeVariable];
} else {
throw new Exception(G::LoadTranslation("ID_INVALID_VALUE_ONLY_ACCEPTS_VALUES", ['$typeVariable', implode(',', $variable->getVariableTypes())]));
}
// Review if the word has the prefix
$count = preg_match_all('/\@(?:([\@\%\#\?\$\=\&Qq\!])|([a-zA-Z\_][\w\-\>\:]*)\(((?:[^\\\\\)]*(?:[\\\\][\w\W])?)*)\))((?:\s*\[[\'"]?\w+[\'"]?\])+|\-\>([a-zA-Z\_]\w*))?/', $search, $match, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE);
// Check if the search has some prefix
$prefix = '';
if ($count) {
$prefix = substr($search,0,2);
$search = substr($search,2);
}
$response = $variable->getVariablesByType($prj_uid, $typeVatId, $start, $limit, $search, $prefix);
return $response;
} catch (Exception $e) {
throw (new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage()));
}
}
/**
* @url GET /:prj_uid/process-variable/:var_uid
*