Questions and discussion about developing processes and programming in PHP, JavaScript, web services & REST API.
Forum rules: Please search to see if a question has already asked before creating a new topic. Please don't post the same question in multiple forums.
#814201
API error to fetch GRID report table data.
I am trying via API to create a report table of type GRID but when trying to save it returns the error below:
erro.png
erro.png (7.48 KiB) Viewed 4357 times
I'm using this API:
api.PNG
api.PNG (45.25 KiB) Viewed 4357 times
Last edited by marcosfpa on Mon May 14, 2018 3:39 pm, edited 1 time in total.
#814275
I looked through the code and found that the endpoint was designed for processes from ProcessMaker version 2.X. It doesn't retrieve the field names for the BPMN DynaForms in ProcessMaker 3.

Here is what you have to do to fix it. Edit workflow/engine/src/ProcessMaker/Services/Api/Project/ReportTable.php and change the definition of the doPostReportTableI() function to:
Code: Select all
    /**
     * @param string $prj_uid {@min 32} {@max 32}
     * @param array $fields {@from body}
     *
     * @param string $rep_tab_name {@from body}
     * @param string $rep_tab_dsc {@from body}
     * @param string $rep_tab_connection {@from body}
     * @param string $rep_tab_type {@from body} {@choice NORMAL,GRID}
     * @param string $rep_tab_grid {@from body}
     * @return array
     *
     * @author Brayan Pereyra (Cochalo) <brayan@colosa.com>
     * @copyright Colosa - Bolivia
     *
     * @url POST /:prj_uid/report-table
     * @status 201
     */
    public function doPostReportTable(
        $prj_uid,
        $fields,
        $rep_tab_name,
        $rep_tab_dsc,
        $rep_tab_connection,
        $rep_tab_type,
        $rep_tab_grid = ''
    ) {
        try {
            $oReportTable = new \ProcessMaker\BusinessModel\Table();
            
            $aTableData = array( 
                'REP_TAB_NAME'       => $rep_tab_name,
                'REP_TAB_DSC'        => $rep_tab_dsc,
                'REP_TAB_CONNECTION' => $rep_tab_connection,
                'REP_TAB_TYPE'       => $rep_tab_type,
                'REP_TAB_GRID'       => $rep_tab_grid,
                'FIELDS'             => $fields
            );
            
            $response = $oReportTable->saveTable($aTableData, $prj_uid, true);
            if (isset($response['pro_uid'])) {
                unset($response['pro_uid']);
            }
            return $response;
        } catch (\Exception $e) {
            throw (new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage()));
        }
    }
Then, edit workflow/engine/src/ProcessMaker/BusinessModel/Table.php and in the saveTable() function, change these lines from:
Code: Select all
            if (isset($columns[$i]['fld_size'])) {
                $columns[$i]['field_size'] = $columns[$i]['fld_size'];
                if (!is_int($columns[$i]['field_size'])) {
                    throw (new \Exception("The property fld_size: '". $columns[$i]['field_size'] . "' is incorrect numeric value."));
                } else {
                    $columns[$i]['field_size'] = (int)$columns[$i]['field_size'];
                }
                unset($columns[$i]['fld_size']);
            }
To:
Code: Select all
            if (isset($columns[$i]['fld_size'])) {
                if (is_string($columns[$i]['fld_size']) and preg_match('/^[0-9]+$/', $columns[$i]['fld_size'])) {
                    $columns[$i]['fld_size'] = (int) $columns[$i]['fld_size'];
                }
                $columns[$i]['field_size'] = $columns[$i]['fld_size'];
                if (!is_int($columns[$i]['field_size'])) {
                    throw (new \Exception("The property fld_size: '". $columns[$i]['field_size'] . "' is incorrect numeric value."));
                } else {
                    $columns[$i]['field_size'] = (int)$columns[$i]['field_size'];
                }
                unset($columns[$i]['fld_size']);
            }
