Skip to content

rantalainen/fuusor-api-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Fuusor API Client

Third party Fuusor API client. Fuusor website: https://www.fuusor.fi/

⚠️ This tool is in early stages and is subject to change.

⚠️ This tool does not have the latest functionality defined in Fuusor API documentation.

Installation

Install from npm:

npm install @rantalainen/fuusor-api-client

Setup

Import to NodeJS project

const { FuusorApiClient } = require('@rantalainen/fuusor-api-client');

Import to TypeScript project

import { FuusorApiClient } from '@rantalainen/fuusor-api-client';

Setup client with options

Please consult Fuusor Oy to get your clientId, clientSecret, username and password for API usage.

const fuusorApiClient = new FuusorApiClient({
  clientId: 'api-client-id-from-fuusor',
  clientSecret: 'api-client-secret-from-fuusor',
  username: 'environment-username-from-fuusor',
  password: 'environment-password-from-fuusor',

  // Optional: change timeout
  timeout: 60000,

  // Optional: keep alive agent
  keepAliveAgent: true,

  // Optional: DNS cache
  dnsCache: true,
})

Changing timeout on the fly

Default timeout implemented in 1.0.0 is 120 seconds for Fuusor API requests. You can change it in initialization or before saving dataset:

// Change timeout on the fly:
fuusorApiClient.options.timeout = 60000;

Datasets

fuusorApiClient.createDataSet: Create dataset instance

const dataSet = fuusorApiClient.createDataSet(dataSetOptions);

Used to create new dataset instance for updating data in Fuusor database.

required:

  • groupId Company specific identifier from Company Management
  • datasetName Dataset name shown in Company Management
  • datasetId Dataset identifier shown in Company Management (use same id to update old dataset)
  • datasetType Short type identifier, for example: invoices or offers

optional:

  • begin and end With large datasets you can only update data on certain timeframe between begin and end
  • primarydate When updating dataset based on date, use primarydate to define which property contains primary date in data
  • periods Array of periods (financial year term selections, defaults to calendar year)
  • updateById If only certain rows should be updated, define the field name that contains unique id
const dataSet = await fuusorApiClient.createDataSet({
  groupId: 'abc1234-1234-abcd-abcd-abcdabcdabcd',
  datasetName: 'Invoices',
  datasetId: 'invoices',
  datasetType: 'invoices',

  begin: '2020-01-01',
  end: '2020-12-31',
  primarydate: 'invoice_date',
  periods: [
    {
      begin: '2019-01-01',
      end: '2019-12-31'
    },
    {
      begin: '2020-01-01',
      end: '2020-12-31'
    }
  ],

  updateById: 'customer'
});

dataSet.defineField: Define dataset fields

dataSet.defineField(type, id, name, items?);

Shorthands:

dataSet.defineDimensionField(id, name, items);
dataSet.defineDateField(id, name);
dataSet.defineValueField(id, name);
dataSet.defineDescriptionField(id, name);

Each dataset is dynamically constructed, so you have to define data type for each field (property in object).

At the moment of writing, Fuusor has 4 different data types that are listed below:

  • dimension Dataset dimensions used to filter data
  • date Dataset date fields
  • value Numeric value fields (for example hours, euros etc.)
  • description Textual description fields for data row

Definition properties are as listed below:

  • id Field property name in row objects
  • name Field display name in Fuusor

For dimension field you will also define items (that are shown in filtering). Please see example.

Examples

// Define dimension field
dataSet.defineDimensionField('costcenter', 'Cost center', [
  { id: 'SK123', name: 'Production' },
  { id: 'SK124', name: 'Sales' }
]);

// Define date field
dataSet.defineDateField('project_date', 'Project date');

// Define value field
dataSet.defineValueField('hours', 'Project hours');

// Define description field
dataSet.defineDescriptionField('work_description', 'Project work description');

dataSet.pushDimensionFieldDimension: Add dimension item to dimension field

dataSet.pushDimensionFieldDimension(dimensionId, item, options?);

Add dimension items to earlier defined dimension field by dimension id.

Examples

dataSet.pushDimensionFieldDimension('costcenter', {
  id: 'SK125',
  name: 'Accounting'
});

// Option to allow empty dimensions when programmatically adding new dimensions to dataset
dataSet.pushDimensionFieldDimension(
  'customer',
  {
    id: null, // unknown in dataset row
    name: null // unknown in dataset row
  },
  { allowEmptyDimension: true }
);

dataSet.defineDimensionHierarchy: Define dataset dimension hierarchies

dataSet.defineDimensionHierarchy(id, name, dimensionId, items?);

This method is used to define dataset dimension hierarchies. When defining dimension hierarchy, the referenced dimension id must exist in dataset.

Definition properties are as listed below:

  • id Dimension hierarchy id
  • name Dimension hierarchy name
  • dimensionId Referenced dimension id

Examples

// Define dimension hierarchy, 'customer' must be defined as dimension
dataSet.defineDimensionHierarchy('customer_category', 'Customer category', 'customer');

dataSet.pushDimensionHierarchyItem: Add items to defined hierarchy

dataSet.pushDimensionHierarchyItem(hierarchyId, hierarchyItem);

This method is used to define dataset dimension hierarchy items. When defining hierarchy items, the referenced dimension hierarchy id must exist in dataset.

Definition properties are as listed below:

  • hierarchyId Hierarchy item id
  • hierarchyItem Hierarchy item (see examples)

Examples

// Defined customer_category hierarchy in previous example
dataSet.defineDimensionHierarchy('customer_category', 'Customer category', 'customer');

// Add items to hierarchy

dataSet.pushDimensionHierarchyItem('customer_category', {
  id: 333, // actual category id
  name: 'Production customers', // actual category name
  items: [111, 222, 333] // actual customer ids in this category
});

