compucorp / uk.co.compucorp.civicrm.pivotreport

CiviCRM Pivot table reporting solution
Other
8 stars 13 forks source link

PCHR-3504: Add people report filter #116

Closed reneolivo closed 6 years ago

reneolivo commented 6 years ago

Overview

This PR adds a date filter to the admin's people report. This date filter will only include staff that have a valid contract and role for the given date.

For both the contract and roles, the start date must always be defined. If the end date is not defined for one of them, it means they are valid for any given date between the start date and the future.

Before

people report hr17 9000 1 No filter and all staffs are displayed even if they don't have a contract.

After

anim

Staff From To
Role 2016-01-01 ---
Contract 2016-01-14 ---
Manager From To
Role 2018-01-01 2018-04-30
Contract 2018-01-01 ---

Technical details

The people report template was modified and a record filter form was added which includes the head count date filter:

<div id="pivot-report-record-filter-form" class="hidden">
  <form>
    <label>Headcount on date:</label><br />
    <input name="headCountOnDate" class="crm-ui-datepicker" />
    <hr />
    <button class"btn btn-primary" type="submit">
      Filter
    </button>
  </form>
</div>

The report configuration was also augmented to pass a custom filter that can be used to only display staff with valid contracts:

<script type="text/javascript">
  CRM.$(function ($) {
    new CRM.PivotReport.PivotTable({
      // ...
      'recordFilter': function (record) {
        var endsAfterDate, hasValidStartDates, startsBeforeDate;
        var date = moment(this.recordFilterValues.headCountOnDate); // is provided by the pivot table class
        var contract = {
          start: moment(record['Contract Start Date']),
          end: moment(record['Contract End Date'])
        };
        var role = {
          start: moment(record['Role Start Date']),
          end: moment(record['Role End Date'])
        };

        hasValidStartDates = contract.start.isValid() && role.start.isValid();
        startsBeforeDate = contract.start.isSameOrBefore(date) && role.start.isSameOrBefore(date);
        endsAfterDate = (!contract.end.isValid() || date.isBetween(contract.start, contract.end, null, '[]'))
          && (!role.end.isValid() || date.isBetween(role.start, role.end, null, '[]'));

        return hasValidStartDates && startsBeforeDate && endsAfterDate;
      },
      // ...
    });
  });
</script>

The pivot table class was also modified to accomplish the following:

The form filter dates are initialized to the current date:

PivotTable.prototype.initRecordFilterDefaultValues = function () {
  var today = moment().format('YYYY-MM-DD');

  this.recordFilterForm.find('.crm-ui-datepicker')
    .filter(function () {
      return _.isEmpty($(this).val());
    })
    .val(today)
    .change(); // needed so the value is updated into the crm date picker
};

Initializing the record filter form:

PivotTable.prototype.initRecordFilterForm = function () {
  // ...

  // moves the form so it's inside the pivot table:
  this.recordFilterForm.detach()
    .appendTo(this.pivotTableContainer.find('tr:first td:first'))
    .removeClass('hidden')
    .show();

  // initializes the form's date pickers:
  this.recordFilterForm.find('.crm-ui-datepicker')
    .crmDatepicker({ time: false, allowClear: false });

  // when the form is submitted it refreshes the pivot table:
  this.recordFilterForm.on('submit', function (event) {
    event.preventDefault();

    this.applyConfig(this.lastPivotConfig); // uses the last configuration to reset the pivot table
  }.bind(this));
};

Finally, when the pivot table is initialized, it will check if there is a record filter and apply it before displaying the pivot table:

PivotTable.prototype.applyConfig = function (config) {
  var data = this.data;
  this.lastPivotConfig = config;

  this.storeRecordFilterValues();

  if (this.config.recordFilter) {
    data = _.filter(this.data, function (record) {
      return this.config.recordFilter.call(this, record);
    }.bind(this));
  }

  // ... renders the pivot table
};

PivotTable.prototype.storeRecordFilterValues = function () {
  this.recordFilterValues = {};

  this.recordFilterForm.find('form').serializeArray()
    .forEach(function (field) {
      this.recordFilterValues[field.name] = field.value;
    }.bind(this));
};
deb1990 commented 6 years ago

@reneolivo The date field looks broken, the icon has no black border, also the icon disappears some times.

reneolivo commented 6 years ago

As discussed with @deb1990 the style issue for the date picker is going to be fixed in PCHR-3846. As a note, the borders were intoduced in this commit: https://github.com/compucorp/org.civicrm.shoreditch/blame/446d502abe10b15d1d19dd891d3627b26103fbde/scss/civicrm/common/_forms.scss#L614 as part of this PR: https://github.com/compucorp/civihr/pull/1153