In the same file, edit the getDynafields() function and change its definition to:
Code: Select all
    public function getDynafields ($pro_uid, $rep_tab_type, $rep_tab_grid = '')
    {
        G::LoadClass( 'reportTables' );

        $dynFields = array();
        $aFields   = array();
        $aFields['FIELDS']  = array();
        $aFields['PRO_UID'] = $pro_uid;
        
        //ABB edit starts:
        $oProcess = new \Process();
        $aProcessInfo = $oProcess->Load($pro_uid);
         
        //if a BPMN process: 
        if ($aProcessInfo['PRO_BPMN'] == 1) {
            $oTableData = new \stdClass();
            $oTableData->PRO_UID  = $pro_uid;
            $oTableData->TYPE     = $rep_tab_type;
            $oTableData->GRID_UID = $rep_tab_grid;
            
            require_once PATH_HOME.'engine'.PATH_SEP.'controllers'.PATH_SEP.'pmTablesProxy.php';
            $oPmTable = new \pmTablesProxy();
            $aDynaFields = $oPmTable->getDynafields($oTableData);
            $dynFields = $aDynaFields['rows'];
        }
        else { //if a classic process:    
            if (isset( $rep_tab_type ) && $rep_tab_type == 'GRID') {
                list ($gridName, $gridId) = explode( '-', $rep_tab_grid );
                $dynFields = $this->_getDynafields($pro_uid, 'grid', $gridId);
            } else {
                $dynFields = $this->_getDynafields($pro_uid, 'xmlform');
            }
        }
        //ABB edit ends

        $fieldReturn = array();
        foreach ($dynFields as $value) {
            $fieldReturn['NAMES'][]  = $value['FIELD_NAME'];
            $fieldReturn['UIDS'][]   = $value['FIELD_UID'];
            $fieldReturn['INDEXS'][] = $value['_index'];
        }
        return $fieldReturn;
    }
Finally, change the definition of the validateRepGrid() function to:
Code: Select all
    public function validateRepGrid ($rep_tab_grid, $pro_uid)
    {
        $rep_tab_grid = trim($rep_tab_grid);
        if ($rep_tab_grid == '') {
            throw (new \Exception("The property rep_tab_grid: '$rep_tab_grid' is empty."));
        }
        
        list($gridId, $dynaformId) = explode('-', $rep_tab_grid);
        
        if (empty($dynaformId)) {
            throw new \Exception("The rep_tab_grid '$rep_tab_grid' should have 'gridID-dynaformUID', ".
                "such as 'clientsList-8381991475aac246e1a7e02065872683'");
        }
        
        $oProcess = new \Process();
        $aProcessInfo = $oProcess->Load($pro_uid);
         
        //if a BPMN process: 
        if (isset($aProcessInfo['PRO_BPMN']) and $aProcessInfo['PRO_BPMN'] == 1) {        
            G::loadClass("pmDynaform");
            //$oDynaform = new \pmDynaform(\ProcessMaker\Util\DateTime::convertUtcToTimeZone($data));
            $oDynaform = new \pmDynaform(array());
            $aField = $oDynaform->searchField($dynaformId, $gridId, $pro_uid);
            
            if (!isset($aField->type) or $aField->type != 'grid') {
                throw new \Exception("The property rep_tab_grid: '$rep_tab_grid' is incorrect.");
            }
            return $rep_tab_grid;
        }
        else { //if a classic process:

            G::loadSystem('dynaformhandler');
            $grids = array();
            $namesGrid = array();
            $aFieldsNames = array();

            $oCriteria = new \Criteria( 'workflow' );
            $oCriteria->addSelectColumn( \DynaformPeer::DYN_FILENAME );
            $oCriteria->add( \DynaformPeer::PRO_UID, $pro_uid );
            $oCriteria->add( \DynaformPeer::DYN_TYPE, 'xmlform' );
            $oDataset = \DynaformPeer::doSelectRS( $oCriteria );
            $oDataset->setFetchmode( \ResultSet::FETCHMODE_ASSOC );

            while ($oDataset->next()) {
                $aRow = $oDataset->getRow();
                $dynaformHandler = new \dynaformHandler( PATH_DYNAFORM . $aRow['DYN_FILENAME'] . '.xml' );
                $nodeFieldsList = $dynaformHandler->getFields();
                foreach ($nodeFieldsList as $node) {
                    $arrayNode = $dynaformHandler->getArray( $node );
                    $fieldName = $arrayNode['__nodeName__'];
                    $fieldType = $arrayNode['type'];
                    if ($fieldType == 'grid') {
                        if (! in_array( $fieldName, $aFieldsNames )) {
                            $namesGrid[] = $fieldName;
                            $grids[] = str_replace( $pro_uid . '/', '', $arrayNode['xmlgrid']);
                        }
                    }
                }
            }
        
            $find = array_search($rep_tab_grid, $grids);
            if ($find === false) {
                throw (new \Exception("The property rep_tab_grid: '$rep_tab_grid' is incorrect."));
            } else {
                $rep_tab_grid = $namesGrid[$find] . '-' . $rep_tab_grid;
            }
            return $rep_tab_grid;
        }
    }
Make sure that you make backup copies of these files, just in case you need to return them to their original state.

