Skip to content

art-wit/service-reporting

Repository files navigation

Service reporting


Description

It's a meteor service to generate reports in PDF format by the provided data. Service returns link to generated report.


Installation

Programs installation (Ubuntu):

  1. apt update -y -q

Usage

Service receive data in JSON format. Received data validate by SimpleSchema which custom for each report. On validated data generates report in PDF format. Report dumps on storage. The link is returned to the user.

Adding new report:

  1. Add simpleSchema for new report (dataSchema + filterSchema if necessary) in definitions folder.

Example (new-report-schema.js):

import SimpleSchema from 'simpl-schema';

export const filterSchema = new SimpleSchema({
  'member': String,
  'jobTitle': String,
});

export const dataSchema = new SimpleSchema({
  'modules': {
    type: Array,
    optional: true,
  },
  'policies': {
    type: Array,
    optional: true,
  },
});
  1. Add definition for new report which extends ReportDocDefinition class.

Example (new-report.js):

import { ReportDocDefinition } from '../definition';
import { dataSchema, filterSchema } from './new-report-schema';

export class newReportDefinition extends ReportDocDefinition {

  constructor(params) {
    super(params, {
      dataSchema,
      filterSchema,
    });
  }

}
  1. Export definition to definitions/index.js.

Example (index.js):

...
export * from './new-report';
...
...
  1. Add mapping route to report-routes.js.

Example (report-routes.js):

...
const mappings = {
  ...
  'newReport': defs.newReportDefinition,
  ...
}
...
  1. Add data to test-data folder in JSON format.

Example (new-report-definition.json):

{
  "modules": [
    {
      "name": "Aseptic technique",
      "completedOn": {
        "$date": "2020-08-21T08:58:08.601Z"
      },
      "cpd": 120
    },
    {
      "name": "Basic Wound Management",
      "completedOn": {
        "$date": "2020-08-29T18:30:00.000Z"
      },
      "cpd": 60
    }
  ],
  "policies": [
    {
      "name": "Emergency Contact Details",
      "completedOn": {
        "$date": "2021-03-04T01:17:28.956Z"
      }
    },
    {
      "name": "Employee Dependents Form",
      "completedOn": {
        "$date": "2021-03-09T01:45:38.792Z"
      }
    }
  ],
}
  1. Create test, which generate newReport and dump it (if necessary).

Example (methods.tests.js):

  // Use this beforeEach code block to prevent fs operations

  beforeEach(function () {
    sinon.stub(fs, 'createWriteStream').returns({
      write: sinon.fake(),
      once: sinon.fake(),
      end: sinon.fake(),
      on: sinon.fake(),
      emit: sinon.fake(),
      path: '',
    });
    sinon.replace(ReportDocDefinition, 'saveFile', sinon.fake());
    sinon.replace(ImageFetcher, 'download', sinon.fake.returns({ text: '' }));
  });

 ...

  it('dump newReport', function () {
    const filter = {
      member: 'Member string',
      jobTitle: 'JobTitle string',
    };
    const params = {
      ...EJSON.fromJSONValue(require('/test-data/common-data-definition.json')),
      report: 'newReport',
      filter,
      data: EJSON.fromJSONValue(require('/test-data/new-report-definition.json')),
    };
    assert.match(Meteor.call('HSE.Reporting.generate', params), /^http/);
  });

Adding content in report:

Example (new-report.js):

...
  // Override ReportDocDefinition method to generate content
  reportContent() {
    return [
      'Content string',
    ];
  }
...

Adding titles in report:

Example (new-report.js):

...
  // Override ReportDocDefinition method to generate title
  reportTitle() {
    return 'Report Title';
  }

  // Override ReportDocDefinition method to generate subtitle
  reportSubTitle() {
    const from = new Date();
    const till = new Date();
    return this.formatDateRange(from, till); // ReportDocDefinition method to generate date range
  }
...

Adding filterSection in report:

Example (new-report.js):

...
  filterSection(){
    const {member, jobTitle} = this.filter;
    // ReportDocDefinition method to generate filter section
    return super.filterSection(
        [ // 1-st row
          { // 1-st column
            label: 'Member',
            value: member,
            width: '50%',
          },
        ],
        [ // 2-nd row
          { // 1-st column
            label: 'Job Title',
            value: jobTitle,
            width: '*',
          },
          { // 2-nd column
            label: 'Test label',
            value: 'Test value',
            width: 150,
          },
        ],
      ];
    );
  }

  reportContent() {
    return [
      this.filterSection(),
    ];
  }
...

For additional use cases look for examples in definition.spec.js

Adding tableSection in report:

Example (new-report.js):

tableSection () {
  const view = [
    { // Column 1
      heading: 'Name', // table header
      render: (item) => item.name ?? '\u2013', // table cell's render callback
    },
    { // Column 2
      heading: 'CPD',
      render: (item) => item.cpd ?? '',
    },
  ];
  const data = [
    {
      'name': 'Name 1',
      'cpd': 60,
    },
    {
      'name': 'Name 2',
      'cpd': 90,
    },
    {
      'name': 'Name 3',
      'cpd': 120,
    },
  ];
  // ReportDocDefinition method to generate tables
  return super.tableSection(view, data);
}

reportContent() {
  return [
    this.tableSection();
  ];
}

For additional use cases look for examples in definition.spec.js

Adding renderChart in report:

Example (new-report.js):

  renderChart() {
    const chartData = {
      'type': 'doughnut',
      'height': 200,
      'data': {
        'labels': [
          'Not specified',
          'Aboriginal and Torres Str...',
          'Registered Nurse',
          'Administration – Clinical',
          'Aboriginal health worker',
          'Administration/Clerical –...',
          'Enrolled Nurse',
          'Manager – Administration',
          'Other',
        ],
        'datasets': [
          {
            'data': [
              19,
              10,
              6,
              4,
              3,
              3,
              3,
              3,
              37,
            ],
            'backgroundColor': [
              '#020E87',
              '#387BE4',
              '#A9060F',
              '#CF4D38',
              '#E6AC27',
              '#669A45',
              '#138887',
              '#622F8C',
              '#B661E4',
              '#E560B6',
            ],
          },
        ],
      },
      'options': {
        'title': {
          'display': true,
          'text': 'Members by Job Title',
        },
        'legend': {
          'position': 'right',
          'align': 'left',
        },
      },
    };
    const width = 1800;
    const height = 600;
    const chartOptions = {
      title: {
        fontSize: 40,
        padding: 20,
      },
      legend: {
        labels: {
          fontSize: 25,
          boxWidth: 60,
          padding: 10,
        },
      },
    };
    // ReportDocDefinition method to generate tables
    return super.renderChart(chartData, width, height, chartOptions);
  }

  reportContent() {
    return [
       this.renderChart();
    ];
  }

For additional use cases look for examples in definition.spec.js

Data access:

Example (new-report.js):

  ...
  reportContent() {
    {  user, data, organisation, team, branding, filter, strings } = this;
    return ...
  }
  ...

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published