dataSet.pushDimensionHierarchyItem('customer_category', {
  id: 444,
  name: 'Prospects',
  items: [777, 888]
});

dataSet.addRow(s): Add data rows to dataset

// Add one row
dataSet.addRow(data);

// Add multiple rows
dataSet.addRows(data[]);

Add rows to dataset. Each row property field must be defined with dataSet.defineField

Examples

dataSet.addRow({
  project_date: '2020-12-01',
  work_description: 'My great project',
  hours: 10,
  costcenter: 'SK123'
});

dataSet.save: Save dataset to Fuusor via API

await dataSet.save();

Saves dataset to Fuusor. Returns promise.

Full dataset example (JS)

import { FuusorApiClient } from 'fuusor-api-client';

const fuusorApiClient = new FuusorApiClient({
  clientId: 'api-client-id-from-fuusor',
  clientSecret: 'api-client-secret-from-fuusor',
  username: 'environment-username-from-fuusor',
  password: 'environment-password-from-fuusor',
}

const dataSet = fuusorApiClient.createDataSet({
  groupId: 'abc1234-1234-abcd-abcd-abcdabcdabcd',
  datasetName: 'Invoices',
  datasetId: 'invoices',
  datasetType: 'invoices',

  // define begin, end and primarydate or updatebyid field
  begin: '2020-01-01',
  end: '2020-01-31',
  primarydate: 'invoice_date',

  // if we want to update only certain rows, we must define updateById field
  updateById: 'customer'
});

dataSet.defineDateField('invoice_date', 'Invoice date');
dataSet.defineValueField('total', 'Invoice total');

dataSet.defineDimensionField('customer', 'Customer name');
dataSet.pushDimensionFieldDimension('customer', { id: 1, name: 'Customer 1 Oy' });
dataSet.pushDimensionFieldDimension('customer', { id: 2, name: 'Customer 2 Oy' });

dataSet.defineDimensionField('costcenter', 'Branch', [
  { id: 'branch1', name: 'Branch 1' },
  { id: 'branch2', name: 'Branch 2' }
]);

dataSet.defineDimensionHierarchy('customer_category', 'Customer category', 'customer');

dataSet.pushDimensionHierarchyItem('customer_category', {
  id: 5,
  name: 'Category 5',
  items: [1]
});

dataSet.pushDimensionHierarchyItem('customer_category', {
  id: 6,
  name: 'Category 6',
  items: [2]
});

dataSet.pushDimensionFieldDimension('costcenter', {
  id: 'branch3', name: 'Branch 3'
});

dataSet.addRows([
  { invoice_date: '2020-01-05', total: 150.00, customer: 1, costcenter: 'branch1', category_id: 5 },
  { invoice_date: '2020-01-06', total: 120.24, customer: 2, costcenter: 'branch2', category_id: 6 }
]);

await dataSet.save();

Users

fuusorApiClient.users.getAll()

Gets all user accounts.

const users = await fuusorApiClient.users.getAll();

Example response

[
  {
    userName: '[email protected]',
    authenticationType: null,
    language: 'fi-FI',
    validUntil: '2022-02-28'
  }
]

fuusorApiClient.users.create(user)

Creates a new user account.

required:

  • user.userName Email used for login

optional:

  • user.authenticationType Authentication type. Valid values: microsoft, google, activationlink. Default is microsoft.
  • user.language Default UI language for user. Valid values: fi-FI, en-US. Default is fi-FI.
  • user.validUntil Optional expiration date for account.
await fuusorApiClient.users.create({
  userName: '[email protected]',
  authenticationType: 'microsoft',
  language: 'fi-FI',
  validUntil: '2022-02-28'
});

If activationlink is used as an authentication type, the request will respond with the activation code (as a string) that is used to activate the account.

const activationCode = await fuusorApiClient.users.create({
  userName: '[email protected]',
  authenticationType: 'activationlink',
  language: 'fi-FI'
});

fuusorApiClient.users.delete(userName)

Deletes user account.

required:

  • userName Email used for login
await fuusorApiClient.users.delete('[email protected]');

User groups

fuusorApiClient.userGroups.getAll()

Gets all user groups.

const groups = await fuusorApiClient.userGroups.getAll();

Example response

[
  {
    id: '3fa85f64-5717-4562-b3fc-2c963f66afa6',
    name: 'Example group',
    description: 'Example description',
    users: ['[email protected]']
  }
]

fuusorApiClient.userGroups.addUsers(id, users)

Adds users to the user group.

required:

  • id User group id
  • users Array of user emails
await fuusorApiClient.userGroups.addUsers('3fa85f64-5717-4562-b3fc-2c963f66afa6', ['[email protected]']);

fuusorApiClient.userGroups.removeUsers(id, users)

Removes users from the user group.

required:

  • id User group id
  • users Array of user emails
await fuusorApiClient.userGroups.removeUsers('3fa85f64-5717-4562-b3fc-2c963f66afa6', ['[email protected]']);

Changelog

  • 0.1.0 Add support for dimension hierarchies
  • 0.1.1 Add backwards compatible support for dataset endpoint (instead of fileupload)
  • 1.0.0 Add timeout option
  • 1.0.1 Scope @rantalainen/fuusor-api-client
  • 1.1.0 Add support for User and User Group API endpoints
  • 1.1.1 Add support for new authentication type when creating new users
  • 1.1.2 Add support for user expiration date
  • 1.1.3 Better logging in case of invalid hierarchy items or dimension items
  • 1.2.0 pushDimensionFieldDimension option to allow empty dimensions
  • 2.0.0 Add internal httpsAgent (from agentkeepalive package) by default
  • 3.0.0 Added DNS cahcing support and updated httpsAgent to support options