After you make these changes, it should be possible to call the endpoint like this in PHP:
Code: Select all
        $processId = '2834197345a2a09e94b2ed5000427983';
        $url = "/api/1.0/workflow/project/$processId/report-table";
        $aVars = array(
                "rep_tab_name"       => "PMT_TESTREPORT2",
                "rep_tab_dsc"        => "My test table2",
                "rep_tab_connection" => "workflow",
                "rep_tab_type"       => "NORMAL",
                "rep_tab_grid"       => "",
                "fields"             => array(
                        array(
                            "fld_dyn"  => "selectCountry",
                            "fld_name" => "SELECTCOUNTRY",
                            "fld_label"=> "SELECTCOUNTRY",
                            "fld_type" => "VARCHAR",
                            "fld_size" => 255
                        ),
                        array(
                            "fld_dyn"  => "selectCountry_label",
                            "fld_name" => "SELECTCOUNTRY_LABEL",
                            "fld_label"=> "SELECTCOUNTRY_LABEL",
                            "fld_type" => "LONGVARCHAR",
                            "fld_size" => 255
                        )
                )
        );
                
    $oRet = pmRestRequest("POST", $url, $aVars, $oToken->access_token);
    if ($oRet->status == 201) {        
         print json_encode($oRet->response, JSON_PRETTY_PRINT);
    }
The endpoint should return a JSON object like this:
Code: Select all
{
    "rep_uid": "8334430305ae7b4bb75c389011090990",
    "rep_tab_name": "PMT_TESTREPORT2",
    "rep_tab_description": "My test table2",
    "rep_tab_class_name": "PmtTestreport2",
    "rep_tab_connection": "workflow",
    "rep_tab_type": "NORMAL",
    "rep_tab_grid": "",
    "rep_num_rows": 16,
    "fields": [
        {
            "fld_uid": "3532392285ae7b4bb81b935065670486",
            "fld_index": "0",
            "fld_name": "APP_UID",
            "fld_description": "APP_UID",
            "fld_type": "VARCHAR",
            "fld_size": "32",
            "fld_null": "0",
            "fld_auto_increment": "0",
            "fld_key": "1",
            "fld_table_index": "0"
        },
        {
            "fld_uid": "1013578315ae7b4bba167c0047777423",
            "fld_index": "1",
            "fld_name": "APP_NUMBER",
            "fld_description": "APP_NUMBER",
            "fld_type": "INTEGER",
            "fld_size": "11",
            "fld_null": "0",
            "fld_auto_increment": "0",
            "fld_key": "0",
            "fld_table_index": "0"
        },
        {
            "fld_uid": "9489932165ae7b4bbb70597011842701",
            "fld_index": "2",
            "fld_name": "APP_STATUS",
            "fld_description": "APP_STATUS",
            "fld_type": "VARCHAR",
            "fld_size": "10",
            "fld_null": "0",
            "fld_auto_increment": "0",
            "fld_key": "0",
            "fld_table_index": "0"
        },
        {
            "fld_uid": "5031677935ae7b4bbc1eab1002468046",
            "fld_index": "3",
            "fld_name": "SELECTCOUNTRY",
            "fld_description": "SELECTCOUNTRY",
            "fld_type": "VARCHAR",
            "fld_size": "255",
            "fld_null": "1",
            "fld_auto_increment": "0",
            "fld_key": "0",
            "fld_table_index": "0"
        },
        {
            "fld_uid": "8795062015ae7b4bbccd336040096800",
            "fld_index": "4",
            "fld_name": "SELECTCOUNTRY_LABEL",
            "fld_description": "SELECTCOUNTRY_LABEL",
            "fld_type": "LONGVARCHAR",
            "fld_size": "255",
            "fld_null": "1",
            "fld_auto_increment": "0",
            "fld_key": "0",
            "fld_table_index": "0"
        }
    ]
}
The following PHP code creates a grid table:
Code: Select all
        $processId = '2834197345a2a09e94b2ed5000427983';
        $url = "/api/1.0/workflow/project/$processId/report-table";
        $aVars = array(
                "rep_tab_name"       => "PMT_TESTGRID",
                "rep_tab_dsc"        => "My test grid table",
                "rep_tab_connection" => "workflow",
                "rep_tab_type"       => "GRID",
                                               //set to: //ID of the grid field, hyphen, the ID of the Dynaform
                "rep_tab_grid"       => "clientList-5757604865a2a0bba6db081073294722", 
                "fields"             => array(
                        array(  //text field
                                "fld_dyn"   => "clientBusiness",
                                "fld_name"  => "CLIENTBUSINESS",
                                "fld_label" => "CLIENTBUSINESS",
                                "fld_type"  => "VARCHAR",
                                "fld_size"  => "32"
                        ),
                        array(  //checkbox field
                                "fld_dyn"   => "renewableContract",
                                "fld_name"  => "RENEWABLECONTRACT",
                                "fld_label" => "RENEWABLECONTRACT",
                                "fld_type"  => "VARCHAR",
                                "fld_size"  => "32"
                        ),
                        array(  //datetime field
                                "fld_dyn"   => "startContract",
                                "fld_name"  => "STARTCONTRACT",
                                "fld_label" => "STARTCONTRACT",
                                "fld_type"  => "VARCHAR",
                                "fld_size"  => "10"
                        )
                )
        );
                
    $oRet = pmRestRequest("POST", $url, $aVars, $oToken->access_token);
        if ($oRet->status == 201) {        
            print json_encode($oRet->response, JSON_PRETTY_PRINT);
        }
