diff --git a/CHANGELOG.md b/CHANGELOG.md
index cac4328086b13487cbc82f0535a0a655d8fa69cb..72e42c8fc2fffeb61989a193988277c874cc67ab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+# Master version (in development)
+
+* Respect selected permissions for outputs 
+* Allow to specify "Is Empty" for various filters.
+* Allow to limit ContactFilter to only show contacts from specific groups.
+* it is now also possible to output a data processor on CiviCRMs dahsboard.
+* Added field outputs for simple calculations (substract and total).
+
+# Version 1.0.2
+
+* Fixed bug #11 (Fatal error clone on non object)
+
 # Version 1.0.1
 
 Initial release.
\ No newline at end of file
diff --git a/CRM/Contact/DataProcessorContactSearch.php b/CRM/Contact/DataProcessorContactSearch.php
index b5dd908bccd1bbac9868faded217564f844f8ece..2227c2830017d6436d51cb174d93827a41f31da3 100644
--- a/CRM/Contact/DataProcessorContactSearch.php
+++ b/CRM/Contact/DataProcessorContactSearch.php
@@ -35,7 +35,16 @@ class CRM_Contact_DataProcessorContactSearch implements UIOutputInterface {
       $fields[$field->alias] = $field->title;
     }
 
-    $form->add('text', 'title', E::ts('Title'), true);
+    $form->add('text', 'title', E::ts('Title'),NULL, true);
+    
+    // form elements for adding Dashlet
+    // $output['dashlet'] 1-> Yes 2->No
+
+    if(isset($output['dashlet']) && $output['dashlet']==1){
+      $form->add('text', 'dashlet_title', E::ts('Dashlet Title'), NULL, true);
+      $form->add('text', 'dashlet_name', E::ts('Dashlet Name (system name)'), NULL, true);
+      $form->add('select', 'dashlet_active', E::ts('Is Dashlet Active ?'), array(1=>'Yes', 0=> 'No'), true);
+    }
 
     $form->add('select','permission', E::ts('Permission'), \CRM_Core_Permission::basicPermissions(), true, array(
       'style' => 'min-width:250px',
@@ -61,9 +70,15 @@ class CRM_Contact_DataProcessorContactSearch implements UIOutputInterface {
 
     $defaults = array();
     if ($output) {
+      
       if (isset($output['permission'])) {
         $defaults['permission'] = $output['permission'];
       }
+      if (isset($output['dashlet_name'])) {
+        $defaults['dashlet_name'] = $output['dashlet_name'];
+        $defaults['dashlet_title'] = $output['dashlet_title'];
+        $defaults['dashlet_active'] = $output['dashlet_active'];
+      }
       if (isset($output['configuration']) && is_array($output['configuration'])) {
         if (isset($output['configuration']['contact_id_field'])) {
           $defaults['contact_id_field'] = $output['configuration']['contact_id_field'];
@@ -88,6 +103,7 @@ class CRM_Contact_DataProcessorContactSearch implements UIOutputInterface {
     if (empty($defaults['title'])) {
       $defaults['title'] = civicrm_api3('DataProcessor', 'getvalue', array('id' => $output['data_processor_id'], 'return' => 'title'));
     }
+    
     $form->setDefaults($defaults);
   }
 
@@ -119,6 +135,25 @@ class CRM_Contact_DataProcessorContactSearch implements UIOutputInterface {
     return $configuration;
   }
 
+  /**
+   * Process the submitted values and create a configuration array
+   *
+   * @param $submittedValues
+   * @param array $output
+   * @return array
+   */
+  public function processDashletConfiguration($submittedValues) {
+
+    $configuration['domain_id'] = 1;
+    $configuration['name'] = $submittedValues['dashlet_name'];
+    $configuration['label'] = $submittedValues['dashlet_title'];
+    $configuration['permission'] = $submittedValues['permission'];
+    $configuration['is_active'] = $submittedValues['dashlet_active'];
+    $configuration['cache_minutes'] = 60;
+
+    return $configuration;
+  }
+
   /**
    * Returns the url for the page/form this output will show to the user
    *
diff --git a/CRM/Dataprocessor/Form/FilterValue.php b/CRM/Dataprocessor/Form/FilterValue.php
index 6dbdb2e44c635a8aa04b97ac4732b5d503d29669..585ae2bc0f63ddc29bb383f6c49b1923ec4fb77c 100644
--- a/CRM/Dataprocessor/Form/FilterValue.php
+++ b/CRM/Dataprocessor/Form/FilterValue.php
@@ -55,7 +55,6 @@ class CRM_Dataprocessor_Form_FilterValue extends CRM_Core_Form {
 
 
     $this->filter = civicrm_api3('DataProcessorFilter', 'getsingle', array('id' => $this->id));
-    $this->assign('filter', $this->filter);
     $this->filterTypeClass = $factory->getFilterByName($this->filter['type']);
     $this->filterTypeClass->setDataProcessor($this->dataProcessorClass);
     $this->filterTypeClass->initialize($this->filter);
@@ -68,7 +67,8 @@ class CRM_Dataprocessor_Form_FilterValue extends CRM_Core_Form {
     $this->add('hidden', 'data_processor_id');
     $this->add('hidden', 'id');
 
-    $this->filterTypeClass->addToFilterForm($this, $this->filter['filter_value']);
+    $filter = $this->filterTypeClass->addToFilterForm($this, $this->filter['filter_value']);
+    $this->assign('filter', $filter);
     $this->assign('filter_template', $this->filterTypeClass->getTemplateFileName());
 
     $this->addButtons(array(
diff --git a/CRM/Dataprocessor/Form/Output.php b/CRM/Dataprocessor/Form/Output.php
index cea74b394ba643182208d863d028161f6ca7ee2f..1fc2c49366a12e861a21298462b728b5e318e3a0 100644
--- a/CRM/Dataprocessor/Form/Output.php
+++ b/CRM/Dataprocessor/Form/Output.php
@@ -13,6 +13,10 @@ class CRM_Dataprocessor_Form_Output extends CRM_Core_Form {
 
   private $id;
 
+  private $dashlet;
+
+  private $dashlet_id;
+
   private $output;
 
   /**
@@ -28,7 +32,9 @@ class CRM_Dataprocessor_Form_Output extends CRM_Core_Form {
    * @access public
    */
   function preProcess() {
+
     $this->snippet = CRM_Utils_Request::retrieve('snippet', 'String');
+
     if ($this->snippet) {
       $this->assign('suppressForm', TRUE);
       $this->controller->_generateQFKey = FALSE;
@@ -41,11 +47,34 @@ class CRM_Dataprocessor_Form_Output extends CRM_Core_Form {
     $this->id = CRM_Utils_Request::retrieve('id', 'Integer');
     $this->assign('id', $this->id);
 
+    $dashlet = CRM_Utils_Request::retrieve('dashlet', 'Integer');
+    // dashlet 1->Yes 2->No
+
     if ($this->id) {
       $this->output = civicrm_api3('DataProcessorOutput', 'getsingle', array('id' => $this->id));
       $this->assign('output', $this->output);
       $this->outputTypeClass = $factory->getOutputByName($this->output['type']);
       $this->assign('has_configuration', $this->outputTypeClass->hasConfiguration());
+
+
+      // Check for Dashlet
+      $dashlet_url = $this->createDashletUrl($this->id,$this->dataProcessorId);
+      try{
+        $result_dashlet = civicrm_api3('Dashboard', 'getsingle', [
+          'url' => $dashlet_url,
+        ]);
+        $this->dashlet = 1;
+        $this->dashlet_id = $result_dashlet['id'];
+        $this->output['dashlet'] = $this->dashlet;
+        $this->output['dashlet_name'] = $result_dashlet['name'];
+        $this->output['dashlet_title'] = $result_dashlet['label'];
+        $this->output['dashlet_active'] = $result_dashlet['is_active'];
+      }
+      catch(Exception $e){
+        $this->dashlet = 2;
+        $this->output['dashlet'] = $this->dashlet;
+      }
+
     }
 
     $type = CRM_Utils_Request::retrieve('type', 'String');
@@ -57,6 +86,10 @@ class CRM_Dataprocessor_Form_Output extends CRM_Core_Form {
     if (!$this->output) {
       $this->output['data_processor_id'] = $this->dataProcessorId;
     }
+    if($dashlet){
+      $this->dashlet = $dashlet;
+      $this->output['dashlet'] = $this->dashlet;
+    }
 
     $title = E::ts('Data Processor Output');
     CRM_Utils_System::setTitle($title);
@@ -73,7 +106,7 @@ class CRM_Dataprocessor_Form_Output extends CRM_Core_Form {
       $factory = dataprocessor_get_factory();
       $types = array(' - select - ')  + $factory->getOutputs();
       $this->add('select', 'type', ts('Select output'), $types, true, array('class' => 'crm-select2'));
-
+      $this->add('select', 'dashlet', E::ts('Add Output as Dashlet'), array(''=>' - select - ', 1=>'Yes', 2=> 'No'), true,array('id' => 'dashlet'));
       if ($this->outputTypeClass && $this->outputTypeClass->hasConfiguration()) {
         $this->outputTypeClass->buildConfigurationForm($this, $this->output);
         $this->assign('configuration_template', $this->outputTypeClass->getConfigurationTemplateFileName());
@@ -94,6 +127,9 @@ class CRM_Dataprocessor_Form_Output extends CRM_Core_Form {
     if (isset($this->output['type'])) {
       $defaults['type'] = $this->output['type'];
     }
+    if (isset($this->output['dashlet'])) {
+      $defaults['dashlet'] = $this->output['dashlet'];
+    }
     return $defaults;
   }
 
@@ -132,10 +168,41 @@ class CRM_Dataprocessor_Form_Output extends CRM_Core_Form {
       $params['id'] = $this->id;
     }
     $params['configuration'] = $this->outputTypeClass->processConfiguration($values, $params);
+    
     $result = civicrm_api3('DataProcessorOutput', 'create', $params);
+    
+    if($this->dashlet == 1){
+
+      $dashlet_params = $this->outputTypeClass->processDashletConfiguration($values);
+      $dashlet_params['url'] = $this->createDashletUrl($result['id'],$this->dataProcessorId);
+      if ($this->dashlet_id) {
+        $dashlet_params['id'] = $this->dashlet_id;
+      }
+      $dashlet_result = civicrm_api3('Dashboard', 'create', $dashlet_params);
+    }
+    elseif($this->dashlet == 2){
+      if ($this->dashlet_id) {
+        $dashlet_params['id'] = $this->dashlet_id;
+        $dashlet_result = civicrm_api3('Dashboard', 'delete', $dashlet_params); 
+      }
+    }
 
     CRM_Utils_System::redirect($redirectUrl);
     parent::postProcess();
   }
 
+  /**
+   * Returns the url for the dashlet url
+   *
+   * @param array $outputId
+   * @param array $dataProcessorId
+   * @return string
+   */
+
+  public function createDashletUrl($outputId,$dataProcessorId){
+    $url = CRM_Utils_System::url('civicrm/dataprocessor/form/dashlet', array('outputId' => $outputId, 'dataProcessorId' => $dataProcessorId));
+    //substr is used to remove starting slash
+    return substr($url, 1);
+  }
+
 }
diff --git a/CRM/Dataprocessor/Form/Output/AbstractUIOutputForm.php b/CRM/Dataprocessor/Form/Output/AbstractUIOutputForm.php
index eae35dd66e1b571adf9398f67b71f19022b4f364..250755c5e2c3adf1a29cd226d83385bb26a81be8 100644
--- a/CRM/Dataprocessor/Form/Output/AbstractUIOutputForm.php
+++ b/CRM/Dataprocessor/Form/Output/AbstractUIOutputForm.php
@@ -131,6 +131,9 @@ abstract class CRM_Dataprocessor_Form_Output_AbstractUIOutputForm extends CRM_Co
       foreach ($dataProcessor->getFilterHandlers() as $filter) {
         if ($filter->isExposed()) {
           $filterValues = $filter->processSubmittedValues($submittedValues);
+          if (empty($filterValues)) {
+            $filterValues = $filter->getDefaultFilterValues();
+          }
           $filter->applyFilterFromSubmittedFilterParams($filterValues);
         }
       }
diff --git a/CRM/Dataprocessor/Page/AJAX.php b/CRM/Dataprocessor/Page/AJAX.php
new file mode 100644
index 0000000000000000000000000000000000000000..c6521c18338b3d3e0a8de159369bb7fd3d29f0bf
--- /dev/null
+++ b/CRM/Dataprocessor/Page/AJAX.php
@@ -0,0 +1,71 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 5                                                  |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2019                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM 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 and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2019
+ *
+ */
+
+/**
+ * This class contains all contact related functions that are called using AJAX (jQuery)
+ */
+class CRM_Dataprocessor_Page_AJAX {
+
+  public static function getDashlet() {
+
+  	$outputId = CRM_Utils_Request::retrieve('outputId', 'Integer');
+  	$dataProcessorId = CRM_Utils_Request::retrieve('dataProcessorId', 'Integer');
+  	$dataProcessor = civicrm_api3('DataProcessor', 'getsingle', array('id' => $dataProcessorId));
+  	$dataProcessorClass = CRM_Dataprocessor_BAO_DataProcessor::dataProcessorToClass($dataProcessor);
+
+  	$results = [];
+
+  	try {
+      while($record = $dataProcessorClass->getDataFlow()->nextRecord()) {
+			$row = array();
+			$row['record'] = $record;
+			$result = array();
+			foreach($record as $key => $value) {
+				$result[$key] = $value->formattedValue;
+			}
+
+			$results[] = $result;
+        }
+    }
+     catch (\Civi\DataProcessor\DataFlow\EndOfFlowException $e) {
+      // Do nothing
+    }  	
+
+    $return_output['data'] = $results;
+    
+    CRM_Utils_JSON::output($return_output);
+
+  }
+
+}
diff --git a/CRM/Dataprocessor/Page/Dashlet.php b/CRM/Dataprocessor/Page/Dashlet.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f8cc95b0c17c0e12aeefce5460fdc3dafb91228
--- /dev/null
+++ b/CRM/Dataprocessor/Page/Dashlet.php
@@ -0,0 +1,72 @@
+<?php
+
+use CRM_Dataprocessor_ExtensionUtil as E;
+
+/**
+ * Main page for Data Processor Output dashlet
+ *
+ */
+class CRM_Dataprocessor_Page_Dashlet extends CRM_Core_Page {
+  
+  /**
+   * @var int
+   */
+  private $outputId;
+
+  /**
+   * @var int
+   */
+  private $dataProcessorId;
+
+  /**
+   * @var array
+   */
+  private $dataProcessor;
+
+  /**
+   * @var Civi\DataProcessor\ProcessorType\AbstractProcessorType
+   */
+  private $dataProcessorClass;
+
+  /**
+   * Pre Process the results
+   *
+   * @return void
+   */
+
+  protected function preProcess() {
+    $this->outputId = CRM_Utils_Request::retrieve('outputId', 'Integer');
+    $this->dataProcessorId = CRM_Utils_Request::retrieve('dataProcessorId', 'Integer');
+
+    $this->dataProcessor = civicrm_api3('DataProcessor', 'getsingle', array('id' => $this->dataProcessorId));
+    $this->dataProcessorClass = CRM_Dataprocessor_BAO_DataProcessor::dataProcessorToClass($this->dataProcessor);
+    $this->assign('dataProcessorId', $this->dataProcessorId);
+    $this->assign('outputId', $this->outputId);
+  }
+
+  /**
+   * Dataprocessor Output as dashlet.
+   *
+   * @return void
+   */
+
+  public function run() {
+    $this->preProcess();
+    $this->addColumnHeaders();
+
+    return parent::run();
+  }
+
+  /**
+   * Add the headers for the columns
+   *
+   */
+  protected function addColumnHeaders() {
+    $columnHeaders = array();
+    foreach($this->dataProcessorClass->getDataFlow()->getOutputFieldHandlers() as $outputFieldHandler) {
+      $field = $outputFieldHandler->getOutputFieldSpecification();
+      $columnHeaders[$field->alias] = $field->title;
+    }
+    $this->assign('columnHeaders', $columnHeaders);
+  }
+}
diff --git a/CRM/DataprocessorSearch/Controller/CaseSearch.php b/CRM/DataprocessorSearch/Controller/CaseSearch.php
index 9198fc75da1313ca19bb8e54ac777404234496b0..8008084b4dacf808d2f841375dde4b1cce25ddc7 100644
--- a/CRM/DataprocessorSearch/Controller/CaseSearch.php
+++ b/CRM/DataprocessorSearch/Controller/CaseSearch.php
@@ -55,7 +55,7 @@ class CRM_DataprocessorSearch_Controller_CaseSearch extends CRM_Core_Controller
     list($pageName, $action) = $actionName;
     // Hack to replace to userContext for redirecting after a Task has been completed.
     // We want the redirect
-    if (!$this->_pages[$pageName] instanceof CRM_DataprocessorSearch_Form_CaseySearch) {
+    if (!$this->_pages[$pageName] instanceof CRM_DataprocessorSearch_Form_CaseSearch) {
       $session = CRM_Core_Session::singleton();
       $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this);
       $urlPath = CRM_Utils_System::getUrlPath();
diff --git a/CRM/DataprocessorSearch/Form/AbstractSearch.php b/CRM/DataprocessorSearch/Form/AbstractSearch.php
index 953e9db5213df924d83932a6cf2d10a3b93a71af..c06983af790bb79dc7de600c815cddcb08051d16 100644
--- a/CRM/DataprocessorSearch/Form/AbstractSearch.php
+++ b/CRM/DataprocessorSearch/Form/AbstractSearch.php
@@ -249,7 +249,7 @@ abstract class CRM_DataprocessorSearch_Form_AbstractSearch extends CRM_Dataproce
 
         $row['id'] = null;
         if (isset($record[$id_field])) {
-          $row['id'] = $record[$id_field]->formattedValue;
+          $row['id'] = $record[$id_field]->rawValue;
         }
         $row['checkbox'] = CRM_Core_Form::CB_PREFIX.$row['id'];
         $row['record'] = $record;
@@ -269,6 +269,8 @@ abstract class CRM_DataprocessorSearch_Form_AbstractSearch extends CRM_Dataproce
             'data' => $record,
           );
           $ids[] = $row['id'];
+        } else {
+          $ids[] = $row['id'];
         }
 
         $rows[] = $row;
diff --git a/CRM/DataprocessorSearch/Form/ActivitySearch.php b/CRM/DataprocessorSearch/Form/ActivitySearch.php
index e9686ea28e02b38599319c59c72da6c1505cc52f..52467c477de1a602ad1ecf28fbf9a9482f9f82bd 100644
--- a/CRM/DataprocessorSearch/Form/ActivitySearch.php
+++ b/CRM/DataprocessorSearch/Form/ActivitySearch.php
@@ -8,6 +8,15 @@ use CRM_Dataprocessor_ExtensionUtil as E;
 
 class CRM_DataprocessorSearch_Form_ActivitySearch extends CRM_DataprocessorSearch_Form_AbstractSearch {
 
+  /**
+   * The params that are sent to the query.
+   *
+   * @var array
+   */
+  protected $_queryParams;
+
+  protected $activity_ids;
+
 
   /**
    * Returns the name of the default Entity
@@ -99,4 +108,29 @@ class CRM_DataprocessorSearch_Form_ActivitySearch extends CRM_DataprocessorSearc
     return $this->_taskList;
   }
 
+  /**
+   * Return altered rows
+   *
+   * Save the ids into the queryParams value. So that when an action is done on the selected record
+   * or on all records, the queryParams will hold all the activity ids so that in the next step only the selected record, or the first
+   * 50 records are populated.
+   *
+   * @param array $rows
+   * @param array $ids
+   *
+   */
+  protected function alterRows(&$rows, $ids) {
+    $this->activity_ids = $ids;
+    $this->_queryParams[0] = array(
+      'activity_id',
+      '=',
+      array(
+        'IN' => $this->activity_ids,
+      ),
+      0,
+      0
+    );
+    $this->controller->set('queryParams', $this->_queryParams);
+  }
+
 }
\ No newline at end of file
diff --git a/CRM/DataprocessorSearch/ParticipantSearch.php b/CRM/DataprocessorSearch/ParticipantSearch.php
index 92697330383867fa6a2c116352d94a20033e0768..bd71f3b5f959de9d6a3fd2bf2fc6948538c2a823 100644
--- a/CRM/DataprocessorSearch/ParticipantSearch.php
+++ b/CRM/DataprocessorSearch/ParticipantSearch.php
@@ -27,6 +27,7 @@ class CRM_DataprocessorSearch_ParticipantSearch implements UIOutputInterface {
    * @param array $filter
    */
   public function buildConfigurationForm(\CRM_Core_Form $form, $output=array()) {
+
     $navigation = CRM_Dataprocessor_Utils_Navigation::singleton();
     $dataProcessor = civicrm_api3('DataProcessor', 'getsingle', array('id' => $output['data_processor_id']));
     $dataProcessorClass = \CRM_Dataprocessor_BAO_DataProcessor::dataProcessorToClass($dataProcessor);
@@ -36,7 +37,7 @@ class CRM_DataprocessorSearch_ParticipantSearch implements UIOutputInterface {
       $fields[$field->alias] = $field->title;
     }
 
-    $form->add('text', 'title', E::ts('Title'), true);
+    $form->add('text', 'title', E::ts('Title'), NULL,true);
 
     $form->add('select','permission', E::ts('Permission'), \CRM_Core_Permission::basicPermissions(), true, array(
       'style' => 'min-width:250px',
diff --git a/CRM/DataprocessorSearch/Search.php b/CRM/DataprocessorSearch/Search.php
index 5009ae45733ee274a26054c95f883693e3e2049e..ac76532489e51152662ef8db5aed69eafee94e10 100644
--- a/CRM/DataprocessorSearch/Search.php
+++ b/CRM/DataprocessorSearch/Search.php
@@ -49,7 +49,7 @@ class CRM_DataprocessorSearch_Search implements UIOutputInterface {
       'class' => 'crm-select2 huge',
       'placeholder' => E::ts('- select -'),
     ));
-    $form->add('select', 'hide_id_field', E::ts('Show ID field'), array(0=>'ID is Visible', 1=> 'Activity ID is hidden'));
+    $form->add('select', 'hide_id_field', E::ts('Show ID field'), array(0=>'ID is Visible', 1=> 'ID field is hidden'));
 
     $form->add('wysiwyg', 'help_text', E::ts('Help text for this search'), array('rows' => 6, 'cols' => 80));
 
diff --git a/Civi/DataProcessor/DataFlow/CombinedDataFlow/CombinedSqlDataFlow.php b/Civi/DataProcessor/DataFlow/CombinedDataFlow/CombinedSqlDataFlow.php
index 4ee995d9d1a7364f880c80209eeeea11bebe7435..edbf67ab05ca827fbcfa633470641f24e7daf45f 100644
--- a/Civi/DataProcessor/DataFlow/CombinedDataFlow/CombinedSqlDataFlow.php
+++ b/Civi/DataProcessor/DataFlow/CombinedDataFlow/CombinedSqlDataFlow.php
@@ -66,7 +66,9 @@ class CombinedSqlDataFlow extends SqlDataFlow implements MultipleSourceDataFlows
    * @return string
    */
   public function getTableStatement() {
-    return "`{$this->primary_table}` `{$this->primary_table_alias}`";
+    $sourceDataFlowDescription = reset($this->sourceDataFlowDescriptions);
+    $dataFlow = $sourceDataFlowDescription->getDataFlow();
+    return $dataFlow->getTableStatement();
   }
 
   /**
@@ -213,5 +215,24 @@ class CombinedSqlDataFlow extends SqlDataFlow implements MultipleSourceDataFlows
     return $this->primary_table_alias;
   }
 
+  /**
+   * @param \Civi\DataProcessor\DataFlow\SqlDataFlow\WhereClauseInterface $clause
+   *
+   * @return \Civi\DataProcessor\DataFlow\SqlDataFlow
+   */
+  public function removeWhereClause(SqlDataFlow\WhereClauseInterface $clause) {
+    foreach($this->whereClauses as  $i => $c) {
+      if ($c->getWhereClause() == $clause->getWhereClause()) {
+        unset($this->whereClauses[$i]);
+      }
+    }
+    foreach($this->sourceDataFlowDescriptions as $sourceDataFlowDescription) {
+      if ($sourceDataFlowDescription->getDataFlow() instanceof SqlDataFlow) {
+        $sourceDataFlowDescription->getDataFlow()->removeWhereClause($clause);
+      }
+    }
+    return $this;
+  }
+
 
 }
\ No newline at end of file
diff --git a/Civi/DataProcessor/DataFlow/SqlDataFlow/SimpleWhereClause.php b/Civi/DataProcessor/DataFlow/SqlDataFlow/SimpleWhereClause.php
index fa7bc95eed9c83c653c761e662e44a876282595e..1b4a518e136c5adc4e3d6785c547b18bf3970293 100644
--- a/Civi/DataProcessor/DataFlow/SqlDataFlow/SimpleWhereClause.php
+++ b/Civi/DataProcessor/DataFlow/SqlDataFlow/SimpleWhereClause.php
@@ -27,6 +27,11 @@ class SimpleWhereClause implements WhereClauseInterface {
         case '!=':
           $operator = 'NOT IN';
           break;
+
+        case 'IS NULL':
+          $operator = 'IS NULL';
+          break;
+
       }
     }
 
@@ -34,6 +39,12 @@ class SimpleWhereClause implements WhereClauseInterface {
     $this->table_alias = $table_alias;
     $this->field = $field;
     $this->operator = $operator;
+
+    if ($operator == 'IS NULL') {
+      $this->value = NULL;
+      return;
+    }
+
     if (is_array($value)) {
       $esacpedValues = array();
       foreach($value as $val) {
@@ -61,6 +72,7 @@ class SimpleWhereClause implements WhereClauseInterface {
         case 'Memo':
           $this->value = "'" . \CRM_Utils_Type::escape($value, $valueType) . "'";
           break;
+
         default:
           $this->value = \CRM_Utils_Type::escape($value, $valueType);
           break;
diff --git a/Civi/DataProcessor/Factory.php b/Civi/DataProcessor/Factory.php
index 0735aaaeb3fed0fbf0bea37b31add12dfe7dd453..24224c87cca101906e282d9562d85c6a2cdf6682 100644
--- a/Civi/DataProcessor/Factory.php
+++ b/Civi/DataProcessor/Factory.php
@@ -126,6 +126,7 @@ class Factory {
     $this->addOutput('participant_search', 'CRM_DataprocessorSearch_ParticipantSearch', E::ts('Participant Search'));
     $this->addOutput('export_csv', 'CRM_DataprocessorOutputExport_CSV', E::ts('CSV Export'));
     $this->addFilter('simple_sql_filter', 'Civi\DataProcessor\FilterHandler\SimpleSqlFilter', E::ts('Field filter'));
+    $this->addFilter('activity_filter', 'Civi\DataProcessor\FilterHandler\ActivityFilter', E::ts('Activity filter'));
     $this->addFilter('contact_filter', 'Civi\DataProcessor\FilterHandler\ContactFilter', E::ts('Contact filter'));
     $this->addFilter('contact_in_group_filter', 'Civi\DataProcessor\FilterHandler\ContactInGroupFilter', E::ts('Contact in Group filter'));
     $this->addFilter('case_role_filter', 'Civi\DataProcessor\FilterHandler\CaseRoleFilter', E::ts('Case Role filter'));
@@ -140,7 +141,8 @@ class Factory {
     $this->addOutputHandler('groups_of_contact', 'Civi\DataProcessor\FieldOutputHandler\GroupsOfContactFieldOutputHandler', E::ts('Display the groups of a contact'));
     $this->addOutputHandler('event_repeating_info', 'Civi\DataProcessor\FieldOutputHandler\EventRepeatingInfoFieldOutputHandler', E::ts('Display info about repeating event'));
     $this->addOutputHandler('event_participants', 'Civi\DataProcessor\FieldOutputHandler\EventParticipantsFieldOutputHandler', E::ts('List participants'));
-
+    $this->addOutputHandler('calculations_substract', 'Civi\DataProcessor\FieldOutputHandler\Calculations\SubtractFieldOutputHandler', E::ts('Calculation: Subtract'));
+    $this->addOutputHandler('calculations_total', 'Civi\DataProcessor\FieldOutputHandler\Calculations\TotalFieldOutputHandler', E::ts('Calculation: Total'));
   }
 
   /**
diff --git a/Civi/DataProcessor/FieldOutputHandler/Calculations/CalculationFieldOutputHandler.php b/Civi/DataProcessor/FieldOutputHandler/Calculations/CalculationFieldOutputHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..5143f5ccfd19cd4d3b25748410ec8eaedfeac52d
--- /dev/null
+++ b/Civi/DataProcessor/FieldOutputHandler/Calculations/CalculationFieldOutputHandler.php
@@ -0,0 +1,236 @@
+<?php
+/**
+ * @author Jaap Jansma <jaap.jansma@civicoop.org>
+ * @license AGPL-3.0
+ */
+
+namespace Civi\DataProcessor\FieldOutputHandler\Calculations;
+
+use Civi\DataProcessor\DataSpecification\FieldSpecification;
+use Civi\DataProcessor\FieldOutputHandler\AbstractFieldOutputHandler;
+use Civi\DataProcessor\FieldOutputHandler\FieldOutput;
+use Civi\DataProcessor\Exception\DataSourceNotFoundException;
+use Civi\DataProcessor\Exception\FieldNotFoundException;
+use CRM_Dataprocessor_ExtensionUtil as E;
+
+abstract class CalculationFieldOutputHandler extends AbstractFieldOutputHandler {
+
+  /**
+   * @var \Civi\DataProcessor\DataSpecification\FieldSpecification
+   */
+  protected $outputFieldSpec;
+
+  /**
+   * @var \Civi\DataProcessor\DataSpecification\FieldSpecification[]
+   */
+  protected $inputFieldSpecs = array();
+
+  protected $prefix = '';
+
+  protected $suffix = '';
+
+  protected $number_of_decimals = '';
+
+  protected $decimal_sep = '';
+
+  protected $thousand_sep = '';
+
+  /**
+   * @param array $values
+   * @return int|float
+   */
+  abstract protected function doCalculation($values);
+
+  /**
+   * @return \Civi\DataProcessor\DataSpecification\FieldSpecification
+   */
+  public function getOutputFieldSpecification() {
+    return $this->outputFieldSpec;
+  }
+
+  /**
+   * Returns the data type of this field
+   *
+   * @return String
+   */
+  protected function getType() {
+    return 'Float';
+  }
+
+  /**
+   * Initialize the processor
+   *
+   * @param String $alias
+   * @param String $title
+   * @param array $configuration
+   * @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $processorType
+   */
+  public function initialize($alias, $title, $configuration) {
+    foreach($configuration['fields'] as $fieldAndDataSource) {
+      list($datasourceName, $field) = explode('::', $fieldAndDataSource, 2);
+      $dataSource = $this->dataProcessor->getDataSourceByName($datasourceName);
+      if (!$dataSource) {
+        throw new DataSourceNotFoundException(E::ts("Field %1 requires data source '%2' which could not be found. Did you rename or deleted the data source?", array(1=>$title, 2=>$datasourceName)));
+      }
+      $inputFieldSpec = $dataSource->getAvailableFields()
+        ->getFieldSpecificationByName($field);
+      if (!$inputFieldSpec) {
+        throw new FieldNotFoundException(E::ts("Field %1 requires a field with the name '%2' in the data source '%3'. Did you change the data source type?", [
+          1 => $title,
+          2 => $field,
+          3 => $datasourceName
+        ]));
+      }
+      $dataSource->ensureFieldInSource($inputFieldSpec);
+      $this->inputFieldSpecs[] = $inputFieldSpec;
+    }
+
+    $this->outputFieldSpec = new FieldSpecification($alias, 'Float', $title, null, $alias);
+
+    if (isset($configuration['number_of_decimals'])) {
+      $this->number_of_decimals = $configuration['number_of_decimals'];
+    }
+    if (isset($configuration['decimal_separator'])) {
+      $this->decimal_sep = $configuration['decimal_separator'];
+    }
+    if (isset($configuration['thousand_separator'])) {
+      $this->thousand_sep = $configuration['thousand_separator'];
+    }
+    if (isset($configuration['prefix'])) {
+      $this->prefix = $configuration['prefix'];
+    }
+    if (isset($configuration['suffix'])) {
+      $this->suffix = $configuration['suffix'];
+    }
+  }
+
+  /**
+   * Returns true when this handler has additional configuration.
+   *
+   * @return bool
+   */
+  public function hasConfiguration() {
+    return true;
+  }
+
+  /**
+   * When this handler has additional configuration you can add
+   * the fields on the form with this function.
+   *
+   * @param \CRM_Core_Form $form
+   * @param array $field
+   */
+  public function buildConfigurationForm(\CRM_Core_Form $form, $field=array()) {
+    $fieldSelect = $this->getFieldOptions($field['data_processor_id']);
+
+    $form->add('select', 'fields', E::ts('Fields'), $fieldSelect, true, array(
+      'style' => 'min-width:250px',
+      'class' => 'crm-select2 huge data-processor-field-for-name',
+      'placeholder' => E::ts('- select -'),
+      'multiple' => true,
+    ));
+    $form->add('text', 'number_of_decimals', E::ts('Number of decimals'), false);
+    $form->add('text', 'decimal_separator', E::ts('Decimal separator'), false);
+    $form->add('text', 'thousand_separator', E::ts('Thousand separator'), false);
+    $form->add('text', 'prefix', E::ts('Prefix (e.g. &euro;)'), false);
+    $form->add('text', 'suffix', E::ts('Suffix (e.g. $)'), false);
+    if (isset($field['configuration'])) {
+      $configuration = $field['configuration'];
+      $defaults = array();
+      if (isset($configuration['fields'])) {
+        $defaults['fields'] = $configuration['fields'];
+      }
+      if (isset($configuration['number_of_decimals'])) {
+        $defaults['number_of_decimals'] = $configuration['number_of_decimals'];
+      }
+      if (isset($configuration['decimal_separator'])) {
+        $defaults['decimal_separator'] = $configuration['decimal_separator'];
+      }
+      if (isset($configuration['thousand_separator'])) {
+        $defaults['thousand_separator'] = $configuration['thousand_separator'];
+      }
+      if (isset($configuration['prefix'])) {
+        $defaults['prefix'] = $configuration['prefix'];
+      }
+      if (isset($configuration['suffix'])) {
+        $defaults['suffix'] = $configuration['suffix'];
+      }
+      $form->setDefaults($defaults);
+    }
+  }
+
+  /**
+   * When this handler has configuration specify the template file name
+   * for the configuration form.
+   *
+   * @return false|string
+   */
+  public function getConfigurationTemplateFileName() {
+    return "CRM/Dataprocessor/Form/Field/Configuration/CalculationFieldOutputHandler.tpl";
+  }
+
+
+  /**
+   * Process the submitted values and create a configuration array
+   *
+   * @param $submittedValues
+   * @return array
+   */
+  public function processConfiguration($submittedValues) {
+    $configuration['fields'] = $submittedValues['fields'];
+    $configuration['number_of_decimals'] = $submittedValues['number_of_decimals'];
+    $configuration['decimal_separator'] = $submittedValues['decimal_separator'];
+    $configuration['thousand_separator'] = $submittedValues['thousand_separator'];
+    $configuration['prefix'] = $submittedValues['prefix'];
+    $configuration['suffix'] = $submittedValues['suffix'];
+    return $configuration;
+  }
+
+  /**
+   * Returns all possible fields
+   *
+   * @param $data_processor_id
+   *
+   * @return array
+   * @throws \Exception
+   */
+  protected function getFieldOptions($data_processor_id) {
+    $fieldSelect = \CRM_Dataprocessor_Utils_DataSourceFields::getAvailableFieldsInDataSources($data_processor_id, array($this, 'isFieldValid'));
+    return $fieldSelect;
+  }
+
+  /**
+   * Callback function for determining whether this field could be handled by this output handler.
+   *
+   * @param \Civi\DataProcessor\DataSpecification\FieldSpecification $field
+   * @return bool
+   */
+  public function isFieldValid(FieldSpecification $field) {
+    return true;
+  }
+
+  /**
+   * Returns the formatted value
+   *
+   * @param $rawRecord
+   * @param $formattedRecord
+   *
+   * @return \Civi\DataProcessor\FieldOutputHandler\FieldOutput
+   */
+  public function formatField($rawRecord, $formattedRecord) {
+    $values = array();
+    foreach($this->inputFieldSpecs as $inputFieldSpec) {
+      $values[] = $rawRecord[$inputFieldSpec->alias];
+    }
+    $value = $this->doCalculation($values);
+    $formattedValue = $value;
+    if (is_numeric($this->number_of_decimals)) {
+      $formattedValue = number_format($value, $this->number_of_decimals, $this->decimal_sep, $this->thousand_sep);
+    }
+    $formattedValue = $this->prefix.$formattedValue.$this->suffix;
+    $output = new FieldOutput($value);
+    $output->formattedValue = $formattedValue;
+    return $output;
+  }
+
+}
\ No newline at end of file
diff --git a/Civi/DataProcessor/FieldOutputHandler/Calculations/SubtractFieldOutputHandler.php b/Civi/DataProcessor/FieldOutputHandler/Calculations/SubtractFieldOutputHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..a7f8141021b9ffa4e469105140f0ed17543564db
--- /dev/null
+++ b/Civi/DataProcessor/FieldOutputHandler/Calculations/SubtractFieldOutputHandler.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @author Jaap Jansma <jaap.jansma@civicoop.org>
+ * @license AGPL-3.0
+ */
+
+namespace Civi\DataProcessor\FieldOutputHandler\Calculations;
+
+use Civi\Api4\Phone;
+use Civi\DataProcessor\FieldOutputHandler\FieldOutput;
+
+class SubtractFieldOutputHandler extends CalculationFieldOutputHandler {
+
+  /**
+   * @param array $values
+   * @return int|float
+   */
+  protected function doCalculation($values) {
+    $value = 0;
+    $i =0;
+    foreach($values as $v) {
+      if ($i == 0) {
+        $value = $v;
+      } else {
+        $value = $value - $v;
+      }
+      $i++;
+    }
+    return $value;
+  }
+
+}
\ No newline at end of file
diff --git a/Civi/DataProcessor/FieldOutputHandler/Calculations/TotalFieldOutputHandler.php b/Civi/DataProcessor/FieldOutputHandler/Calculations/TotalFieldOutputHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..8548376ef51d2d45b6d96166934c0b4fe8eb566f
--- /dev/null
+++ b/Civi/DataProcessor/FieldOutputHandler/Calculations/TotalFieldOutputHandler.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @author Jaap Jansma <jaap.jansma@civicoop.org>
+ * @license AGPL-3.0
+ */
+
+namespace Civi\DataProcessor\FieldOutputHandler\Calculations;
+
+use Civi\DataProcessor\FieldOutputHandler\FieldOutput;
+
+class TotalFieldOutputHandler extends CalculationFieldOutputHandler {
+
+  /**
+   * @param array $values
+   * @return int|float
+   */
+  protected function doCalculation($values) {
+    $value = 0;
+    foreach($values as $v) {
+      $value = $value + $v;
+    }
+    return $value;
+  }
+
+}
\ No newline at end of file
diff --git a/Civi/DataProcessor/FieldOutputHandler/ContactLinkFieldOutputHandler.php b/Civi/DataProcessor/FieldOutputHandler/ContactLinkFieldOutputHandler.php
index 07a8defc4b11a509ef7dae840baa80b29256c276..55dcc940025ecc03fbc967f7a603cbcd49bf7a52 100644
--- a/Civi/DataProcessor/FieldOutputHandler/ContactLinkFieldOutputHandler.php
+++ b/Civi/DataProcessor/FieldOutputHandler/ContactLinkFieldOutputHandler.php
@@ -132,7 +132,7 @@ class ContactLinkFieldOutputHandler extends AbstractFieldOutputHandler implement
       'cid' => $contactId,
     ));
     $link = '<a href="'.$url.'">'.$contactname.'</a>';
-    $formattedValue = new FieldOutput($contactname);
+    $formattedValue = new FieldOutput($contactId);
     $formattedValue->formattedValue = $link;
     return $formattedValue;
   }
diff --git a/Civi/DataProcessor/FilterHandler/AbstractFieldFilterHandler.php b/Civi/DataProcessor/FilterHandler/AbstractFieldFilterHandler.php
index b30570257155959a256178ed4935fc7844b111ce..b288830e1bccc81f3c71d4895375296eb04de365 100644
--- a/Civi/DataProcessor/FilterHandler/AbstractFieldFilterHandler.php
+++ b/Civi/DataProcessor/FilterHandler/AbstractFieldFilterHandler.php
@@ -9,6 +9,7 @@ namespace Civi\DataProcessor\FilterHandler;
 use Civi\DataProcessor\DataFlow\SqlDataFlow;
 use Civi\DataProcessor\Exception\DataSourceNotFoundException;
 use Civi\DataProcessor\Exception\FieldNotFoundException;
+use CRM_Dataprocessor_ExtensionUtil as E;
 
 abstract class AbstractFieldFilterHandler extends AbstractFilterHandler {
 
@@ -39,6 +40,13 @@ abstract class AbstractFieldFilterHandler extends AbstractFilterHandler {
     if (!$this->dataSource) {
       throw new DataSourceNotFoundException(E::ts("Filter %1 requires data source '%2' which could not be found. Did you rename or deleted the data source?", array(1=>$this->title, 2=>$datasource_name)));
     }
+    if (!$this->dataSource->getAvailableFilterFields()->getFieldSpecificationByName($field_name)) {
+      throw new FieldNotFoundException(E::ts("Filter %1 requires a field with the name '%2' in the data source '%3'. Did you change the data source type?", array(
+        1 => $this->title,
+        2 => $field_name,
+        3 => $datasource_name
+      )));
+    }
     $this->fieldSpecification  =  clone $this->dataSource->getAvailableFilterFields()->getFieldSpecificationByName($field_name);
     if (!$this->fieldSpecification) {
       throw new FieldNotFoundException(E::ts("Filter %1 requires a field with the name '%2' in the data source '%3'. Did you change the data source type?", array(
diff --git a/Civi/DataProcessor/FilterHandler/AbstractFilterHandler.php b/Civi/DataProcessor/FilterHandler/AbstractFilterHandler.php
index 0c5c4feb66386ec4126a560cb1e8a095a52b5407..41bc7d3f87c7405cdaf28ee670bbd6caa8304c8f 100644
--- a/Civi/DataProcessor/FilterHandler/AbstractFilterHandler.php
+++ b/Civi/DataProcessor/FilterHandler/AbstractFilterHandler.php
@@ -319,6 +319,18 @@ abstract class AbstractFilterHandler {
             $isFilterSet = TRUE;
           }
           break;
+
+        case 'null':
+          if (empty($submittedValues['value'])) {
+            $filterParams = [
+              'op' => 'IS NULL',
+              'value' => '',
+            ];
+            $this->setFilter($filterParams);
+            $isFilterSet = TRUE;
+          }
+          break;
+
       }
     }
     if ($this->isRequired() && !$isFilterSet) {
@@ -468,6 +480,7 @@ abstract class AbstractFilterHandler {
     }
 
     $filter['type'] = $fieldSpec->type;
+    $filter['alias'] = $fieldSpec->alias;
     $filter['title'] = $title;
 
 
@@ -483,6 +496,7 @@ abstract class AbstractFilterHandler {
       return array(
         'IN' => E::ts('Is one of'),
         'NOT IN' => E::ts('Is not one of'),
+        'null' => E::ts('Is empty'),
       );
     }
     $types = \CRM_Utils_Type::getValidTypes();
@@ -503,6 +517,7 @@ abstract class AbstractFilterHandler {
           '<' => E::ts('Is less than'),
           '>' => E::ts('Is greater than'),
           '!=' => E::ts('Is not equal to'),
+          'null' => E::ts('Is empty'),
         );
         break;
     }
@@ -513,6 +528,7 @@ abstract class AbstractFilterHandler {
       'sw' => E::ts('Starts with'),
       'ew' => E::ts('Ends with'),
       'nhas' => E::ts('Does not contain'),
+      'null' => E::ts('Is empty'),
     );
   }
 
@@ -521,15 +537,15 @@ abstract class AbstractFilterHandler {
    * @return string|null
    */
   protected function applyDateFilter($submittedValues) {
-    $filterName = $this->getFieldSpecification()->alias;
     $type = $this->getFieldSpecification()->type;
-    $relative = \CRM_Utils_Array::value("{$filterName}_relative", $submittedValues);
-    $from = \CRM_Utils_Array::value("{$filterName}_from", $submittedValues);
-    $to = \CRM_Utils_Array::value("{$filterName}_to", $submittedValues);
-    $fromTime = \CRM_Utils_Array::value("{$filterName}_from_time", $submittedValues);
-    $toTime = \CRM_Utils_Array::value("{$filterName}_to_time", $submittedValues);
+    $relative = \CRM_Utils_Array::value("relative", $submittedValues);
+    $from = \CRM_Utils_Array::value("from", $submittedValues);
+    $to = \CRM_Utils_Array::value("to", $submittedValues);
+    $fromTime = \CRM_Utils_Array::value("from_time", $submittedValues);
+    $toTime = \CRM_Utils_Array::value("to_time", $submittedValues);
 
     list($from, $to) = \CRM_Utils_Date::getFromTo($relative, $from, $to, $fromTime, $toTime);
+
     if ($from && $to) {
       $from = ($type == "Date") ? substr($from, 0, 8) : $from;
       $to = ($type == "Date") ? substr($to, 0, 8) : $to;
diff --git a/Civi/DataProcessor/FilterHandler/ActivityFilter.php b/Civi/DataProcessor/FilterHandler/ActivityFilter.php
new file mode 100644
index 0000000000000000000000000000000000000000..fa58ad51efa039270c86dfada23c2527b67ae6c7
--- /dev/null
+++ b/Civi/DataProcessor/FilterHandler/ActivityFilter.php
@@ -0,0 +1,194 @@
+<?php
+/**
+ * @author Jaap Jansma <jaap.jansma@civicoop.org>
+ * @license AGPL-3.0
+ */
+
+namespace Civi\DataProcessor\FilterHandler;
+
+use Civi\DataProcessor\Exception\InvalidConfigurationException;
+use CRM_Dataprocessor_ExtensionUtil as E;
+
+class ActivityFilter extends AbstractFieldFilterHandler {
+
+  /**
+   * @var array
+   *   Filter configuration
+   */
+  protected $configuration;
+
+  public function __construct() {
+    parent::__construct();
+  }
+
+  /**
+   * Initialize the filter
+   *
+   * @throws \Civi\DataProcessor\Exception\DataSourceNotFoundException
+   * @throws \Civi\DataProcessor\Exception\InvalidConfigurationException
+   * @throws \Civi\DataProcessor\Exception\FieldNotFoundException
+   */
+  protected function doInitialization() {
+    if (!isset($this->configuration['datasource']) || !isset($this->configuration['field'])) {
+      throw new InvalidConfigurationException(E::ts("Filter %1 requires a field to filter on. None given.", array(1=>$this->title)));
+    }
+    $this->initializeField($this->configuration['datasource'], $this->configuration['field']);
+  }
+
+  /**
+   * Returns true when this filter has additional configuration
+   *
+   * @return bool
+   */
+  public function hasConfiguration() {
+    return true;
+  }
+
+  /**
+   * When this filter type has additional configuration you can add
+   * the fields on the form with this function.
+   *
+   * @param \CRM_Core_Form $form
+   * @param array $filter
+   */
+  public function buildConfigurationForm(\CRM_Core_Form $form, $filter=array()) {
+    $fieldSelect = \CRM_Dataprocessor_Utils_DataSourceFields::getAvailableFilterFieldsInDataSources($filter['data_processor_id']);
+
+    $form->add('select', 'field', E::ts('Contact ID Field'), $fieldSelect, true, array(
+      'style' => 'min-width:250px',
+      'class' => 'crm-select2 huge data-processor-field-for-name',
+      'placeholder' => E::ts('- select -'),
+    ));
+
+    $optionValueApi = civicrm_api3('OptionValue', 'get', array('option_group_id' => "activity_type", 'options' => array('limit' => 0)));
+
+    $activityType = array();
+    foreach($optionValueApi['values'] as $option) {
+      $activityType[$option['id']] = $option['label'];
+    }
+
+    $form->add('select', 'limit_activity_types', E::ts('Limit to Contacts of activity types'), $activityType, false, array(
+      'style' => 'min-width:250px',
+      'class' => 'crm-select2 huge',
+      'placeholder' => E::ts('- Show all activity types -'),
+      'multiple' => true,
+    ));
+
+    if (isset($filter['configuration'])) {
+      $configuration = $filter['configuration'];
+      $defaults = array();
+      if (isset($configuration['field']) && isset($configuration['datasource'])) {
+        $defaults['field'] = $configuration['datasource'] . '::' . $configuration['field'];
+      }
+      if (isset($configuration['limit_activity_types'])) {
+        $defaults['limit_activity_types'] = $configuration['limit_activity_types'];
+      }
+      $form->setDefaults($defaults);
+    }
+  }
+
+  /**
+   * When this filter type has configuration specify the template file name
+   * for the configuration form.
+   *
+   * @return false|string
+   */
+  public function getConfigurationTemplateFileName() {
+    return "CRM/Dataprocessor/Form/Filter/Configuration/ActivityFilter.tpl";
+  }
+
+
+  /**
+   * Process the submitted values and create a configuration array
+   *
+   * @param $submittedValues
+   * @return array
+   */
+  public function processConfiguration($submittedValues) {
+    list($datasource, $field) = explode('::', $submittedValues['field'], 2);
+    $configuration['field'] = $field;
+    $configuration['datasource'] = $datasource;
+    $configuration['limit_activity_types'] = isset($submittedValues['limit_activity_types']) ? $submittedValues['limit_activity_types'] : false;
+    return $configuration;
+  }
+
+  /**
+   * Add the elements to the filter form.
+   *
+   * @param \CRM_Core_Form $form
+   * @param array $defaultFilterValue
+   * @return array
+   *   Return variables belonging to this filter.
+   */
+  public function addToFilterForm(\CRM_Core_Form $form, $defaultFilterValue) {
+    $fieldSpec = $this->getFieldSpecification();
+    $operations = $this->getOperatorOptions($fieldSpec);
+    $defaults = array();
+
+    $title = $fieldSpec->title;
+    $alias = $fieldSpec->alias;
+    if ($this->isRequired()) {
+      $title .= ' <span class="crm-marker">*</span>';
+    }
+
+    $form->addElement('select', "{$alias}_op", E::ts('Operator:'), $operations);
+
+    $props = array(
+      'placeholder' => E::ts('Select a Contact'),
+      'entity' => 'Contact',
+      'create' => false,
+      'multiple' => true,
+    );
+    if (!empty($this->configuration['limit_activity_types'])) {
+      $optionValueApi = civicrm_api3('OptionValue', 'get', array('option_group_id' => "activity_type", 'options' => array('limit' => 0)));
+
+      $activityType = array();
+      foreach($optionValueApi['values'] as $option) {
+        $activityType[$option['id']] = $option['label'];
+      }
+      $param_activity_type = array();
+
+      foreach($this->configuration['limit_activity_types'] as $type_id){
+        array_push($param_activity_type, $activityType[$type_id]);
+      }
+
+      $result = civicrm_api3('ActivityContact', 'get', [
+        'activity_id.activity_type_id'  => ['IN' => $param_activity_type],
+        'options' => ['limit' => 0],
+      ]);
+
+      $contact_id_list = array();
+      foreach ($result['values'] as $contact) {
+        array_push($contact_id_list, $contact['contact_id']);
+      }
+      $contact_id_list = array_values(array_unique($contact_id_list));
+      $props['api'] = ['params' => ['contact_id' => ['IN' => $contact_id_list]]];
+    }
+    $props['select'] = ['minimumInputLength' => 0];
+    $form->addEntityRef( "{$alias}_value", '', $props);
+    if (isset($defaultFilterValue['op'])) {
+      $defaults[$alias . '_op'] = $defaultFilterValue['op'];
+    }
+    if (isset($defaultFilterValue['value'])) {
+      $defaults[$alias.'_value'] = $defaultFilterValue['value'];
+    }
+    if (count($defaults)) {
+      $form->setDefaults($defaults);
+    }
+
+    $filter['type'] = $fieldSpec->type;
+    $filter['title'] = $title;
+
+    return $filter;
+  }
+
+  protected function getOperatorOptions(\Civi\DataProcessor\DataSpecification\FieldSpecification $fieldSpec) {
+    return array(
+      'IN' => E::ts('Is one of'),
+      'NOT IN' => E::ts('Is not one of'),
+      'null' => E::ts('Is empty'),
+    );
+  }
+
+
+}
\ No newline at end of file
diff --git a/Civi/DataProcessor/FilterHandler/CaseRoleFilter.php b/Civi/DataProcessor/FilterHandler/CaseRoleFilter.php
index 8f34ae4b2acf401f8683ad019709eac8c172469f..208f5165ab6e256655ebcce25e2cdd7368bd8088 100644
--- a/Civi/DataProcessor/FilterHandler/CaseRoleFilter.php
+++ b/Civi/DataProcessor/FilterHandler/CaseRoleFilter.php
@@ -167,10 +167,12 @@ class CaseRoleFilter extends AbstractFieldFilterHandler {
    * Add the elements to the filter form.
    *
    * @param \CRM_Core_Form $form
+   * @param array $defaultFilterValue
+   * 
    * @return array
    *   Return variables belonging to this filter.
    */
-  public function addToFilterForm(\CRM_Core_Form $form) {
+  public function addToFilterForm(\CRM_Core_Form $form, $defaultFilterValue) {
     $fieldSpec = $this->getFieldSpecification();
     $operations = $this->getOperatorOptions($fieldSpec);
 
@@ -188,6 +190,7 @@ class CaseRoleFilter extends AbstractFieldFilterHandler {
     ));
 
     $filter['type'] = $fieldSpec->type;
+    $filter['alias'] = $fieldSpec->alias;
     $filter['title'] = $title;
 
     return $filter;
diff --git a/Civi/DataProcessor/FilterHandler/ContactFilter.php b/Civi/DataProcessor/FilterHandler/ContactFilter.php
index 71e73d02b14e742ebcd34ac457851bb7f145c0f5..b62781f8fd0451b9eac46e6ac005a77ed6c4d39f 100644
--- a/Civi/DataProcessor/FilterHandler/ContactFilter.php
+++ b/Civi/DataProcessor/FilterHandler/ContactFilter.php
@@ -11,6 +11,12 @@ use CRM_Dataprocessor_ExtensionUtil as E;
 
 class ContactFilter extends AbstractFieldFilterHandler {
 
+  /**
+   * @var array
+   *   Filter configuration
+   */
+  protected $configuration;
+
   public function __construct() {
     parent::__construct();
   }
@@ -54,6 +60,17 @@ class ContactFilter extends AbstractFieldFilterHandler {
       'placeholder' => E::ts('- select -'),
     ));
 
+    $groupsApi = civicrm_api3('Group', 'get', array('is_active' => 1, 'options' => array('limit' => 0)));
+    $groups = array();
+    foreach($groupsApi['values'] as $group) {
+      $groups[$group['id']] = $group['title'];
+    }
+    $form->add('select', 'limit_groups', E::ts('Limit to Contacts in group(s)'), $groups, false, array(
+      'style' => 'min-width:250px',
+      'class' => 'crm-select2 huge',
+      'placeholder' => E::ts('- Show all groups -'),
+      'multiple' => true,
+    ));
 
     if (isset($filter['configuration'])) {
       $configuration = $filter['configuration'];
@@ -61,6 +78,9 @@ class ContactFilter extends AbstractFieldFilterHandler {
       if (isset($configuration['field']) && isset($configuration['datasource'])) {
         $defaults['field'] = $configuration['datasource'] . '::' . $configuration['field'];
       }
+      if (isset($configuration['limit_groups'])) {
+        $defaults['limit_groups'] = $configuration['limit_groups'];
+      }
       $form->setDefaults($defaults);
     }
   }
@@ -86,6 +106,7 @@ class ContactFilter extends AbstractFieldFilterHandler {
     list($datasource, $field) = explode('::', $submittedValues['field'], 2);
     $configuration['field'] = $field;
     $configuration['datasource'] = $datasource;
+    $configuration['limit_groups'] = isset($submittedValues['limit_groups']) ? $submittedValues['limit_groups'] : false;
     return $configuration;
   }
 
@@ -109,12 +130,17 @@ class ContactFilter extends AbstractFieldFilterHandler {
     }
 
     $form->addElement('select', "{$alias}_op", E::ts('Operator:'), $operations);
-    $form->addEntityRef( "{$alias}_value", NULL, array(
+
+    $props = array(
       'placeholder' => E::ts('Select a contact'),
       'entity' => 'Contact',
       'create' => false,
       'multiple' => true,
-    ));
+    );
+    if (!empty($this->configuration['limit_groups'])) {
+      $props['api'] = ['params' => ['group' => ['IN' => $this->configuration['limit_groups']]]];
+    }
+    $form->addEntityRef( "{$alias}_value", '', $props);
 
     if (isset($defaultFilterValue['op'])) {
       $defaults[$alias . '_op'] = $defaultFilterValue['op'];
@@ -128,6 +154,7 @@ class ContactFilter extends AbstractFieldFilterHandler {
 
     $filter['type'] = $fieldSpec->type;
     $filter['title'] = $title;
+    $filter['alias'] = $fieldSpec->alias;
 
     return $filter;
   }
@@ -136,6 +163,7 @@ class ContactFilter extends AbstractFieldFilterHandler {
     return array(
       'IN' => E::ts('Is one of'),
       'NOT IN' => E::ts('Is not one of'),
+      'null' => E::ts('Is empty'),
     );
   }
 
diff --git a/Civi/DataProcessor/FilterHandler/ContactInGroupFilter.php b/Civi/DataProcessor/FilterHandler/ContactInGroupFilter.php
index 79be6aa3052c2cc398d93cdb070d3ed6da2fccff..aa82588e020d262544888dd7532ca05e6f52dab8 100644
--- a/Civi/DataProcessor/FilterHandler/ContactInGroupFilter.php
+++ b/Civi/DataProcessor/FilterHandler/ContactInGroupFilter.php
@@ -154,10 +154,12 @@ class ContactInGroupFilter extends AbstractFieldFilterHandler {
    * Add the elements to the filter form.
    *
    * @param \CRM_Core_Form $form
+   * @param array $defaultFilterValue
+   *
    * @return array
    *   Return variables belonging to this filter.
    */
-  public function addToFilterForm(\CRM_Core_Form $form) {
+  public function addToFilterForm(\CRM_Core_Form $form, $defaultFilterValue) {
     $fieldSpec = $this->getFieldSpecification();
     $operations = $this->getOperatorOptions($fieldSpec);
 
@@ -182,6 +184,7 @@ class ContactInGroupFilter extends AbstractFieldFilterHandler {
     ));
 
     $filter['type'] = $fieldSpec->type;
+    $filter['alias'] = $fieldSpec->alias;
     $filter['title'] = $title;
 
     return $filter;
diff --git a/Civi/DataProcessor/Output/UIOutputHelper.php b/Civi/DataProcessor/Output/UIOutputHelper.php
index 8b9c854d15e9e30682fa709ea5afbbcfe30a2164..4d1048ee7928edb364f0ec5edb37bc41b76fa2a1 100644
--- a/Civi/DataProcessor/Output/UIOutputHelper.php
+++ b/Civi/DataProcessor/Output/UIOutputHelper.php
@@ -52,7 +52,7 @@ class UIOutputHelper {
         $item = [
           'title' => $title,
           'page_callback' => $outputClass->getCallbackForUi(),
-          'access_arguments' => [$dao->permission],
+          'access_arguments' => [[$dao->permission], 'and'],
         ];
         $items[$url] = $item;
       }
diff --git a/Civi/DataProcessor/Source/Contribution/ContributionSource.php b/Civi/DataProcessor/Source/Contribution/ContributionSource.php
index 312bc9bfe91cda3ca1eb03b5b456758d0a17afa3..318398918dad92ea19160004f7295f19c4cb1a68 100644
--- a/Civi/DataProcessor/Source/Contribution/ContributionSource.php
+++ b/Civi/DataProcessor/Source/Contribution/ContributionSource.php
@@ -6,12 +6,43 @@
 
 namespace Civi\DataProcessor\Source\Contribution;
 
+use Civi\DataProcessor\DataFlow\CombinedDataFlow\CombinedSqlDataFlow;
+use Civi\DataProcessor\DataFlow\MultipleDataFlows\DataFlowDescription;
+use Civi\DataProcessor\DataFlow\MultipleDataFlows\SimpleJoin;
+use Civi\DataProcessor\DataFlow\CombinedDataFlow\SubqueryDataFlow;
+use Civi\DataProcessor\DataFlow\SqlTableDataFlow;
+use Civi\DataProcessor\DataSpecification\DataSpecification;
 use Civi\DataProcessor\Source\AbstractCivicrmEntitySource;
+use Civi\DataProcessor\DataSpecification\Utils as DataSpecificationUtils;
 
 use CRM_Dataprocessor_ExtensionUtil as E;
 
 class ContributionSource extends AbstractCivicrmEntitySource {
 
+  /**
+   * @var SqlTableDataFlow
+   */
+  protected $contributionDataFlow;
+
+  /**
+   * @var SqlTableDataFlow
+   */
+  protected $contributionSoftDataFlow;
+
+  public function __construct() {
+    parent::__construct();
+
+    // Create the contribution data flow and data flow description
+    $this->contributionDataFlow = new SqlTableDataFlow($this->getTable(), $this->getSourceName().'_contribution', $this->getSourceTitle());
+    DataSpecificationUtils::addDAOFieldsToDataSpecification('CRM_Contribute_DAO_Contribution', $this->contributionDataFlow->getDataSpecification());
+
+    // Create the contribution soft data flow and data flow description
+    $this->contributionSoftDataFlow = new SqlTableDataFlow('civicrm_contribution_soft', $this->getSourceName().'_contribution_soft');
+    DataSpecificationUtils::addDAOFieldsToDataSpecification('CRM_Contribute_DAO_ContributionSoft', $this->contributionSoftDataFlow->getDataSpecification(), array('id'), '', 'contribution_soft_', E::ts('Soft :: '));
+  }
+
+
+
   /**
    * Returns the entity name
    *
@@ -29,4 +60,88 @@ class ContributionSource extends AbstractCivicrmEntitySource {
   protected function getTable() {
     return 'civicrm_contribution';
   }
+
+  /**
+   * Initialize this data source.
+   *
+   * @throws \Exception
+   */
+  public function initialize() {
+    if (!$this->primaryDataFlow) {
+      $this->primaryDataFlow = $this->getEntityDataFlow();
+    }
+    $this->addFilters($this->configuration);
+    if (count($this->customGroupDataFlowDescriptions) || count($this->additionalDataFlowDescriptions)) {
+      $this->dataFlow = new CombinedSqlDataFlow('', $this->primaryDataFlow->getPrimaryTable(), $this->contributionDataFlow->getTableAlias());
+      $this->dataFlow->addSourceDataFlow(new DataFlowDescription($this->primaryDataFlow));
+      foreach ($this->additionalDataFlowDescriptions as $additionalDataFlowDescription) {
+        $this->dataFlow->addSourceDataFlow($additionalDataFlowDescription);
+      }
+      foreach ($this->customGroupDataFlowDescriptions as $customGroupDataFlowDescription) {
+        $this->dataFlow->addSourceDataFlow($customGroupDataFlowDescription);
+      }
+    }
+    else {
+      $this->dataFlow = $this->primaryDataFlow;
+    }
+  }
+
+  /**
+   * @return \Civi\DataProcessor\DataFlow\SqlDataFlow
+   * @throws \Exception
+   */
+  protected function getEntityDataFlow() {
+    $contributionDataDescription = new DataFlowDescription($this->contributionDataFlow);
+
+    $join = new SimpleJoin($this->contributionDataFlow->getTableAlias(), 'id', $this->contributionSoftDataFlow->getTableAlias(), 'contribution_id');
+    $join->setDataProcessor($this->dataProcessor);
+    $contributionSoftDataDescription = new DataFlowDescription($this->contributionSoftDataFlow, $join);
+
+    // Create the subquery data flow
+    $entityDataFlow = new SubqueryDataFlow($this->getSourceName(), $this->getTable(), $this->getSourceName());
+    $entityDataFlow->addSourceDataFlow($contributionDataDescription);
+    $entityDataFlow->addSourceDataFlow($contributionSoftDataDescription);
+
+    return $entityDataFlow;
+  }
+
+  /**
+   * Ensure that the entity table is added the to the data flow.
+   *
+   * @return \Civi\DataProcessor\DataFlow\AbstractDataFlow
+   * @throws \Exception
+   */
+  protected function ensureEntity() {
+    if ($this->primaryDataFlow && $this->primaryDataFlow instanceof SubqueryDataFlow && $this->primaryDataFlow->getPrimaryTable() === $this->getTable()) {
+      return $this->primaryDataFlow;
+    } elseif (empty($this->primaryDataFlow)) {
+      $this->primaryDataFlow = $this->getEntityDataFlow();
+      return $this->primaryDataFlow;
+    }
+    foreach($this->additionalDataFlowDescriptions as $additionalDataFlowDescription) {
+      if ($additionalDataFlowDescription->getDataFlow()->getTable() == $this->getTable()) {
+        return $additionalDataFlowDescription->getDataFlow();
+      }
+    }
+    $entityDataFlow = $this->getEntityDataFlow();
+    $join = new SimpleJoin($this->getSourceName(), 'id', $this->getSourceName(), 'entity_id', 'LEFT');
+    $join->setDataProcessor($this->dataProcessor);
+    $additionalDataFlowDescription = new DataFlowDescription($entityDataFlow,$join);
+    $this->additionalDataFlowDescriptions[] = $additionalDataFlowDescription;
+    return $additionalDataFlowDescription->getDataFlow();
+  }
+
+  /**
+   * Load the fields from this entity.
+   *
+   * @param DataSpecification $dataSpecification
+   * @throws \Civi\DataProcessor\DataSpecification\FieldExistsException
+   */
+  protected function loadFields(DataSpecification $dataSpecification, $fieldsToSkip=array()) {
+    $daoClass = \CRM_Core_DAO_AllCoreTables::getFullName($this->getEntity());
+    $aliasPrefix = $this->getSourceName().'_';
+
+    DataSpecificationUtils::addDAOFieldsToDataSpecification($daoClass, $dataSpecification, $fieldsToSkip, '', $aliasPrefix);
+    DataSpecificationUtils::addDAOFieldsToDataSpecification('CRM_Contribute_DAO_ContributionSoft', $dataSpecification, array('id', 'contribution_id'), 'contribution_soft_', $aliasPrefix, E::ts('Soft :: '));
+  }
 }
\ No newline at end of file
diff --git a/README.md b/README.md
index f3ca5fc7f1540ff52173161b4085e1e9c2ddd7ba..f0ce50b210b60147c2ebf2a301eb1c17b9ca1b0e 100644
--- a/README.md
+++ b/README.md
@@ -29,9 +29,16 @@ The extension is licensed under [AGPL-3.0](LICENSE.txt).
 * [Add your own data source for a CiviCRM Entity](docs/add_your_own_datasource.md)
 * Add your own data source for a CSV File
 * How to store a data processor in code in your extension
+* [Develop PHPUnit TestCase for the extension](docs/how_to_create_test.md)
 
 ## Installation
 
 Install this extension by downloading it from https://lab.civicrm.org/extensions/dataprocessor/-/archive/master/dataprocessor-master.zip
 and then upload it to your civicrm server in the extension folder.
 And then press install in the Administer -->  System Settings --> Extensions screen.
+
+## Optional 
+
+To get more information about each fields in DataProcessor. A CiviTutorial has been created, to view tutorial install CiviTutorial Extension.
+
+To Install CiviTutorial in the Administer -->  System Settings --> Extensions screen. (Found in Add New)
diff --git a/crm-tutorials/civicrm-dataprocessor-form-edit-action-update-Overview_of_the_configuration_screen_of_DataProcessor.js b/crm-tutorials/civicrm-dataprocessor-form-edit-action-update-Overview_of_the_configuration_screen_of_DataProcessor.js
new file mode 100644
index 0000000000000000000000000000000000000000..fc9dbb9d1d4a14fec72988ae302c918edaf9271e
--- /dev/null
+++ b/crm-tutorials/civicrm-dataprocessor-form-edit-action-update-Overview_of_the_configuration_screen_of_DataProcessor.js
@@ -0,0 +1,87 @@
+{
+    "title": ts("Overview of the configuration screen of DataProcessor"),
+    "auto_start": true,
+    "steps": [
+        {
+            "target": "#DataProcessor .label",
+            "title": ts("Contains the Title and Description of the DataProcessor"),
+            "placement": "bottom",
+            "content": ts("You can change the title and description of your dataprocessor.\nYou can also disable or enable the dataprocessor. "),
+            "icon": ""
+        },
+        {
+            "target": "#DataProcessor .add.button",
+            "title": ts("Data Sources"),
+            "placement": "bottom",
+            "content": ts("A data processor has at least one data source.\nA data source could be CiviCRM entity, such as Individual, Household, Activity, Relationship etc. "),
+            "icon": ""
+        },
+        {
+            "target": "#DataProcessor .right.nowrap",
+            "title": ts("Configuration of Data Sources"),
+            "placement": "bottom",
+            "content": ts("You can edit the Data Sources or remove them."),
+            "icon": ""
+        },
+        {
+            "target": "#DataProcessor .add.button:eq(3)",
+            "title": ts("Fields"),
+            "placement": "bottom",
+            "content": ts("Select the fields you want to return in the results. For example Contact ID, First Name, Birth date, Gender etc."),
+            "icon": ""
+        },
+        {
+            "target": "#DataProcessor .order-icon:eq(17)",
+            "title": ts("Change The order of the fields"),
+            "placement": "bottom",
+            "content": ts("You can use the arrows to change the order of the fields, the result will be shown in up to down order."),
+            "icon": ""
+        },
+        {
+            "target": "#DataProcessor .right.nowrap:eq(5)",
+            "title": ts("<span style=\"font-size: 13.376px;\">Configuration of Fields</span>"),
+            "placement": "bottom",
+            "content": ts("Similarly to the conifguration of data sources. You can change the configuration of fields or remove them."),
+            "icon": ""
+        },
+        {
+            "target": "#DataProcessor .add.button:eq(1)",
+            "title": ts("Aggregation Fields"),
+            "placement": "bottom",
+            "content": ts("Allows to group results by defining the aggregation field."),
+            "icon": ""
+        },
+        {
+            "target": "#DataProcessor .add.button:eq(4)",
+            "title": ts("Filters"),
+            "placement": "bottom",
+            "content": ts("Define the filters, that may or may not (depends on configuration) be exposed to user on the output page. Filters can be defined so that user can narrow down the results according to his needs. "),
+            "icon": ""
+        },
+        {
+            "target": "#DataProcessor .add.button:eq(2)",
+            "title": ts("Output result of Data Processor"),
+            "placement": "bottom",
+            "content": ts("Add output of the data processor. Output can be of form Contact Search, Activity Search etc. Depends on the user."),
+            "icon": ""
+        },
+        {
+            "target": "#_qf_DataProcessor_next-bottom",
+            "title": ts("Save Data Processor Configuration"),
+            "placement": "bottom",
+            "content": "",
+            "icon": ""
+        },
+        {
+            "target": "#_qf_DataProcessor_cancel-bottom",
+            "title": ts("<span style=\"font-size: 13.376px;\">Cancel Data Processor Configuration</span>"),
+            "placement": "bottom",
+            "content": "",
+            "icon": ""
+        }
+    ],
+    "groups": [],
+    "url": "civicrm/dataprocessor/form/edit?action=update",
+    "domain": null,
+    "source": null
+}
diff --git a/crm-tutorials/civicrm-dataprocessor-manage-Learn_about_this_screen.js b/crm-tutorials/civicrm-dataprocessor-manage-Learn_about_this_screen.js
new file mode 100644
index 0000000000000000000000000000000000000000..10e74429ba9ad21fdafc9602c35b771acca30739
--- /dev/null
+++ b/crm-tutorials/civicrm-dataprocessor-manage-Learn_about_this_screen.js
@@ -0,0 +1,22 @@
+{
+    "title": ts("Learn about this screen"),
+    "auto_start": false,
+    "steps": [
+        {
+            "target": "#ManageDataProcessors .button",
+            "title": ts("Add New Dataprocessor"),
+            "placement": "bottom",
+            "content": ts("You will see the dataprocessor list below after adding."),
+            "icon": ""
+        },
+        {
+            "target": "#ManageDataProcessors .button:eq(1)",
+            "title": ts("Import Data Processor"),
+            "placement": "bottom",
+            "content": ts("If you have a saved JSON config file that has stored dataprocessor configuration. You can import by clicking here. "),
+            "icon": ""
+        }
+    ],
+    "groups": [],
+    "url": "civicrm/dataprocessor/manage"
+}
diff --git a/docs/how_to_create_test.md b/docs/how_to_create_test.md
new file mode 100644
index 0000000000000000000000000000000000000000..ecb3a95df52e2db8054829b4ba48b6339ddc3181
--- /dev/null
+++ b/docs/how_to_create_test.md
@@ -0,0 +1,8 @@
+# How to create a PHPUnit Test
+
+- Create file with appropriate name ending with test. For Example `CreateDataProcessorTest.php`
+- Follow the simplest test case file `CreateDataProcessorTest.php` for creating a test case.
+- Create a function whose name starting with test. For Example `testCreateDataProcessor`. All the function starting with **test** will be evaluated, so name your utility functions properly.
+- If you want to reset the Test Database and install from beginning pass `True` in `apply()` function in `setupHeadless() function`.
+- Don't remove `setUp()` and `tearDown()` function from the UnitTest file.
+
diff --git a/info.xml b/info.xml
index 70874a8438a56bd5bb3a9e4351fa03346a716227..f264cb5f1f179a103ab29bcfe864b6f13316f2cd 100644
--- a/info.xml
+++ b/info.xml
@@ -14,14 +14,15 @@
     <url desc="Documentation">https://lab.civicrm.org/extensions/dataprocessor/README.md</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2018-08-14</releaseDate>
+  <releaseDate>2019-07-15</releaseDate>
   <version>master</version>
-  <develStage>alpha</develStage>
+  <develStage>dev</develStage>
   <compatibility>
     <ver>4.7</ver>
     <ver>5.7</ver>
     <ver>5.13</ver>
     <ver>5.14</ver>
+    <ver>5.15</ver>
   </compatibility>
   <classloader>
     <psr4 prefix="Civi\" path="Civi" />
diff --git a/templates/CRM/Contact/Form/OutputConfiguration/DashletConfiguration.tpl b/templates/CRM/Contact/Form/OutputConfiguration/DashletConfiguration.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..3c657772f62ae2c98a606d266f92a7877559e2a1
--- /dev/null
+++ b/templates/CRM/Contact/Form/OutputConfiguration/DashletConfiguration.tpl
@@ -0,0 +1,22 @@
+{crmScope extensionKey='dataprocessor'}
+
+<div id="dashlet_configuration">
+    <div class="crm-section">
+        <div class="label">{$form.dashlet_title.label}</div>
+        <div class="content">{$form.dashlet_title.html}</div>
+        <div class="clear"></div>
+    </div>
+    <div class="crm-section">
+        <div class="label">{$form.dashlet_name.label}</div>
+        <div class="content">{$form.dashlet_name.html}</div>
+        <div class="clear"></div>
+    </div>
+    <div class="crm-section">
+        <div class="label">{$form.dashlet_active.label}</div>
+        <div class="content">{$form.dashlet_active.html}</div>
+        <div class="clear"></div>
+    </div>
+</div>
+
+{/crmScope}
+
diff --git a/templates/CRM/Contact/Form/OutputConfiguration/DataProcessorContactSearch.tpl b/templates/CRM/Contact/Form/OutputConfiguration/DataProcessorContactSearch.tpl
index 4a606293ef2e0aafff2b40c1c695a0cfa0f52665..7d0f459c1c4950a6f0fb516defed9067b2d80337 100644
--- a/templates/CRM/Contact/Form/OutputConfiguration/DataProcessorContactSearch.tpl
+++ b/templates/CRM/Contact/Form/OutputConfiguration/DataProcessorContactSearch.tpl
@@ -1,4 +1,5 @@
 {crmScope extensionKey='dataprocessor'}
+    {include file='CRM/Contact/Form/OutputConfiguration/DashletConfiguration.tpl'}
     <div class="crm-section">
         <div class="label">{$form.title.label}</div>
         <div class="content">{$form.title.html}</div>
@@ -29,4 +30,5 @@
         <div class="content">{$form.help_text.html}</div>
         <div class="clear"></div>
     </div>
+    
 {/crmScope}
\ No newline at end of file
diff --git a/templates/CRM/Dataprocessor/Form/Field/Configuration/CalculationFieldOutputHandler.tpl b/templates/CRM/Dataprocessor/Form/Field/Configuration/CalculationFieldOutputHandler.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..c642c4824743edb6fbf2bfcdcbb57778ecbd22ac
--- /dev/null
+++ b/templates/CRM/Dataprocessor/Form/Field/Configuration/CalculationFieldOutputHandler.tpl
@@ -0,0 +1,35 @@
+{crmScope extensionKey='dataprocessor'}
+    <div class="crm-section">
+        <div class="label">{$form.fields.label}</div>
+        <div class="content">{$form.fields.html}</div>
+        <div class="clear"></div>
+    </div>
+
+    <div class="crm-section">
+        <div class="label">{$form.number_of_decimals.label}</div>
+        <div class="content">{$form.number_of_decimals.html}
+            <p class="description">{ts}Leave empty for no formatting{/ts}</p>
+        </div>
+        <div class="clear"></div>
+    </div>
+    <div class="crm-section">
+        <div class="label">{$form.decimal_separator.label}</div>
+        <div class="content">{$form.decimal_separator.html}</div>
+        <div class="clear"></div>
+    </div>
+    <div class="crm-section">
+        <div class="label">{$form.thousand_separator.label}</div>
+        <div class="content">{$form.thousand_separator.html}</div>
+        <div class="clear"></div>
+    </div>
+    <div class="crm-section">
+        <div class="label">{$form.prefix.label}</div>
+        <div class="content">{$form.prefix.html}</div>
+        <div class="clear"></div>
+    </div>
+    <div class="crm-section">
+        <div class="label">{$form.suffix.label}</div>
+        <div class="content">{$form.suffix.html}</div>
+        <div class="clear"></div>
+    </div>
+{/crmScope}
\ No newline at end of file
diff --git a/templates/CRM/Dataprocessor/Form/Filter/Configuration/ActivityFilter.tpl b/templates/CRM/Dataprocessor/Form/Filter/Configuration/ActivityFilter.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..ca3dc1cc0df6996c7bdd5faea2bde7b139764225
--- /dev/null
+++ b/templates/CRM/Dataprocessor/Form/Filter/Configuration/ActivityFilter.tpl
@@ -0,0 +1,12 @@
+{crmScope extensionKey='dataprocessor'}
+<div class="crm-section">
+    <div class="label">{$form.field.label}</div>
+    <div class="content">{$form.field.html}</div>
+    <div class="clear"></div>
+</div>
+<div class="crm-section">
+    <div class="label">{$form.limit_activity_types.label}</div>
+    <div class="content">{$form.limit_activity_types.html}</div>
+    <div class="clear"></div>
+</div>
+{/crmScope}
\ No newline at end of file
diff --git a/templates/CRM/Dataprocessor/Form/Filter/Configuration/ContactFilter.tpl b/templates/CRM/Dataprocessor/Form/Filter/Configuration/ContactFilter.tpl
index 699cd97b3d12abaf39898421ff8f7a18bd052863..5052e691d3dca4d07f2955c228fbcf577d69cf5d 100644
--- a/templates/CRM/Dataprocessor/Form/Filter/Configuration/ContactFilter.tpl
+++ b/templates/CRM/Dataprocessor/Form/Filter/Configuration/ContactFilter.tpl
@@ -4,4 +4,9 @@
     <div class="content">{$form.field.html}</div>
     <div class="clear"></div>
 </div>
+<div class="crm-section">
+    <div class="label">{$form.limit_groups.label}</div>
+    <div class="content">{$form.limit_groups.html}</div>
+    <div class="clear"></div>
+</div>
 {/crmScope}
\ No newline at end of file
diff --git a/templates/CRM/Dataprocessor/Form/Filter/GenericFilter.tpl b/templates/CRM/Dataprocessor/Form/Filter/GenericFilter.tpl
index 84e2445936923c32399eaab313df47ff4f56624d..0bd887432c3d0fd66a292ebcba4d40a977848079 100644
--- a/templates/CRM/Dataprocessor/Form/Filter/GenericFilter.tpl
+++ b/templates/CRM/Dataprocessor/Form/Filter/GenericFilter.tpl
@@ -1,12 +1,12 @@
-{assign var=fieldOp     value=$filterName|cat:"_op"}
-{assign var=filterVal   value=$filterName|cat:"_value"}
-{assign var=filterMin   value=$filterName|cat:"_min"}
-{assign var=filterMax   value=$filterName|cat:"_max"}
+{assign var=fieldOp     value=$filter.alias|cat:"_op"}
+{assign var=filterVal   value=$filter.alias|cat:"_value"}
+{assign var=filterMin   value=$filter.alias|cat:"_min"}
+{assign var=filterMax   value=$filter.alias|cat:"_max"}
 
 {if $filter.type == 'Date' || $filter.type == 'Timestamp'}
     <tr>
         <td class="label">{$filter.title}</td>
-        {include file="CRM/Dataprocessor/Form/Filter/DateRange.tpl" fieldName=$filterName from='_from' to='_to'}
+        {include file="CRM/Dataprocessor/Form/Filter/DateRange.tpl" fieldName=$filter.alias from='_from' to='_to'}
     </tr>
 {elseif $form.$fieldOp.html}
     <tr>
diff --git a/templates/CRM/Dataprocessor/Form/Output.tpl b/templates/CRM/Dataprocessor/Form/Output.tpl
index f0628bc93d11a4c0aeff8571d5123ec43d879360..e09526515c14da9c7d01fd83530dc8773bb830bf 100644
--- a/templates/CRM/Dataprocessor/Form/Output.tpl
+++ b/templates/CRM/Dataprocessor/Form/Output.tpl
@@ -20,6 +20,12 @@
             <div class="content">{$form.type.html}</div>
             <div class="clear"></div>
         </div>
+        <div class="crm-section">
+            <div class="label">{$form.dashlet.label}</div>
+            <div class="content">{$form.dashlet.html}</div>
+            <div class="clear"></div>
+        </div>
+
 
     <div id="type_configuration">
         {if ($configuration_template)}
@@ -39,6 +45,16 @@
           var id = {/literal}{if ($output)}{$output.id}{else}false{/if}{literal};
           var data_processor_id = {/literal}{$data_processor_id}{literal};
 
+          $('#dashlet').on('change', function() {
+            var type = $('#type').val();
+            var dashlet_check = $('#dashlet').val();
+            if(dashlet_check){
+                console.log(dashlet_check);
+                var dataUrl = CRM.url('civicrm/dataprocessor/form/output', {type: type, 'data_processor_id': data_processor_id, 'id': id,'dashlet':dashlet_check});
+                CRM.loadPage(dataUrl, {'target': '#type_configuration'});
+            }
+          });
+
           $('#type').on('change', function() {
             var type = $('#type').val();
             if (type) {
@@ -47,7 +63,9 @@
             }
           });
 
+
           $('#type').change();
+          $('#dashlet').change();
         });
         {/literal}
     </script>
diff --git a/templates/CRM/Dataprocessor/Form/Output/UIOutput/CriteriaForm.tpl b/templates/CRM/Dataprocessor/Form/Output/UIOutput/CriteriaForm.tpl
index dffdc70f64bcd3635b4d9c13943fac23aa0555be..01a81349910b05eef0dee5e10f86ec990a15f1af 100644
--- a/templates/CRM/Dataprocessor/Form/Output/UIOutput/CriteriaForm.tpl
+++ b/templates/CRM/Dataprocessor/Form/Output/UIOutput/CriteriaForm.tpl
@@ -13,7 +13,7 @@
                         <th>{ts}Value{/ts}</th>
                     </tr>
                     {foreach from=$filters key=filterName item=filter}
-                        {include file=$filter.template filterName=$filterName filter=$filter.filter}
+                        {include file=$filter.template filterName=filter.alias filter=$filter.filter}
                     {/foreach}
                 </table>
                 <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="botton"}</div>
diff --git a/templates/CRM/Dataprocessor/Page/Dashlet.tpl b/templates/CRM/Dataprocessor/Page/Dashlet.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..cb1d82ea21e50a376806a7d530b158decf4342d0
--- /dev/null
+++ b/templates/CRM/Dataprocessor/Page/Dashlet.tpl
@@ -0,0 +1,29 @@
+<div>
+	<table class="case-selector">
+	<thead>
+	  <tr>
+	  	{foreach from=$columnHeaders key=headerName item=headerTitle}
+            <th data-data={$headerName} class="crm-dashlet-{$headerName}" data-orderable="true">
+                {$headerTitle}
+            </th>
+        {/foreach}
+	  </tr>
+	</thead>
+	</table>
+</div>
+
+{literal}
+<script type="text/javascript">
+(function($) {
+$('table.case-selector').DataTable({
+		"pageLength":5,
+		"order":[],
+		"lengthMenu": [[5, 10, 20], [5, 10, 20]],
+		"searching": true,
+        "ajax": {
+          "url": {/literal}'{crmURL p="civicrm/ajax/getDashlet" q="dataProcessorId=$dataProcessorId&outputId=$outputId"}'{literal},
+        }
+      });
+})(CRM.$);
+</script>
+{/literal}
\ No newline at end of file
diff --git a/xml/Menu/dataprocessor.xml b/xml/Menu/dataprocessor.xml
index 73c5e0ae047dbb217b5b2828bb77e4a3fedbfb4e..84e26d4da71768cd4de520a5f713891e4accd4ec 100644
--- a/xml/Menu/dataprocessor.xml
+++ b/xml/Menu/dataprocessor.xml
@@ -63,10 +63,22 @@
     <access_arguments>access CiviCRM</access_arguments>
     <access_arguments>administer CiviCRM</access_arguments>
   </item>
+  <item>
+    <path>civicrm/dataprocessor/form/dashlet</path>
+    <page_callback>CRM_Dataprocessor_Page_Dashlet</page_callback>
+    <title>DataProcessor</title>
+    <access_arguments>access CiviCRM</access_arguments>
+    <access_arguments>administer CiviCRM</access_arguments>
+  </item>
   <item>
     <path>civicrm/dataprocessor/form/output/download</path>
     <title>Browse Uploaded files</title>
     <access_arguments>access uploaded files</access_arguments>
     <page_callback>CRM_DataprocessorOutputExport_Page_Download</page_callback>
   </item>
+  <item>
+     <path>civicrm/ajax/getDashlet</path>
+     <page_callback>CRM_Dataprocessor_Page_AJAX::getDashlet</page_callback>
+     <access_arguments>access CiviCRM</access_arguments>
+</item>
 </menu>