An explanation of the generators used to calculate Business Intelligence measures
Operating mode
Cloud Suite
|ON-PREMISES
Modules
Services & CRM
Budget & Phases
Purchases
Resource Planning
Business Intelligence
To provide data for the Business Intelligence module, we use a data repository according to the data warehouse concept, sometimes also called an "OLAP cube". Depending on the choice of dimensions, a section is cut from a cube.
Essentially, the data warehouse consists of a large data table (cube) with pre-calculated data values. This enables efficient, business logic-independent access to the BI data, and thus a high-performance display, even with large amounts of data.
The calculation is time-independent and with full business logic support via regular scheduled tasks. Thus, if required, the calculation can be done in individual packages (e.g. individual months) in own processes or even parallelized.
The calculation logic is defined in Python scripts called "generators". These are saved on the measures. To view the code of a generator, click on the button with the three dots next to the Generator field on the measure:
The generator must contain a calculation for the measures on which it is saved. The internal name of the measure must match the values returned by the generator.
Vertec supplies the following generators by default:
Generator name | Data used |
Calculated measures |
ServicesGenerator.ServicesGenerator | Service sums (global groupServicesOperator) grouped by project, phase, user and service type. |
|
ProjectGenerator.ProjectGenerator |
Service sums (global groupServicesOperator) grouped by project and invoice. Only uses productive projects. |
|
UsersGenerator.UsersGenerator |
Users who joined before the end date and have not yet left, or whose exit date is after the start date. |
|
InvoicesGenerator.InvoicesGenerator | Invoices that have been charged and whose value date is within the calculated date range. |
|
PhasesGenerator.PhasesGenerator (before Vertec 8.6) |
Top-level phases that have an issue date and whose issue date is before the end date and that have not been completed, or have not been completed until after the start date:
|
|
PhasesMonthGenerator.PhasesMonthGenerator |
Top-level project phases that have an issue date and whose issue date is before the end date and that have not been completed or have not been completed until after the start date:
|
|
PhasesRangeGenerator.PhasesRangeGenerator |
Top-level phases that have an issue date and whose issue date is before the end date and that have not been completed or have not been completed until after the start date:
|
|
The data is regularly calculated from a scheduled task during the night. It can be found in the folder Settings > Customizing > Scheduled tasks.
This process triggers all the generators stored in the active measures, and calculates the values for the period from January of the penultimate year to the end of the next year.
The status of the task shows whether the calculation was successful or failed. The feedback of the calculation is shown in the output window.
A Vertec app does not have to be in operation, only a running Vertec Cloud Server is required. For the calculation, a user is defined on the scheduled task. This user must have administrator rights in order to perform the calculations.
The Next execution
field shows when the scheduled task will run next.
In the Cloud Suite, the time on the interface cannot be changed. The calculation always takes place overnight, in a time window between 11pm and 5am
For On-Premises, the time window can be set with the parameters Special task scheduler range start and Special task scheduler range end in the Vertec.ini file.
The BI recalculation can also be initiated manually. There are two options:
This triggers the calculation of all generators on all active measures.
Note: The calculation is started directly in the current Vertec app and not in a separate task runner process as is the case with time-controlled execution. This should not be done during ongoing operations, as the calculation takes a very long time and Vertec may be blocked.
The generator stored on the measure is triggered and the corresponding measures are recalculated. The date interval can be set:
At the end there is a message indicating which measures have been calculated.
By recalculating measures, existing values are replaced only for the selected period and the relevant measures. All other existing values remain.
There are two Python methods for calculating BI data.
vtcapp.standardprocessbi() |
Triggers the calculation of all generators on all active measures. Requires administrator rights. Corresponds to the execution of the scheduled task supplied by default, see above. |
vtcapp.processbi(from: string, to: string, generator: string) |
Triggers the calculation of the generator supplied as a parameter. Requires administrator rights.
vtcapp.processbi("2023-01", "2026-12", "ServicesGenerator.ServicesGenerator" Corresponds to the calculation of the BI data on a measure, see above. |
You can extend existing generators or create new generators. To do this, create a new script in the folder Settings > Reports & Scripts > Scripts. And write the generator code in Python.
The designation of the script itself is the module name. Together with the class name of the generator, it forms the generator ID. You can specify this as the generator for the BI measures calculated by this generator:
Module names must be unique. You cannot overwrite an existing generator by writing a module with the same name, but rather by creating a new generator and saving it on the relevant measures.
With Vertec version 6.8, we introduced a built-in module called vtcbi with the following classes:
The module vtcbi is also supplied as a stub file.
You must import the module or classes into the BI generator script:
from vtcbi import BiGenerator, Measure, Dimension
initialize(self, startdate, enddate) |
Optional. Called up once before calculating with the entire period. To pre-calculate data for the entire period, we recommend you use the method generate_range() instead. |
generate_month(self, startdate, enddate) |
Is called up once by the business logic for each calculated month. Startdate and enddate are the first and last day of the month. It must call up Only |
generate_range(self, startdate, enddate) |
This method is called once for the entire period to be calculated. Can be used to pre-calculate data. It must call It may only be used either |
store_values([currency, date]) |
With
|
finalize(self) |
Optional. Called up once after calculation. Can be used to approve loaded data (e.g. service sums). |
The BI measures are defined within a generator as follows:
Measure(InternalName: string, Description: string, Unit: integer, [IsCutOffDateValue: boolean=False])
Internal name |
Here you can specify the internal name of the measure. |
Description |
Specifies the designation of the measure. The designation is used as NV (native) of the label field (MLstring) if the measure is imported directly from the generator. |
Unit |
Indicates the unit of the measure.
For easier usability, there is the auxiliary class from vtcbi import BiUnit |
IsCutOffDateValue |
Optional. Specifies whether the measure is a key date value. – By default, this value is |
The dimensions are defined like the measures within a generator:
Dimension(order: integer, type: string[, role: string]
Order |
Order of the dimension on the measure. Must match the order on the measure: ![]() |
Type |
Specifies the class name of the dimension. |
Role |
Optional. The role name of the dimension can be specified here. The value passed is used as the NV (native) of the role field (MLstring). |
As an example, a generator is created to show productive and unproductive services separately.
generate_range() calculates the entire time period. store_values() takes care of the correct summation and sorting.
from vtcbi import BiGenerator, Measure, Dimension, BiUnit class ProductiveGenerator(BiGenerator): prodServices = Measure("ProdServices", "Productive Services", BiUnit.Hours) unprodServices = Measure("UnprodServices", "Unproductive Services", 1) project = Dimension(1, "Project") projectmanager = Dimension(2, "User", "as project manager") user = Dimension(3, "User") def generate_range(self, startdate, enddate): # calc service sums for the whole period, grouped by month, project and user servicesums = vtcapp.evalocl("TimSession.allInstances->first->groupLeistungen('{}', '{}', 'MONTH, PROJECT, USER')".format (vtcapp.datetostrgerman(startdate), vtcapp.datetostrgerman(enddate))) for servicesum in servicesums: self.project = servicesum.evalocl("project") self.projectmanager = servicesum.evalocl("project->oclAsType(Project).projectmanager") self.user = servicesum.evalocl("user") self.prodServices = servicesum.evalocl("(minutesIntOpen + minutesIntCharged)-(minutesIntOpenUnprod + minutesIntChargedUnprod)") self.unprodServices = servicesum.evalocl("minutesintOpenUnprod + minutesIntChargedUnprod") self.store_values(None, servicesum.evalocl("entrydate"))
The declaration of the generator is as follows:
class <Generatorname>(object):
The generator object can be accessed at any time in the script via self. Within the generator, the following methods are available:
Methodology | Description |
---|---|
get_dimensions(self) | This method specifies for which dimensions the generator calculates values:
def get_dimensions(self): return ['Projekt', 'Projektbearbeiter'] The same number of dimensions must be specified in the measures as supplied here, and in the order specified. For example, if you want to show values for both users as project managers and users as key users, the dimension def get_dimensions(self): return ['Projekt', 'Projektbearbeiter', 'Projektbearbeiter'] |
get_measures(self) | This method specifies which measures are calculated. The return values must match the internal names on the measures.
def get_measures(self): return ['OffersQuantity'] The generator can then be saved on all measures that are returned here. |
initialize(self, startdate, enddate) |
First, the method is run through. The variables Here, you can preload the lists of used objects in a performance-optimized way so that you have all the relevant data for the entire period. In the method |
generate(self, startdate, enddate) |
The The variables The data preloaded in Return valueThe return value is a tuple of dimensions and a tuple of measures, in exactly the order declared above. The return value is not returned as usual in Python with yield((project, project.projektleiter), (OffersQuantity,)) Using CurrenciesIf you work with more than one currency in Vertec, you have to take this into account during calculations. You can optionally enter one currency per return line (example from the InvoiceGenerator supplied): yield ((project), turnover_tuple, project.waehrung) Vertec then manages the correct conversion into the key currency. The values are always shown in the key currency. |
finalize(self) | At the end, the finalize method is run. With this method, for example, objects that are no longer needed can be removed from memory. |