It will return an HTTP status code of 201 and a JSON object like this:
Code: Select all
{
    "rep_uid": "8498804145ae9df18c2cd17092132199",
    "rep_tab_name": "PMT_TESTGRID",
    "rep_tab_description": "My test grid table",
    "rep_tab_class_name": "PmtTestgrid",
    "rep_tab_connection": "workflow",
    "rep_tab_type": "GRID",
    "rep_tab_grid": "clientList-5757604865a2a0bba6db081073294722",
    "rep_num_rows": 5,
    "fields": [
        {
            "fld_uid": "9080505325ae9df18d1d2c4035027659",
            "fld_index": "0",
            "fld_name": "APP_UID",
            "fld_description": "APP_UID",
            "fld_type": "VARCHAR",
            "fld_size": "32",
            "fld_null": "0",
            "fld_auto_increment": "0",
            "fld_key": "1",
            "fld_table_index": "0"
        },
        {
            "fld_uid": "4810370165ae9df18de04e0011144952",
            "fld_index": "1",
            "fld_name": "APP_NUMBER",
            "fld_description": "APP_NUMBER",
            "fld_type": "INTEGER",
            "fld_size": "11",
            "fld_null": "0",
            "fld_auto_increment": "0",
            "fld_key": "0",
            "fld_table_index": "0"
        },
        {
            "fld_uid": "8184071345ae9df18eba160041724843",
            "fld_index": "2",
            "fld_name": "APP_STATUS",
            "fld_description": "APP_STATUS",
            "fld_type": "VARCHAR",
            "fld_size": "10",
            "fld_null": "0",
            "fld_auto_increment": "0",
            "fld_key": "0",
            "fld_table_index": "0"
        },
        {
            "fld_uid": "9074760415ae9df190268d7047619137",
            "fld_index": "3",
            "fld_name": "ROW",
            "fld_description": "ROW",
            "fld_type": "INTEGER",
            "fld_size": "11",
            "fld_null": "0",
            "fld_auto_increment": "0",
            "fld_key": "1",
            "fld_table_index": "0"
        },
        {
            "fld_uid": "4359563975ae9df19156df5073260757",
            "fld_index": "4",
            "fld_name": "CLIENTBUSINESS",
            "fld_description": "CLIENTBUSINESS",
            "fld_type": "VARCHAR",
            "fld_size": "32",
            "fld_null": "1",
            "fld_auto_increment": "0",
            "fld_key": "0",
            "fld_table_index": "0"
        },
        {
            "fld_uid": "8361015265ae9df19205451037885929",
            "fld_index": "5",
            "fld_name": "RENEWABLECONTRACT",
            "fld_description": "RENEWABLECONTRACT",
            "fld_type": "VARCHAR",
            "fld_size": "32",
            "fld_null": "1",
            "fld_auto_increment": "0",
            "fld_key": "0",
            "fld_table_index": "0"
        },
        {
            "fld_uid": "4952554685ae9df19335c90058100505",
            "fld_index": "6",
            "fld_name": "STARTCONTRACT",
            "fld_description": "STARTCONTRACT",
            "fld_type": "VARCHAR",
            "fld_size": "10",
            "fld_null": "1",
            "fld_auto_increment": "0",
            "fld_key": "0",
            "fld_table_index": "0"
        }
    ]
}
The Report Table should be filled with the data from the existing cases:
TestGridRestResult.png
TestGridRestResult.png (64.6 KiB) Viewed 4312 times
Let me know if you encounter any problems.
#814299
.xml files are always empty for Dynaforms in BPMN processes, but not for classic processes from ProcessMaker 2.
I tested the code changes I gave you in PM 3.2.1 Community (manual install in Debian 8.4 with PHP 5.6.20) with several BPMN processes What version of PM are you using?

Did you replace the code for validateRepGrid()? (I added that part later after the initial post.)

Post the code you are using to call the endpoint.
Want to create your own meme coin?

In the world of cryptocurrencies, a unique and exc[…]

The market for cryptocurrencies is demonstrating a[…]

What's SAP FICO?

Embarking on a dissertation can be one of the most[…]

Hello. For rental housing, there are software solu[…]